2013-11-30 5 views
1

Я написал упражнение «обратная строка» в качестве подготовки к моим предстоящим собеседованиям, однако, когда я пытаюсь запустить тест по нескольким элементам своего массива, я получаю segfault.обратная строка является дефектом seg

В принципе, если я скомпилирую код ниже с помощью -DWORKS, cstr со строкой «zip it shrimp» будет изменен как ожидалось. Однако, если оставить это будет компилировать код, который использует массив указателей, но терпит неудачу на первой итерации (т.е. ПРМ [я], где я = 0):

*s = *e; 

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

#include <stdio.h> 

char *str[] = { "zip it shrimp", "", "a", "ab", "abc" }; 
char cstr[] = "zip it shrimp"; 

void reverse(char *str) 
{  
     char *s = str; 
     char *e = s + strlen(s) - 1; 

     while (s < e) { 
       char c = *s; 
       *s = *e; 
       *e = c; 
       s++; 
       e--; 
     } 
} 

int main(int argc, char **argv) 
{ 
     int i; 
#ifdef WORKS 
     reverse(&cstr); 
     printf("%s\n", cstr); 
#else 
     for (i = 0; i < 4; i++) { 
       reverse(str[i]); 
       printf("%s\n", str[i]); 
     } 
#endif 
     return 0; 
}  

ответ

3

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

char *str[] = { "zip it shrimp", "", "a", "ab", "abc" }; 

Копирование строк в изменяемые ячейки памяти, а затем восстанавливать их. Один из способов - использовать strdup().

for (i = 0; i < 4; i++) { 
      char *p=strdup(str[i]); 
      if (!p) { /* handle error */ } 
      reverse(p); 
      printf("%s\n", p); 
      free(p); 
    } 

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

+0

Спасибо! Это очень понятно, и я ценю ваш практический пример :). – user3043746

1

Если вы явно не резервируете изменяемое пространство для строковых литералов (раздел 6.4.5 в спецификации языка), как и для cstr, им не гарантируется назначение измененного хранилища.

См. Также Is modification of string literals undefined behaviour according to the C89 standard?.

C11, проект спецификации N1516, раздел 6.4.5.7 гласит:

Не определено ли эти массивы различны при условии их элементы имеют соответствующие значения. Если программа пытается модифицировать такой массив, поведение равно undefined.

C99, проект спецификации WG14/N1256, раздел 6.4.5.6 состояния:

Не определено ли эти массивы различны при условии их элементы имеют соответствующие значения. Если программа пытается модифицировать такой массив, поведение равно undefined.

Компилятор может свободно брать такие литералы и объединять их с литералами других модулей. Если вы допустили модификации таких строк, вы можете повлиять на строковые литералы из других модулей. В Linux такие литералы хранятся в разделах .rodata (данные только для чтения), и загрузчик гарантирует, что они не могут быть записаны - что приводит к ошибке сегментации, которую вы наблюдаете.

+0

Уважаемый, в то время как я думаю, что вы заслуживаете «выигрышный» вопрос за то, что навалили меня на части спецификации, мое понимание чтения немного сократилось на некоторое время, но спасибо за ваше Помогите :) – user3043746

Смежные вопросы