Пожалуйста, объясните это поведение с символьными массивами / строками в C - PullRequest
2 голосов
/ 21 октября 2009

Я понимаю это, когда пытался что-то (только для понимания). Пожалуйста, объясните это поведение:


Первая попытка:

void main()    
{  
    char src[] = "vinay";
    int i;
    // char name[5] = "test";
    char *name=  "abcde";
    printf("%s \n", name);
    if (*(name+5) == '\0')
        printf("6th char is null\n");
    strcpy(name,src);
    printf("printcheck \n");
    for (i=0 ; i <6 ; i++)  
    {
        printf("%c \n", *(name+i));
    }
    printf("%s \n",name);    
}

Выход:

abcde 
6th char is null
zsh: 16644 segmentation fault (core dumped)  a.out

Вторая попытка:

void main()
{
    char src[] = "vinay";
    int i;
    char name[] = "pqrst";
    //char *name=  "abcde";
    printf("%s \n", name);

    if (*(name+5) == '\0')    
        printf("6th char is null\n");

    strcpy(name,src);
    printf("printcheck \n");

    for (i=0 ; i <6 ; i++)
    {
        printf("%c \n", *(name+i));
    }

    printf("%s \n",name);
}

Выход:

pqrst 
6th char is null
printcheck     
v     
i   
n   
a     
y 
vinay

=============================================== ============================================

Вопрос: почему происходит сбой при попытке 1? Я пробовал это на машине Solaris Версия ядра: SunOS 5.8 Generic 117350-43 окт 2006 г.

Ответы [ 8 ]

8 голосов
/ 21 октября 2009

Потому что это вид операции:

char name[] = "pqrst";

Копирует постоянную строку в массив в стеке. Вы можете изменить свою локальную копию.

Однако, этот вид операции:

char *name=  "abcde";

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

5 голосов
/ 21 октября 2009

Строковые литералы не могут быть изменены (под штрафом Неопределенное поведение ). Когда вы объявляете указатель на них, вы действительно должны сделать это const

const char *name = "string literal";

Цитата из стандарта:

6.4.5 String literals

6 .... If the program attempts to modify such an array,
  the behavior is undefined.
5 голосов
/ 21 октября 2009
char* name = "abcde";

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

char name[] = "vinay"; 

выделяет записываемый массив.

1 голос
/ 21 октября 2009

Проблема с этой строкой:

char* name = "abcde";

Строка "abcde" - это строка static const , которая встроена в часть вашего исполняемого файла, в которую нельзя писать. Когда вы делаете strcpy(name, src), strcpy пытается записать в статическую часть памяти, что вызывает нарушение доступа.

С другой стороны, когда вы пишете это:

char[] name = "abcde";

затем name - это массив, выделенный в стеке вашей локальной функции. Вы всегда можете записать в свой стек, так что это прекрасно работает.

0 голосов
/ 21 октября 2009

Попытка 1 не удалась, потому что вы модифицируете память, которая была инициализирована компилятором. Использование кавычек, как в char *name = "something", для определения строки в постоянном пространстве памяти (а не в стеке, как в char name[] = "vinay"). Вы не должны изменять ее, и, следовательно, вы получаете ошибку сегментации при попытке записи в недоступную для записи Если вы хотите вместо этого использовать char * и сделать его модифицируемым, выделите память самостоятельно:

char *name = NULL; 
name = (char *) malloc(6);

но не забудьте free() позже!

0 голосов
/ 21 октября 2009

Строковые константы ("abcde"), вероятно, находятся в сегменте данных только для чтения и, следовательно, не могут быть записаны с помощью

char src[] = "vinay";
char *name = "abcde";
[...]
strcpy(name, src); /* copy string src to whatever name points to */

Копирование в ячейку памяти, доступную только для чтения, приведет к ошибке.

Вторая программа работает, так как теперь целевая область памяти расположена там, где находятся все локальные переменные, и эта область памяти (стек) доступна для записи.

char src[] = "vinay";
char name[] = "abcde";
[...]
strcpy(name, src); /* copy string src to the memory area designated by name */
0 голосов
/ 21 октября 2009

Возможно, причина не в том, что вы не выделили место для имени переменной. Вы сбрасываете vinay поверх случайной области в стеке, которая вполне может быть зарезервирована для чего-то другого. Используйте malloc, чтобы выделить место для вашей строки, и все должно быть в порядке:)

0 голосов
/ 21 октября 2009

В первой попытке name указатель на ресурс памяти const. Во второй попытке вы измените это, и выделение будет выполнено до помещения текста в эту область памяти.

Динамическое распределение выполняется с помощью:

char * buffer = malloc(STRING_SIZE);

или

char buffer[STRING_SIZE];
...