Разница между char * str = "STRING" и char str [] = "STRING"? - PullRequest
22 голосов
/ 05 октября 2010

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

void str_remove_chars( char *str, char to_remove)
{
    if(str && to_remove)
    {
       char *ptr = str;
       char *cur = str;
       while(*ptr != '\0')
       {
           if(*ptr != to_remove)
           {
               if(ptr != cur)
               {
                   cur[0] = ptr[0];
               }
               cur++;
           }
           ptr++;
       }
       cur[0] = '\0';
    }
}
int main()
{
    setbuf(stdout, NULL);
    {
        char test[] = "string test"; // stack allocation?
        printf("Test: %s\n", test);
        str_remove_chars(test, ' '); // works
        printf("After: %s\n",test);
    }
    {
        char *test = "string test";  // non-writable?
        printf("Test: %s\n", test);
        str_remove_chars(test, ' '); // crash!!
        printf("After: %s\n",test);
    }

    return 0;
}

Чего я не понимаю, почему второй тест не проходит? Мне кажется, что первая запись char *ptr = "string"; эквивалентна этой: char ptr[] = "string";.

Разве это не так?

Ответы [ 6 ]

40 голосов
/ 05 октября 2010

Два объявления не совпадают.

char ptr[] = "string"; объявляет массив символов размером 7 и инициализирует его символами
s, t, r, i, n, g и \0. Вам разрешено изменять содержимое этого массива.

char *ptr = "string"; объявляет ptr указателем на символ и инициализирует его адресом строковый литерал "string", который только для чтения . Изменение строкового литерала - это неопределенное поведение . То, что вы видели (ошибка сегмента), является одним из проявлений неопределенного поведения.

5 голосов
/ 05 октября 2010

Строго говоря, объявление char *ptr гарантирует только указатель на тип символа.Обычно строка формирует часть сегмента кода скомпилированного приложения, которая устанавливается в некоторых операционных системах только для чтения.Проблема заключается в том, что вы делаете предположение о природе предопределенной строки (что она доступна для записи), когда фактически вы никогда не создавали явно память для этой строки самостоятельно.Возможно, что некоторые реализации компилятора и операционной системы позволят вам сделать то, что вы пытались сделать.

С другой стороны, объявление char test[] по определению фактически выделяет в этом случае читаемую и записываемую память для всего массива символов в стеке.

3 голосов
/ 05 октября 2010

char *test = "string test"; неверно, должно было быть const char*.Этот код компилируется только из-за обратной совместимости.Память, на которую указывает const char*, доступна только для чтения, и всякий раз, когда вы пытаетесь записать в нее, она вызывает неопределенное поведение.С другой стороны, char test[] = "string test" создает доступный для записи массив символов в стеке.Это как любая другая локальная переменная regualr, в которую вы можете записать.

2 голосов
/ 05 октября 2010

Насколько я помню,

char ptr[] = "string";

создает копию из "string" в стеке, так что эта переменная.

Форма

char *ptr = "string";

- это просто обратная совместимость для

const char *ptr = "string";

, и вы не можете (с точки зрения неопределенного поведения) изменять его содержимое.Компилятор может размещать такие строки в разделе памяти, доступном только для чтения.

0 голосов
/ 19 декабря 2012
char *str = strdup("test");
str[0] = 'r';

является правильным кодом и создает изменяемую строку. str назначается память в куче, в ней заполняется значение 'test'.

0 голосов
/ 05 октября 2010

Хороший ответ @ codaddict.

Кроме того, sizeof(ptr) даст разные результаты для разных объявлений.

Первый, объявление массива, вернет длину массива , включая завершающий нулевой символ.

Второй, char* ptr = "a long text..."; вернет длину указателя, обычно 4 или 8.

...