2017-01-29 5 views
2

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

struct Student { 
     uint32_t id; 
     uint8_t marks[8]; 
     int32_t credit; 
}; 

struct Student jacob; 
struct Student *adam = &jacob; 
struct Student mary = *adam; 
mary.marks[3] = 80; 
jacob.marks[3] = 75; 
adam->marks[3] = 67; 

printf("jacob: %d\n", jacob); 
printf("&jacob: %d\n", &jacob); 
printf("adam: %d\n", adam); 
printf("*adam: %d\n", *adam); 
printf("mary: %d\n", mary); 
printf("mary.marks[3]: %d\n", mary.marks[3]); 

Выход:

jacob: 4195856 
&jacob: -436012784 
adam: -436012784 
*adam: 4195856 
mary: 4195856 
mary.marks[3]: 80 

Почему значение mary.marks[3] 80? Из того, что я понимаю, mary косвенно указывает на struct jacob, так как adam указывает на адрес jacob. Поэтому строка adam->marks[3] = 67 изменит значение mary.marks[3], так как они указывают на то же местоположение.

Может кто-то, пожалуйста, помогите мне понять, почему значение mary.marks[3] остается неизменным?

+4

"mary косвенно указывает". Это не может быть правдой. 'mary' не является указателем. 'mary' содержит * копию * того, что указывает адам. – kaylum

+1

Вы не инициализировали содержимое 'jacob', поэтому то, что вы копируете (при назначении' * adam' 'mary') не определено. Вы должны правильно печатать адреса. Вы не должны передавать 'jacob'' 'printf()' (или '* adam', или' mary'). –

+1

p.s. Для справок в будущем вы должны предоставить полный пример, который мы можем скомпилировать. В частности, вам не хватает 'main()'. –

ответ

2

Проще говоря, заявление struct Student jacob; создает пространство для одной копии структуры студента (либо в стеке, либо в памяти, в зависимости, но не имеет значения для ответа).

Заявление struct Student *adam = &jacob; делает adam указателем на jacob.

В заявлении struct Student mary = *adam; копируются неинициализированные данные, из которых адам указывает на (jacob) в новое пространство, выделенное для mary.

Важно, чтобы вы понимали, что jacob и mary выделяются пространство. adam - указатель на jacob. Но когда вы говорите mary.marks [3] = 80, вы вкладываете ценность в вещь «mary», тогда как вещь «jacob» не изменяется.

Затем вы записываете jacob.marks[3] и затем перезаписываете это с помощью adam->marks[3].

Когда вы печатаете адрес на что-то, вы должны использовать% p. Когда вы печатаете структуру с% d, C просто смотрит глупо на память «как бы», это целое число. В строке, где вы говорите struct Student mary = *adam;, вы копируете (пока еще неинициализированную) память, содержащую jacob, в недавно выделенную память для mary. Вот почему printf тот же. Если вы напечатаете f & mary, вы обнаружите, что это не та же память, что и jacob или adam.

1

Поскольку mary не является указателем, когда вы назначили *adam к mary вы просто скопировали ценность того, что adam указывает, таким образом, что mary имеет не то, что указывает adam; поэтому попытка изменить значение *adam не вносит изменения в значение mary.

2

Заявление

struct Student *adam = &jacob; 

будет вызывать неопределенное поведение, потому что jacob только объявлен, и это член не инициализируются.

Также использование неправильного спецификатора для типа данных в printf приведет к неопределенному поведению программы. Следует также отметить, что struct не может быть передан в printf.

Теперь изменяя код немного

struct Student { 
     uint32_t id; 
     uint8_t marks[3]; 
     int32_t credit; 
    }; 

int main(void) 
{ 
    struct Student jacob = {0,{0},0}; 
    struct Student *adam = &jacob; 
    struct Student mary = *adam; 
    mary.marks[3] = 80; 
    jacob.marks[3] = 75; 
    adam->marks[3] = 67; 

    printf("mary.marks[3]: %d\n", mary.marks[3]); 
} 

Теперь jacob инициализируется, инициализацией в struct Student указатель с его значением является законным. Теперь adam указывает на jacob и mary инициализируется с копией jacob (любые изменения к членам jacob не был замечен в mary).
В printf вы печатаете mary.marks[3], который имеет значение 80. Эти заявления

jacob.marks[3] = 75; 
adam->marks[3] = 67; 

не будет иметь никакого влияния на mary. Распечатайте jacob.marks[3] или adam->marks[3], и вы увидите изменения.

+0

Спасибо за объяснение и исправление :) – Jspake

+0

Downvoter, позаботьте объяснить? – haccks

1

У вас есть две структурные переменные типа student и один указатель на структуру типа student.

а) jacob не инициализирован и указатель *adam указывает на Джейкоба.

b) то вы копируете jacob в mary по указателю ссылки adam.

c) jacob и mary - два разных адреса; каждый имеет свою собственную копию данных.

d) когда вы изменяете mary.mary[3], он будет обновляться только в mary не в jacob.

mary.marks[3] = 80; 

последнее обновленное значение так, что будет напечатано.

jacob.marks[3] = 75; //direct 
adam->marks[3] = 67; //via pointer to the same variable 

Оба обновления в том же месте. Вы переписываете на:

jacob.marks[3] 

Также следуйте рекомендациям из комментариев.