C структура и функция malloc - PullRequest
0 голосов
/ 25 мая 2018

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

struct node{
   int data;
   struct node*next;    
};  

int main(){
   struct node *newnode=NULL;
   struct node *start=NULL;
   newnode=start=(struct node*)malloc(sizeof(struct node));
   newnode->data=1;

   //code snippet 
   newnode->next=NULL;
   newnode=newnode->next;
   newnode=(struct node*)malloc(sizeof(struct node));
   newnode->data=2;
   start=start->next;//error probably as start->next is perceived as NULL Address
   printf("%d",start->data);
   return 0;    
}

при замене фрагмента кода на этот код

newnode->next=(struct node*)malloc(sizeof(struct node));
newnode=newnode->next;
newnode->data=2;
start=start->next;
printf("%d",start->data);

ошибка рассеяна ... Как можно это оправдать?

Ответы [ 5 ]

0 голосов
/ 26 мая 2018

Вы правы, что ошибка происходит от printf("%d",start->data);, где вы пытаетесь разыменовать указатель на NULL.

Позвольте мне объяснить это графически: с помощью первых 4 строк вы получите это:

             _____________
newnode ->  | data = 1    |
start   ->  | next = null |
            |_____________|

Эта строка newnode->next=NULL; ничего не делает.Затем newnode=newnode->next; делает это:

             _____________
            | data = 1    |
start   ->  | next = null |      newnode -> NULL
            |_____________|

Затем

 newnode=(struct node*)malloc(sizeof(struct node));
 newnode->data=2;`

делает это:

             _____________                    _____________
            | data = 1    |                  | data = 2    |
start   ->  | next = null |      newnode ->  | next = null | 
            |_____________|                  |_____________|

Наконец, start=start->next; устанавливает состояние следующим образоми, очевидно, вы пытаетесь получить доступ к полю указателя на NULL в результате.

                                              _____________
                                             | data = 2    |
start   ->  null                 newnode ->  | next = null | 
                                             |_____________|
0 голосов
/ 25 мая 2018

Позвольте мне прокомментировать, что делает первая версия:

newnode=start=(struct node*)malloc(sizeof(struct node));
...
// at this point, newnode and start point to the same node

newnode->next=NULL; 
// since start points to the same node as newnode, this means that also 
// start->next will be NULL 
...
start=start->next; // since start->next is null, start will be null after this statement

printf("%d",start->data);  // start is null, so start->null dereferences NULL (undefined behaviour, e.g. a crash or something dubious)

Ваша вторая версия отличается, потому что ...

newnode->next=(struct node*)malloc(sizeof(struct node));
// this lets newnode->next point to a valid (new) node
// since start==newnode, also start->next will point to this valid (new) node

start=start->next;  // afterwards, start will point to the valid (new) node
printf("%d",start->data); // OK; should print 2 then. 

Я думаю, вы могли бы спутать выражение присваивания с "определение псевдонима ":

newnode=newnode->next;
newnode=(struct node*)malloc(sizeof(struct node)); 

очень отличается от

newnode->next = (struct node*)malloc(sizeof(struct node));

, потому что

newnode = newnode->next 

не определяет макрос или текст замены для newnode, так чтотекст newnode заменяется текстом newnode->next отныне.Скорее, переменная newnode получит новое значение, то есть значение, на которое указывает элемент next этого узла.

0 голосов
/ 25 мая 2018

В первом коде newnode и start оба начинают указывать на тот же node, который вы выделили.Затем вы устанавливаете newnode->next = NULL;, так что для start->next также устанавливается NULL.

Затем вы делаете:

newnode = newnode->next;
newnode = (struct node*)malloc(sizeof(struct node));

, так что newnode теперь указывает на другой узел, ноstart по-прежнему указывает на исходный узел.Так что start->next все еще NULL.Затем вы делаете:

start = start->next;

Это устанавливает start в NULL, поэтому попытка печати start->data недопустима, поскольку вы не можете разыменовать нулевой указатель.

Первыйприсваивание перед malloc() бессмысленно, потому что вы немедленно заменяете переменную чем-то другим.Полагаю, вы подумали, что при первом переназначении newnode вызов malloc() обновит и newnode , и newnode->next, поскольку вы объявили их эквивалентными.Но это не то, как работают назначения - все, что он делает, это копирует значение newnode->next в newnode, он не связывает эти два места вместе.

Ваша вторая версия получает это право, присваивая newnode->next скорее newnode.Это также присваивает start->next, потому что newnode и start изначально указывают на одну и ту же структуру.Затем вы назначаете

newnode = newnode->next;

Это обновляет newnode, но start все еще в порядке и указывает на первый узел.Когда вы затем делаете

start = start->next;

, он обновляет start, чтобы указывать также на второй узел.В этом случае допустимо start->data, оно содержит то же, что вы присвоили newnode->data несколькими строками ранее.

0 голосов
/ 25 мая 2018

В первом из ваших двух кодов у вас есть

newnode=newnode->next;
newnode=(struct node*)malloc(sizeof(struct node));

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

Во втором коде у вас вместо этого есть:

newnode->next=(struct node*)malloc(sizeof(struct node));
newnode=newnode->next;

Это имеет гораздо больше смысла.Сначала вы выделяете память и назначаете newnode->next для указания на нее, а затем обновляете newnode для указания на новую память.Кроме того, до этого момента у вас все еще есть start, указывающий на первый динамически распределенный блок, так что вы все равно можете получить к нему доступ, и, поскольку newnode и start изначально указывали на ту же структуру, то впоследствии может быть то же значениетоже получается через выражение start->next.

0 голосов
/ 25 мая 2018

Вы перезаписываете адрес newnode здесь

newnode = newnode->next;

Возможно, вы хотите:

start = malloc(sizeof(struct node));
start->data = 1;

newnode = malloc(sizeof(struct node));
newnode->data = 2;
newnode->next = NULL;

start->next = newnode;

printf("%d", start->data);
...