2013-12-18 14 views
6

To jest testowany przeze mnie kod do kopiowania struct.Błąd magistrali w C struct

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 } 

Kiedy próbowałem strcpy (nowy, string) w linii 40, to wyrzuca błąd autobusowy: 10.

Spodziewałem się, że wartość Zmieniono i Original są takie same w linii 41 i 42. Ale to nie będzie działać. Jaki jest problem z przypisaniem?

Wiedziałem, że błąd magistrali: 10 wystąpiło z powodu braku miejsca przypisania. Ale moje pole nazwa w struct jest wskaźnikiem (w linii 5). Gdybym zmienił nazwę pola jak

char name[100]; 

że działa poprawnie i Zmieniono i pierwotnej wartości są różne! Chociaż przypisałem to jako wskaźnik.

Jaki jest problem z tym przypisaniem do struktury?

+5

Nigdy nie przydziela się pamięci dla 'temp.name', a wartość w bazie danych wskazuje na to, co należy uznać za dane stałe. Jeśli spróbujesz napisać do tego obszaru, wszystko może się zdarzyć; twój system operacyjny najwyraźniej właśnie wyzwolił SIGBUS. – cHao

+0

@CHao. Już próbowałem temp-> name jak przypisywanie wskaźników, ale wyrzuca błąd odniesienia. Wtedy sensowne jest przypisywanie pola * name w sposób "malloc". – Sogo

+1

@ cHao Próbowałem użyć 'char * name = (char *) malloc (sizeof (char) * 100);' i to działa. Masz rację. Myślę, że nieokreślone przypisywanie pamięci zawsze pojawia się błąd. Dzięki! – Sogo

Odpowiedz

3

temp.name to wskaźnik do znaku. Po kopia temp = *(people+5);, temp.name wskazuje na bajty zawierające "Nigel".

Do tej pory nie ma problemu. Ale nie możesz użyć tego wskaźnika jako wyjścia dla funkcji strcpy(); Program strcpy spróbuje go zastąpić i będzie przechowywany w pamięci tylko do odczytu.

Można to zrobić:

temp.name = "Ahn";

... ponieważ wszystko, co tu robisz, polega na zmianie wskaźnika (temp.name), tak aby wskazywał inny obszar pamięci, który został wcześniej ustawiony, aby zawierał "Ahn".

To właściwie nie ma nic wspólnego z kopiowaniem strukturalnym. Będziesz miał ten sam problem, jeśli starają się zrobić strcpy(people[3].name, "Ahn")

1

Kiedy ogłoszony rekord bazy danych, wszystkie nazwy (Fred Jim Fred ...) zostały wprowadzone w pamięci read-only segmentu danych i name wskaźnik znaku wskazał adresy początkowe.

Kiedy robisz strcpy(temp.name, "Ahn");, próbujesz pisać w trybie tylko do odczytu. Próba zapisania w pamięci read-only spowoduje błąd magistrali.

Rozwiązaniem byłoby przydzielenie pamięci dla name, a następnie wykonanie strcpy. Dobrą praktyką programowania jest również używanie strncpy zamiast strcpy