newNode создается без возврата созданного узла из функции createNode (int) - PullRequest
1 голос
/ 01 октября 2019

**** Поскольку я создал функцию с именем createNode (int), которая будет возвращать блок памяти типа struct node *, но я не упомянул, что код return (temp) по-прежнему работает правильно, работая как вставка,удаление работает нормально, есть какая-нибудь концепция кучи или стека там .?****

struct node* createNode(int data){
    struct node *temp;
    temp = (struct node*)malloc(sizeof(struct node));
    temp->data = data;
    temp->next = NULL;
    // return temp 
}
void insertNode(int position){
    struct node *temp;
    ....
    temp = createNode(data);
    ....
}

1 Ответ

1 голос
/ 01 октября 2019

Это неопределенное поведение. Но я все же попытаюсь объяснить, почему тебе здесь повезло.

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

/* test.c */
#include<stdio.h>
#include<stdlib.h>
struct node {
        int data;
        struct node* next;
};
struct node* createNode(int data){
    struct node *temp;
    temp = (struct node*)malloc(sizeof(struct node));
    temp->data = data;
    temp->next = NULL;
    // return temp
}
int main(){
    struct node *temp = createNode(12);
    printf("%d %x", temp->data);
}

Компиляция:

$ gcc -g test.c

Запустите его с помощью GDB, чтобы вы могли видетьdisassembly

$ gdb -q ./a.out
Reading symbols from /root/a.out...done.

Разберите функцию createNode, чтобы увидеть, где находится возвращаемое значение из malloc (поскольку это значение мы вернем обратно к main). Обратите внимание, что rax, который обычно содержит возвращаемое значение функции, содержит возвращаемое значение malloc (вот где вам повезло)

(gdb) disass createNode
Dump of assembler code for function createNode:
   0x0000000000400580 <+0>:     push   %rbp
   0x0000000000400581 <+1>:     mov    %rsp,%rbp
   0x0000000000400584 <+4>:     sub    $0x20,%rsp
   0x0000000000400588 <+8>:     mov    %edi,-0x14(%rbp)
   0x000000000040058b <+11>:    mov    $0x10,%edi
   0x0000000000400590 <+16>:    callq  0x400480 <malloc@plt>
   0x0000000000400595 <+21>:    mov    %rax,-0x8(%rbp)          <== rax register contains the return value of malloc, value is pushed to stack
   0x0000000000400599 <+25>:    mov    -0x8(%rbp),%rax          <== rax value retrieved from stack. now rax contains the return value of malloc
   0x000000000040059d <+29>:    mov    -0x14(%rbp),%edx
   0x00000000004005a0 <+32>:    mov    %edx,(%rax)              <== node->next assignment is done here
   0x00000000004005a2 <+34>:    mov    -0x8(%rbp),%rax          <== again rax is populated by return value of malloc
   0x00000000004005a6 <+38>:    movq   $0x0,0x8(%rax)           <== node->next is assigned to NULL here.
   0x00000000004005ae <+46>:    leaveq
   0x00000000004005af <+47>:    retq
End of assembler dump.

Разберите функцию main, чтобы увидеть, как было createNodeназывается и откуда мы получаем возвращаемое значение. Обратите внимание, что значение rax считывается в переменную temp в кадре main.

(gdb) disass main
Dump of assembler code for function main:
   0x00000000004005b0 <+0>:     push   %rbp
   0x00000000004005b1 <+1>:     mov    %rsp,%rbp
   0x00000000004005b4 <+4>:     sub    $0x10,%rsp
   0x00000000004005b8 <+8>:     mov    $0xc,%edi
   0x00000000004005bd <+13>:    callq  0x400580 <createNode>     <== createNode called
   0x00000000004005c2 <+18>:    mov    %rax,-0x8(%rbp)           <== rax contains the malloc's return value, so we got the correct value luckily
   0x00000000004005c6 <+22>:    mov    -0x8(%rbp),%rax
   0x00000000004005ca <+26>:    mov    (%rax),%eax
   0x00000000004005cc <+28>:    mov    %eax,%esi
   0x00000000004005ce <+30>:    mov    $0x400670,%edi
   0x00000000004005d3 <+35>:    mov    $0x0,%eax
   0x00000000004005d8 <+40>:    callq  0x400450 <printf@plt>
   0x00000000004005dd <+45>:    leaveq
   0x00000000004005de <+46>:    retq
End of assembler dump.
(gdb) q

Надеюсь, это объясняет, почему мы видим правильное значение в temp, даже если в createNode не было оператора return.

...