Удаление пробела из строки - на месте в стиле C с помощью указателей - PullRequest
3 голосов
/ 02 февраля 2012

Итак, это довольно простая проблема, и я знаю решение, которое представляет собой простую функцию, подобную приведенной ниже:

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

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

    *dest = 0;
}

Я работаю в Visual C ++ 2008 Express edition

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

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++;

Может кто-нибудь уточнить, почемуэто происходит?

Ответы [ 3 ]

5 голосов
/ 02 февраля 2012

Когда вы делаете

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, но некоторые старые и несовместимые компиляторы ошибочно допускают такое поведение.

4 голосов
/ 02 февраля 2012

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

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

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

1 голос
/ 02 февраля 2012

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...