Ошибка шины в структуре C

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

 1 #include <stdio.h>
 2 #include <string.h>
 3 
 4 typedef struct emp_struct {
 5     char *name;
 6     int employee_no;
 7     float salary,
 8           tax_to_date;
 9 } Employee;
 10 
 11 typedef Employee Database[10];
 12 
 13 Database people = {
 14     {"Fred", 10, 10000, 3000},
 15     {"Jim", 9, 12000, 3100.5},
 16     {"Fred", 13, 1000000, 30},
 17     {"Mary", 11, 170000, 4000},
 18     {"Judith", 45, 130000, 50000},
 19     {"Nigel", 10, 5000, 1200},
 20     {"Trevor", 10, 20000, 6000},
 21     {"Karen", 10, 120000, 34000},
 22     {"Marianne", 10, 50000, 12000},
 23     {"Mildred", 10, 100000, 30000}
 24 };
 25 
 26 int main () {
 27     // array act like pointer, thus pointing + pointing = ERROR
 28     printf("people[1]->name: ERROR\n");
 29     // jump its memory amount of struct size
 30     printf("(people+1)->name:%s\n",(people+1)->name);
 31     // array works as a pointer
 32     printf("people[3].name:%s\n",people[3].name);
 33 
 34     /* Is it possible to assign struct to struct? */
 35     printf("\nAssigning struct to struct\n");
 36     Employee temp;
 37     temp = *(people+5); // Nigel Record
 38     printf("Name: %s\n",temp.name);
 39     // exchange
 40     strcpy(temp.name, "Ahn");
 41     printf("Changed: %s\n",temp.name);
 42     printf("Original: %s\n",people[5].name);
 43 
 44     return 0;
 45 }

Когда я попытался выполнить strcpy(new, string) в строке 40, он выдал Ошибка шины: 10.

Я ожидал, что значения Changed и Original совпадают в строках 41 и 42. Но это не сработало. В чем проблема назначить?

Я знал, что ошибка шины: 10 возникает из-за нехватки места для назначения. Но мое поле name в структуре является указателем (в строке 5). Если бы я изменил поле имени, например

 char name[100];

Он работает правильно, а значения Changed и Original отличаются! Хотя я назначил это как указатель.

В чем проблема назначения этой структуры?


person sogo    schedule 18.12.2013    source источник
comment
Вы никогда не выделяете память для temp.name, а значение в базе данных указывает на то, что следует считать постоянными данными. Если вы попытаетесь написать в эту область, может случиться что угодно; ваша ОС, по-видимому, просто решила запустить SIGBUS.   -  person cHao    schedule 18.12.2013
comment
@cHao. Я уже пробовал temp-›name как назначение указателя, но это выдает ошибку ссылки. Тогда имеет смысл назначить поле *name способом «malloc».   -  person sogo    schedule 18.12.2013
comment
@cHao Я пытался использовать char *name = (char *)malloc(sizeof(char)*100);, и это работает. Ты прав. Я думаю, что всегда возникает ошибка расплывчатого назначения памяти. Спасибо!   -  person sogo    schedule 18.12.2013
comment
Массивы не являются указателями. Вы не можете назначить массив (за исключением его определения), но вы можете strcpy в него. Вы можете назначать указатели практически по своему желанию, но если вы попытаетесь сделать с ними что-то странное (например, strcpying над областью памяти, доступной только для чтения), это будет на вас.   -  person cHao    schedule 18.12.2013
comment
Почему бы вам не использовать people[5] вместо *(people+5). Это более читабельно.   -  person Fiddling Bits    schedule 18.12.2013


Ответы (2)


temp.name — указатель на char. После копии temp = *(people+5); temp.name указывает на байты, содержащие «Nigel».

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

Ты можешь это сделать:

temp.name = "Ан";

... так как все, что вы здесь делаете, это изменяет указатель (temp.name), чтобы он указывал на другую область памяти, которая заранее настроена для содержания «Ahn».

На самом деле это не имеет ничего общего с копированием структуры. У вас будет та же проблема, если вы попытаетесь сделать strcpy(people[3].name, "Ahn")

person greggo    schedule 18.12.2013

Когда вы объявили запись базы данных, все имена (Фред, Джим, Фред...) были помещены в память read-only сегмента данных, а указатель символа name указывал на их начальные адреса.

Когда вы делаете strcpy(temp.name, "Ahn");, вы пытаетесь писать в режиме только для чтения. Попытка записи в память read-only вызовет ошибку шины.

Решение состоит в том, чтобы выделить память для name, а затем выполнить strcpy. Также хорошей практикой программирования является использование strncpy вместо strcpy.

person user376507    schedule 18.12.2013