Aseem Bansal
Aseem Bansal

Reputation: 6962

Passing pointers between functions in an implementation of linked list

The problem was solved. A guy gave it in comments. The problem was that I was using %d to read in a short int. I should have used %hd or I should have used an `int'.


I tried to create a program of singly-linked list using only local variables. I was able to make a working program by using global variables.

The program with local variables compiles but it crashes when I try to traverse the linked list.

I have absolutely no idea what is wrong with the implementation with local variables. What is the problem present in the Implementation with local variables?

ABOUT THE STRUCTURE OF THE PROGRAMS:

I understand that the programs are big so I'll put in something about structure of the program.

//WORKING IMPLEMENTATION USING GLOBAL VARIABLE

#include<stdio.h>
#include<stdlib.h>

#define MIN 0
#define MAX 2

#define INS_MIN 0
#define INS_MAX 2

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

sll_node *start = NULL;

void intro()
{
    system("cls");
    printf("\n\tThese are the various options:\n");
    printf("\n\t00 Exit");
    printf("\n\t01 Traverse the list");
    printf("\n\t02 Insertion into the list");
}

void insert_begin()
{
    sll_node *node = malloc(sizeof(sll_node));
    if(node == NULL)
    {
        printf("\n\tNot enough menory");
        exit(-1);
    }
    int data;
    printf("\n\tData to be entered: ");
    scanf("%d", &data);

    node->data = data;
    node-> next = start;
    start = node;
}

void insert_end()
{
    sll_node *node = malloc(sizeof(sll_node));
    if(node == NULL)
    {
        printf("\n\tNot enough menory");
        exit(-2);
    }

    if(start == NULL)
        insert_begin();
    else
    {
        printf("\n\tData to be entered: ");
        scanf("%d", &(node->data));
        node-> next = NULL;

        sll_node *node2;
        for(node2 = start; node2->next != NULL; node2 = node2->next)
            ;
        node2->next = node;
    }
}

void insert_intro()
{
    system("cls");
    printf("\n\tThese are the various options:\n");
    printf("\n\t00 Insertion Done");
    printf("\n\t01 Insert at beginning");
    printf("\n\t02 Insert at end");
}

void insertion()
{
    short choice;
    while(1)
    {
        choice = -1;
        while(choice < INS_MIN || choice > INS_MAX)
        {
            insert_intro();
            printf("\n\n\tEnter your chocie: ");
            scanf("%d", &choice);
        }

        switch(choice)
        {
        case 0:
            return;
        case 1:
            insert_begin();
            break;
        case 2:
            insert_end();
            break;
        }
    }
}

void traverse()
{
    if(start == NULL)
        printf("\n\n\tLinked list is empty");
    else
    {
        printf("\n\n\t");
        for(sll_node *node = start; node != NULL; node = node->next)
            printf("%d ", node->data);
    }
    getch();
}

int main()
{
    short choice;
    while(1)
    {
        choice = -1;
        while(choice < MIN || choice > MAX)
        {
            intro();
            printf("\n\n\tEnter your choice: ");
            scanf("%d", &choice);
        }

        switch(choice)
        {
        case 0:
            return 0;
        case 1:
            traverse();
            break;
        case 2:
            insertion();
            break;
        }
    }
    return 0;
}

//COMPILES BUT CRASHES - Same program but with local variable start and variable passing between functions

#include<stdio.h>
#include<stdlib.h>

#define MIN 0
#define MAX 2

#define INS_MIN 0
#define INS_MAX 2

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

void intro()
{
    system("cls");
    printf("\n\tThese are the various options:\n");
    printf("\n\t00 Exit");
    printf("\n\t01 Traverse the list");
    printf("\n\t02 Insertion into the list");
}

sll_node* insert_begin(sll_node *start)
{
    sll_node *node = malloc(sizeof(sll_node));
    if(node == NULL)
    {
        printf("\n\tNot enough menory");
        exit(-1);
    }
    int data;
    printf("\n\tData to be entered: ");
    scanf("%d", &data);

    node->data = data;
    node-> next = start;
    return node;
}

sll_node* insert_end(sll_node *start)
{
    sll_node *node = malloc(sizeof(sll_node));
    if(node == NULL)
    {
        printf("\n\tNot enough menory");
        exit(-2);
    }

    if(start == NULL)
        start = insert_begin(start);
    else
    {
        printf("\n\tData to be entered: ");
        scanf("%d", &(node->data));
        node-> next = NULL;

        sll_node *node2;
        for(node2 = start; node2->next != NULL; node2 = node2->next)
            ;
        node2->next = node;
    }
    return start;
}

void insert_intro()
{
    system("cls");
    printf("\n\tThese are the various options:\n");
    printf("\n\t00 Insertion Done");
    printf("\n\t01 Insert at beginning");
    printf("\n\t02 Insert at end");
}

sll_node* insertion(sll_node *start)
{
    short choice;
    while(1)
    {
        choice = -1;
        while(choice < INS_MIN || choice > INS_MAX)
        {
            insert_intro();
            printf("\n\n\tEnter your chocie: ");
            scanf("%d", &choice);
        }

        switch(choice)
        {
        case 0:
            return start;
        case 1:
            start = insert_begin(start);
            break;
        case 2:
            start = insert_end(start);
            break;
        }
    }
}

void traverse(sll_node *start)
{
    if(start == NULL)
        printf("\n\n\tLinked list is empty");
    else
    {
        printf("\n\n\t");
        for(sll_node *node = start; node != NULL; node = node->next)
            printf("%d ", node->data);
    }
    getch();
}

int main()
{
    sll_node *start = NULL;
    short choice;
    while(1)
    {
        choice = -1;
        while(choice < MIN || choice > MAX)
        {
            intro();
            printf("\n\n\tEnter your choice: ");
            scanf("%d", &choice);
        }

        switch(choice)
        {
        case 0:
            return 0;
        case 1:
            traverse(start);
            break;
        case 2:
            start = insertion(start);
            break;
        }
    }
    return 0;
}

Upvotes: 0

Views: 1253

Answers (5)

Boiko Angelov
Boiko Angelov

Reputation: 21

Yes, sorry. There was another bug hard to see. It was at 2 lines where you read (choice).

    short choice;
    ...
    // It is ERROR to use "%d" with (short choice), because the stack will
    // be overwritten with unsuspected results. The format specifier "%hd"
    // say to compiler that (&choice) point to a short 16-bit integer,
    // not 32-bit
    scanf("%hd", &choice);

This is slightly different version, tested, without memory leaks.

//

    #include <stdio.h>
    #include <stdlib.h>
    #include <assert.h>

    #define MIN 0
    #define MAX 2
    #define INS_MIN 0
    #define INS_MAX 2

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

    void clear_list(sll_node** start)
    {
        assert(start != NULL);
        sll_node* node = *start;
        while (node != NULL)
        {
            sll_node* element = node;
            node = element->next;
            free(element);
        }
        *start = NULL;
    }

    void intro()
    {
        system("cls");
        printf("\n\tThese are the various options:\n");
        printf("\n\t00 Exit");
        printf("\n\t01 Traverse the list");
        printf("\n\t02 Insertion into the list");
    }

    void insert_begin(sll_node** pstart)
    {
        sll_node* node = (sll_node*)malloc(sizeof(sll_node));
        if (node == NULL)
        {
            printf("\n\tNot enough menory");
            clear_list(pstart);
            exit(-1);
        }
        int data;
        printf("\n\tData to be entered: ");
        scanf_s("%d", &data);//scanf
        node->data = data;
        node->next = *pstart;
        // update the local variable start passed from main to point just inserted node
        *pstart = node;
    }

    void insert_end(sll_node** start)
    {
        assert(start != NULL);
        if (*start == NULL)
        {
            insert_begin(start);
        }
        else
        {
            sll_node* node = (sll_node*)malloc(sizeof(sll_node));
            if (node == NULL)
            {
                printf("\n\tNot enough menory");
                clear_list(start);
                exit(-2);
            }
            printf("\n\tData to be entered: ");
            scanf("%d", &(node->data));
            node->next = NULL;
            sll_node* node2;
            for(node2 = *start; node2->next != NULL; node2 = node2->next)
                ;
            node2->next = node;
        }
    }

    void insert_intro()
    {
        system("cls");
        printf("\n\tThese are the various options:\n");
        printf("\n\t00 Insertion Done");
        printf("\n\t01 Insert at beginning");
        printf("\n\t02 Insert at end");
    }

    void insertion(sll_node** start)
    {
        short choice;
        while(1)
        {
            choice = -1;
            while(choice < INS_MIN || choice > INS_MAX)
            {
                insert_intro();
                printf("\n\n\tEnter your chocie: ");
                scanf("%hd", &choice);
            }
            switch(choice)
            {
            case 0:
                return;
            case 1:
                insert_begin(start);
                break;
            case 2:
                insert_end(start);
                break;
            }
        }
    }

    void traverse(sll_node *start)
    {
        if (start == NULL)
            printf("\n\n\tLinked list is empty");
        else
        {
            printf("\n\n\t");
            for(sll_node *node = start; node != NULL; node = node->next)
                printf("%d ", node->data);
        }
        getch();
    }

    int main()
    {
        sll_node *start = NULL;
        short choice;
        while(1)
        {
            choice = -1;
            while(choice < MIN || choice > MAX)
            {
                intro();
                printf("\n\n\tEnter your choice: ");
                scanf("%hd", &choice);
            }
            switch(choice)
            {
            case 0:
                clear_list(&start);
                return 0;
            case 1:
                traverse(start);
                break;
            case 2:
                insertion(&start);
                break;
            }
        }
        return 0;
    }

P.S. Very hard to edit! I'm new here and do not have enough experience. Wasted a lot of time to edit!

Upvotes: 0

tay10r
tay10r

Reputation: 4347

Change short choice to int choice.

Why does this make a difference?

Short answer is that printf("%d") expects an integer.

The long answer is "%d" describes the data type you are passing to printf as an integer (which is commonly 4 to 8 bytes), and you're giving it a datatype of short - which is commonly 2 bytes long. When your program reads the input and stores it at the pointer, &choice, it writes 4 bytes starting at that address (but only 2 were reserved). This causes a segmentation fault and will crash your program.

Here's a list to some printf documentation. You'll notice that to pass a short to printf you would write %hd instead of %d

Upvotes: 2

Boiko Angelov
Boiko Angelov

Reputation: 21

About the crash. Change the argument start in both functions insert_begin and insert_end to sll_node ** start, and when assigning new value, use the expression *start = your-new-value. It is because you have to pass a pointer to the local variable start which is also pointer. You do not need to change function traverse.

About memory leaks, let me to point-out that when you call insert_begin from inside insert_end, the node created from insert_end is left unused. before exit() and the return in main() you should free the list.

Upvotes: 0

user2513066
user2513066

Reputation:

When i compile your code on my computer, it works, but i changed "short choice" to "int choice", because scanf("%d", &choice) takes 4 bytes to write on, and when choice is short it crashes, because short has only 2 bytes, therefore stack corruption will occur, my be on your computer this corruption damage the "start" pointer.

Upvotes: 1

Rohan
Rohan

Reputation: 53326

You are not returning anything from insertion() function when item is added to a list. So linked list may not get constructed properly.

Probably, you should return start only when its added at the beginning, otherwise start in main() will not point to head of the list.

sll_node* insertion(sll_node *start)
{
        ...
        switch(choice)
        {
        case 0:
            return start;
        case 1:
            start = insert_begin(start);
            return start;  //<----- return node
            break;
        case 2:
            start = insert_end(start);
            break;
        }
    ...

}

Upvotes: 3

Related Questions