Thread: Segmentation Fault -- Stack implementing a Linked List

  1. #1
    Registered User
    Join Date
    Feb 2014
    Posts
    4

    Segmentation Fault -- Stack implementing a Linked List

    The program is relatively simple, and is only suppose to take in a text file of a semicolon-delimited value/string/line, reverse the order of the values, put it all back together, and output to a new file. There are specifications, however, that we must use a stack that implements a simple Linked List data structure. I'm pretty new to C, and am just picking up the basics of pointers (I come from Java and .NET, and this is a nightmare for me to grapple with lol). Also, the specifications specifically say that the push() function MUST take in the "old top of stack (node)" and the "value to push", and return the updated pointer to the top of the stack. Also, pop() MUST take in as parameters a "pointer of a pointer to the current top of the stack", and return the value of the popped node.

    We are suppose to compile with gcc -o progname progname.c -Wall -m32 -O. The source compiles just fine, but when attempting to build the stack and such with an actual sample file, I receive a Segmentation Fault. I've run my code through gdb, however, and it's saying that Segmentation Fault is occurring at my "push((values -> head), str1);" call in main(). Since this is the call to push(), I'm guessing there's more fundamental logic error I'm overlooking in my linked list and/or stack.

    I've exhausted my brain at this point, and cannot for the life of me figure out where I'm going wrong. If anyone can provide me some assistance, I'd be forever grateful.

    Also, if some of the code appears ugly, I apologize. I've only been working with C for about 2 weeks now

    A sample input file would be:
    Code:
    23414;-5224;23;569;
    and expected output file would be:
    Code:
    569;23;-5224;23414;
    Here's what I've developed so far:
    Code:
    #include <stdio.h>
    #include <assert.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <stdbool.h>
    
    int STACK_ELEMENTS = 0;
    
    typedef struct node {
        char *value;
        struct node *next;
    } Node;
    
    typedef struct my_stack {
        Node *head;
    } Stack;
    
    Stack *values;
    
    bool stack_isEmpty() {
        if (STACK_ELEMENTS < 1)
            return true;
        else
            return false;
    }
    
    Node *push(Node *oldHead, char *val) {
        Node *newNode;
        newNode = malloc(sizeof(Node));
        newNode -> value = val;    
        
        if (oldHead == NULL) {
            values -> head = newNode;
            values -> head -> value = val;
        }
    
        else {
            values -> head -> next = newNode;
            values -> head = newNode;
        }
        free(newNode);
        STACK_ELEMENTS++;
        return (values -> head);
    }
    
    char *pop(Node **pHead) {
        char *val;
        if ((*pHead) != NULL) {
            Node *tempNode;
            tempNode = malloc(sizeof(Node));
            tempNode = *pHead;
            val = tempNode -> value;
            *pHead = tempNode -> next;
            free(tempNode);
            STACK_ELEMENTS--;
        }
        else
            return 0;
        return val;
        
    }
    
    int main(int argc, char *argv[]) {
        /*verify arguments*/
        if (argc != 3) {
            fprintf(stderr, "usage: strrev <file> <newfile>\n");
            exit(1);
        }
        
        char *fileIn = argv[1];
        char *fileOut = argv[2];
    
        /*open file streams*/    
        FILE *in = fopen(fileIn, "r");
        FILE *out = fopen(fileOut, "w");
        
        
        /*scan input file and delimt on semicolon*/
        /*input file is a single line of semicolon-delimited values*/
        char str1[128];
        while(!feof(in))
        {
            /*scan, delimiting on semicolon*/
            /*if the scanned element does not fit format, break*/
            if (fscanf(in, "%[^;];", str1) != 1) {
                break;
            }
            push((values -> head), str1);
        }
        
        while(!stack_isEmpty()) {
            fprintf(out,"%s;", pop(&(values -> head)));
        }
            
        fclose(in);
        fclose(out);
        return 0;
    }

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,666
    > newNode -> value = val;
    This makes a copy of the pointer, not a copy of the string it points to.

    > push((values -> head), str1);
    values is a global variable (which is bad), which will be initialised to NULL when the program starts.

    You need to decide whether your push/pop functions deal with a stack or a node (I recommend stack).
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Feb 2014
    Posts
    4
    > newNode -> value = val;
    This makes a copy of the pointer, not a copy of the string it points to.
    Thanks for the quick reply. Would you mind explaining this a bit more for me? I'm not sure I grasp it... What I want to have happen in that call to push is to have the newNode's value field set to the passed val string. I'm sure what I'm doing is wrong, I could just use a bit more explanation, sorry.

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,666
    Before you make it all complicated with file handling, try this.

    Code:
            push((values -> head), "hello");
            push((values -> head), "world");
            printf("Top String=%s\n", pop(&(values -> head)));
            printf("Stack empty=%d\n", stack_isEmpty());
    It should print "world" and 0

    Next you move onto
    Code:
        push((values -> head), "hello");
        push((values -> head), "world");
        while(!stack_isEmpty()) {
            printf("String=%s\n", pop(&(values -> head)));
        }
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  5. #5
    Registered User
    Join Date
    Feb 2014
    Posts
    13
    This code is wrong, newNode -> value = val;

    You need to allocate memory for
    newNode -> value and then copying the content from the pointer val

    Code:
    newNode = malloc(sizeof(Node));
    if (null != newNode)
    {
     newNode -> value = malloc(strlen(val) + 1);
     if (null != newNode -> value)
     {
      strcpy(newNode -> value, val);
     }
    }
    


    Also please note that you need to free the allocated pointer for the value first and then node in the function pop()

    Code:
    
    
    Code:
    free(tempNode->value);
    free(tempNode);

  6. #6
    Registered User
    Join Date
    Feb 2014
    Posts
    4
    I took Salem's suggestion and started simple, and was able to slightly modify my push() function to properly push "hello" and "world" onto the stack (and also have them echo out correctly). I also made the current "instance" of the Stack non-global. However, after attempting to re-implement the file handling and the fscanf(), The issue I run into is that the first value is the only one being added to the stack. The correct number of times -- just not the correct data. This leads me to believe it's an issue with the code that follows
    Code:
    char *str1 =  malloc(128);
    
    ...
    within the main() function. Again, however, I can't seem to wrap my head around what exactly the pointer issue is. But, because the "hello" and "world" test cases worked successfully, I'm fairly certain it's an issue with the way I'm addressing the strings after delimiting the file.

    Thanks in advance, you guys are super helpful!

    Updated code (a bit has changed):

    Code:
    #include <stdio.h>
    #include <assert.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <stdbool.h>
    #include <string.h>
    
    /*global variable to track current number of elements in stack*/
    int STACK_ELEMENTS = 0;
    
    /*struct for a new Node*/
    typedef struct node {
        char *value;
        struct node *next;
    } Node;
    
    /*struct for a Stack*/
    typedef struct my_stack {
        Node *head;
    } Stack;
    
    /*determines if stack is empty or not*/
    bool stack_isEmpty() {
        if (STACK_ELEMENTS < 1)
            return true;
        else
            return false;
    }
    
    /*push a new node onto the current stack*/
    /*return the new head node*/
    Node *push(Node **currHead, char *val) {
        Node *tempNode = malloc(sizeof(Node));
        
        tempNode -> value = val;
        tempNode -> next = *currHead;
        *currHead = tempNode;
    
        STACK_ELEMENTS++;
        return (*currHead);
    }
    
    /*pop off current top node of the stack and return its value*/
    char *pop(Node **pHead) {
        char *val;
        /*as long as the head isn't a NULL, ie empty stack*/
        if ((*pHead) != NULL) {
            Node *tempNode;
            tempNode = malloc(sizeof(Node));
            tempNode = *pHead;
            val = tempNode -> value;
            *pHead = tempNode -> next;
            free(tempNode);
            STACK_ELEMENTS--;
        }
        else
            return 0;
        return val;
        
    }
    
    int main(int argc, char *argv[]) {
        /*verify arguments*/
        if (argc != 3) {
            fprintf(stderr, "usage: strrev <file> <newfile>\n");
            exit(1);
        }
        
        char *fileIn = argv[1];
        char *fileOut = argv[2];
    
        /*open file streams*/    
        FILE *in = fopen(fileIn, "r");
        FILE *out = fopen(fileOut, "w");
        
        /*initialize new stack called values*/
        Stack *values;
        values = malloc(sizeof(Stack));
        
        
        char *str1 = malloc(128);
        while(!feof(in))
        {
            
            /*scan, delimiting on semicolon*/
            /*if the scanned element does not fit format, break*/
            if (fscanf(in, "%[^;];", str1) != 1) {
                break;
            }
    
            push(&(values -> head), str1);
        }
        
        /*go through stack until it's empty, writing each popped value to a file*/
        /*this will accomplish reversal due to LIFO*/
        while(!stack_isEmpty()) {
            fprintf(out,"%s;", pop(&(values -> head)));
        }
        
        free(str1);
        fclose(in);
        fclose(out);
        return 0;
    }
    Last edited by jackalclone1; 02-13-2014 at 05:50 PM.

  7. #7
    Registered User
    Join Date
    May 2009
    Posts
    4,183
    I know the second thing I would do would be to change most your function signatures. The first would be to change the struct for stack.

    Your code.
    Code:
    /*global variable to track current number of elements in stack*/
    int STACK_ELEMENTS = 0;
    Code:
    /*struct for a Stack*/
    typedef struct my_stack {
        Node *head;
    } Stack;
    To something like this.

    Code:
    /*struct for a Stack*/
    typedef struct my_stack {
        Node *top;
        int elements;
    } Stack;
    But, I am NOT sure what your assignment really is.

    I am guessing you are supposed to implement a stack by way of a link list. Your OP stated the opposite to me.

    If my above guess is true your function signatures should have the type Stack in them.

    Edit: I suggest re-reading the specifications!

    Tim S.
    Last edited by stahta01; 02-13-2014 at 07:23 PM.
    "...a computer is a stupid machine with the ability to do incredibly smart things, while computer programmers are smart people with the ability to do incredibly stupid things. They are,in short, a perfect match.." Bill Bryson

  8. #8
    Registered User
    Join Date
    May 2009
    Posts
    4,183
    Found what is likely the bad line of code.

    Code:
    tempNode -> value = val;
    The above line does NOT do what you think it does.

    You likely need to use strcpy and malloc to fix this issue.

    I am too tired right now to help you do it.

    Edit: I missed kannanm post that stated the same thing I did in this post and gave what looks like good code.
    Edit2: The "null" in that post should likely be "NULL".

    Tim S.
    Last edited by stahta01; 02-13-2014 at 09:12 PM.
    "...a computer is a stupid machine with the ability to do incredibly smart things, while computer programmers are smart people with the ability to do incredibly stupid things. They are,in short, a perfect match.." Bill Bryson

  9. #9
    Registered User
    Join Date
    Feb 2014
    Posts
    4
    Oh man, thank you so much. I, too, also missed kannanm's suggestion (thank you, kannanm). Would have saved me a lot of frustration if I'd have caught it haha. Everything works as expected now.

    I am still, however, struggling to understand why the simple tempNode -> value = val was not working? It seems odd to me that it would work with the old code with hard-coded string values like "hello" and "world", but not for char *str[] type values. Anyone mind helping my dumb self understand this?

  10. #10
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by jackalclone1 View Post
    I am still, however, struggling to understand why the simple tempNode -> value = val was not working? It seems odd to me that it would work with the old code with hard-coded string values like "hello" and "world", but not for char *str[] type values. Anyone mind helping my dumb self understand this?
    It didn't work then either. You were setting the pointers to point to a previous example of a string literal, not making a copy. (Had you attempted to treat it as a copy, by say trying to change it, it would have blown up instantly.)

  11. #11
    Registered User
    Join Date
    Jun 2011
    Posts
    4,513
    Some more (or more of the same) advice over here on the cross post.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 11
    Last Post: 11-09-2012, 12:45 PM
  2. Replies: 2
    Last Post: 11-08-2012, 02:05 AM
  3. Segmentation fault in linked list...doubt
    By alphasil in forum C Programming
    Replies: 17
    Last Post: 07-11-2012, 05:23 PM
  4. Doubly linked list-segmentation fault
    By prapanch in forum C Programming
    Replies: 2
    Last Post: 05-10-2012, 11:04 PM
  5. Doubly Linked List Segmentation Fault
    By DaNxTh3xMaNx in forum C Programming
    Replies: 5
    Last Post: 09-09-2011, 09:50 AM