Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
261 views
in Technique[技术] by (71.8m points)

c - I am just curious to know why the following code does not give segmentation fault while executing

I have a function to print elements of a doubly linked list. I pass the head of the list to the function and use another variable inside the function. Without assigning the inside variable to the passed variable, I am able to access the list elements. [Note - AddtoHead function is not shown], Now added for clarity

#include <stdio.h>
#include <stdlib.h>    
struct Node {
    int data;
    struct Node *next;
    struct Node *prev;
};
void AddtoHead(struct Node **head_ptr, int data) {
    struct Node *new_node = (struct Node*)malloc(sizeof(struct Node));
    new_node->data = data;
    new_node->next = (*head_ptr);
    new_node->prev = NULL;

    if ((*head_ptr) != NULL)
        (*head_ptr)->prev = new_node;
    (*head_ptr) = new_node;
    return;
}
void PrintFList(struct Node *node) {
    struct Node* last;
    printf("
Walking FAKE List : 
");
    printf("%d-> 

", last->data);
    last = last->next;
    printf("%d-> 

", last->data);    
    return;
}
/* Let's another function to see if it exhibits the same behaviour. A fun Mull to multiply two nos which would be passed as argument */
int Mull(int a, int b) {
    int c, d;
    printf("

%d  %d
", c, d);
    return c*d;
}

int main()
{
    // Start with the empty list 
    struct Node* head = NULL;
    int i;
    // Insert through a for loop
    for (i = 0; i < 5; i++)
        AddtoHead(&head, i+10);

    PrintFList(head);

    // Mull() function does not show the same behaviour 
    printf("

Multiplication of a and b: %d 

", Mull(i, i+1));
    return 0;
}

It prints the following:

Walking FAKE List :
14->
13->

Whereas I was expecting a segmentation fault because last is not assigned


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Accessing an uninitialized pointer leads to undefined behavior. It means that everything can happen depending on a lot of scenarios that might occur at runtime.

The value of last local variable of PrintFList() function is stored in the process stack. Since it has never been initialized, it contains any value was previosly written there before the call.

It happens that the previous call from main was AddtoHead(14), and since it has a signature compatible to the one of PrintFList (meaning that both return void and have a single pointer parameter, so their calls will consume the stack in an identical way), its first local variable (node) occupies exactly the same location that later will be occupied by last.

And what is the value of node? Well, it is the valid address of the last inserted node, and that's why no segmentation fault occurs, and the print starts exactly from the last inserted node ("-> 14").

How to obtain a segmentation fault
Of course this apparently correct behavior is just luck: any further call before PrintFList() will likely overwrite that location of the stack, and a segmentation fault will occur.

In order to obtain the segfault you expected since the very first attempt you just have to place between AddtoHead(14) and PrintFList() a call to any function with some local variables in it. A simple example is... printf() (it for sure has a va_list local variable to parse its variadic arguments):

int main()
{
    // Start with the empty list 
    struct Node* head = NULL;
    int i;
    // Insert through a for loop
    for (i = 0; i < 5; i++)
        AddtoHead(&head, i+10);
        
    printf("hello %d times!
", i); 

    PrintFList(head); // --> Segmentation fault!
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...