2012-02-02 1 views
3

Таким образом, его довольно простая задача, и я знаю, что решение, которое является простой функцией, как показано ниже:Space из строки - In Place стиля C с указателями

void removeSpaces(char* s) { 
    char* source = s; 
    char* dest = s; 

    while(*source) { 
     if(*source == ' ') { 
      source++; 
     } else { 
      *dest++ = *source++; 
     } 
    } 

    *dest = 0; 
} 

Я работаю в Visual C++ 2008 Экспресс издание

когда я называю это следующим она отлично работает без каких-либо проблем, то есть он удаляет все пробелы:

int main() { 
    char input[50] = "I  like   2% milk"; 
    removeSpaces(input); 
    cout<<input; 

    getchar(); 
    return 0; 
} 

Но, проблема в том, когда я называю его, изменив строку Объявление к этому:

char * input = "I  like   2% milk"; 

я получаю исключение (своего рода нарушение прав доступа)

Исключение с указанием на этой строке кода функции removeSpace

*dest++ = *source++; 

Можно ли разработать в почему это происходит?

+1

Почему вы не компилируете свои предупреждения с вашего компилятора? Если бы вы это сделали, это, вероятно, предупредило бы о проблеме здесь. –

+0

Возможный дубликат [Почему простой код C получает ошибку сегментации?] (Http://stackoverflow.com/questions/164194/why-does-simple-c-code-receive-segmentation-fault) –

+0

Я понятия не имею, как для включения предупреждений компилятора в Visuall C++. – Sushant

ответ

5

Когда вы

char* something = "a string literal"; 

Компилятор помещает "a string literal" в собственно исполняемое изображение и просто присваивает указатель этой памяти something. Вам не разрешается изменять эту память, и много раз память, в которой находится строка, помечена как только для чтения, поэтому любые попытки записи на нее приводят к нарушению доступа, аналогичному тому, которое вы испытали.

Когда вы

char something[] = "a string literal"; 

вы действительно создаете массив в стек с именем something и Инициирование его с "a string literal". Это эквивалентно выполнению char something[] = {'a', ' ', 's', 't', 'r', ..., 'a', 'l', 0};. Поскольку эта память находится в стеке, вы можете свободно ее изменять.

char* something = "a string literal" выглядит

stack        executable 

-------------      --------------------- 
|~~~~~~~~~~~|      | ~~~~~~~~~~~~~~~~~ | 
| something | -----------------> | a string literal0 | 
-------------      | ~~~~~~~~~~~~~~~~~ | 
            --------------------- 

В то время как char something[] = "a string literal" выглядит

stack 

----- 
|~~~| 
| a | <- something is an alias for this location 
| | 
| s | 
| t | 
| r | 
| i | 
| n | 
| g | 
| | 
| l | 
| i | 
| t | 
| e | 
| r | 
| a | 
| l | 
| 0 | 
----- 

Где ~~~ означает "другую память и т.д.".

Обратите внимание, что

char* x = "string literal"; 

Является ли на самом деле недействительными и не должны компилироваться, так как вы не можете преобразовать char const[x] в char*. Он должен быть const char* x, а не char* x, но некоторые старые и несоответствующие компиляторы ошибочно допускают подобное поведение.

+0

спасибо ... понял. – Sushant

+3

В зависимости от вашего компилятора и настроек это может быть все виды отвратительно неопределенных или нестандартных. Некоторые люди и я протестировали письмо в строки «const» некоторое время назад, и он часто segfaults, но иногда работал, segfaulted, когда мы писали в конце, вообще не совершал ошибок и т. Д. Он тестировался в нескольких версиях MSVC и GCC. Единственное, что случилось, это почти все компиляторы, предупрежденные об этом, поэтому ** включите свои предупреждения и посмотрите их **. – ssube

+0

@Sushant Обратите внимание, что если вы действительно хотите использовать указатели, вы всегда можете выйти с помощью 'char s [] =" string literal "; char * pt = s; '... – Matthieu

4

потому что вы пытаетесь изменить постоянную строку.

char input [50] выделяет память, которую вы можете изменить, и инициализирует ее строкой. char * = просто указывает на строку, которую вы не можете изменить.

На встроенных устройствах такие постоянные строки обычно помещаются в ПЗУ, где вы не можете даже физически писать в эту память! Более современные ОС с блоками управления памятью просто защитить область, где что постоянные данные, и тогда вы получите исключение, если вы нарушаете, что память с неприятными записи на него :-)

+0

глупо меня. Большое спасибо. Прошло много времени с тех пор, как я работал с указателями. – Sushant

1

char* input = "some string literal"; создает указатель не const на строковый литерал, который - на большинстве систем - помещается в постоянное запоминающее устройство. Попытки написать ему обычно создают исключение сигнала или процессора, в отличие от исключения языка C++ в соответствии с блоками try/catch. Эта ужасная ситуация позволяет сохранить совместимость с C, где это разрешено.

Итак, придерживайтесь исходного кода, который явно запрашивает буфер без const с этим контентом. Или используйте std::string или что-то в этом роде.