0

I am implementing a LinkedList with a bunch of ListNodes that are structs which contain some basic information about people. I have two files, one that is main.c, and another that is main.h. Whenever I attempt to print the list by passing the root to a function, I get an error.

Here is main.c:

#include "main.h"

/* Edward Nusinovich

    This C file is going to have a LinkedList containing information about people.
    The user can interact with it and manipulate the list.

*/

int main(int argc, char **argv){

    if(!checkIfValidArguments(argc).value){return -1;}

    ListNode *root = askForDetails(1,argv);
    ListNode *current = root;
    current->next = NULL;

    ListNode *temp;

    int index = 2;

    while(index<argc){
        temp = askForDetails(index,argv);
        current->next = temp;
        current = current->next;
        index++;
    }

    userLoop(root);

    return 0;
}

In my main.h file, I have no problem printing attributes of the root parameter in the function "userLoop", but as soon as I pass ListNode *root to "print" or "stuff" I get a seg fault when trying to print its values.

Here is main.h:

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

#define true 1
#define false 0

typedef struct bool{
    int value:1;
} boolean;

//this is going to store info about a person
typedef struct people{

    char *name;
    char *hairColor;
    char *eyeColor;
    char *age;
    struct people *next;    

} ListNode;

//using a 1 bit bitfield we have constructed, stores whether or not the user has entered a proper number of inputs
boolean checkIfValidArguments(int numArgs){

    boolean validArguments;

    if(numArgs>1){validArguments.value=true;}
    else{validArguments.value=false; printf("We need some names of people.\n");}

    return validArguments;
}

//this will construct a new Person and return him to 
ListNode *askForDetails(int personIndex, char **argv){

    ListNode toReturn;

    char *name = argv[personIndex];
    printf("Please enter the hair color, eye color, and age of %s.\n",name);

    char *inBuf=malloc(100);
    char nextchar=getchar();
    int index = 0;

    if(nextchar!='\n'){inBuf[index]=nextchar; index++;}

    while((nextchar=getchar())!='\n'){
        inBuf[index] = nextchar;
        index ++;
    }

    toReturn.name = name;
    toReturn.hairColor = strtok(inBuf," ");
    toReturn.eyeColor = strtok(NULL," ");
    toReturn.age = strtok(NULL,"\n");

    ListNode *newNode = malloc(sizeof(ListNode)); 
    newNode = &toReturn;    
    return newNode;
}

char *getInput(char *message){

    printf("%s",message);
    char *inBuf = malloc(40);
    char nextchar=getchar();
    int index = 0;
    if(nextchar!='\n'){inBuf[index]=nextchar; index++;}

    while((nextchar=getchar())!='\n'){
        inBuf[index] = nextchar;
        index ++;
    }

    return inBuf;

}

void addToEnd(ListNode *root){

    ListNode *current = root;

    char *inBuf = getInput("\nEnter the name of a person who you want to add: \n"); 

    ListNode *toAdd = malloc(sizeof(ListNode));
    toAdd = askForDetails(0,&inBuf);
    toAdd->name = inBuf;
    toAdd->next = NULL;

    while((current->next) != NULL){
        current = current->next;
    }

    current->next = toAdd;
}


void print(ListNode *root){

    printf("The name is %s.\n",root->name);
/*
    ListNode *current = root;

    do{
        printf("\n%s's hair is %s, their eyes are %s and they are %s years old.\n",current->name,current->hairColor,current->eyeColor,current->age);
        current = current->next;
    }while(current!=NULL);
*/  

}

void remEnd(ListNode *root){

    ListNode *current = root;

    if(current == NULL){ return; }





}

void addAfter(ListNode *root){

    ListNode *current = root;

    char *name = getInput("\nWho do you want to add after?\n");
    int comparison = 0; 

    while(current!=NULL&&(comparison = strcmp(name,current->name))!=0){
        current = current -> next;
    }

    if(current==NULL){printf("\nIndividual not found.\n"); return;}

    else{
        char *newPerson = getInput("What's the name of the person you wish to add? ");

        ListNode *toAdd = askForDetails(0,&newPerson);
        ListNode *next = current->next;
        current -> next = toAdd;
        toAdd->next = next;
        return;
    }

}

void stuff(ListNode *root){
    printf("name is %s.\n",root->name);
    printf("Root lives at %u.\n",root);
}

void userLoop(ListNode *root){

    char input = ' ';

    printf("Root lives at %u.\n",root);

    while(true){
        printf("name is %s.\n",root->name);     

        if(input!='\n'){
            printf("\nWhat would you like to do with your list:\n");
            printf("A) Add an element at the end of the list\n");
            printf("B) Remove an element from the end of the list\n");
            printf("C) Add an element after an element on your list\n");
            printf("D) Print your list\n");
            printf("E) Quit this program\n\n");
        }

        input = getchar();

        switch(input){
            case 'A': addToEnd(root); break;            
            case 'B': remEnd(root); break;
            case 'C': addAfter(root); break;
            case 'D': stuff(root); break;
            case 'E': return;
        }
    }

}

When printing the address in memory of root in both functions, I get the same value, so I'm not sure why I am unable to access the values in root in one function instead of the other.

Thank you so much for any help.

Enusi
  • 101
  • 1
  • 5
  • Why would you define your function in a header file? – EOF Apr 06 '16 at 01:22
  • why don't you simplify your question for better readability. – Dilip Kumar Apr 06 '16 at 01:22
  • you need `current->next = NULL;` after while-loop. – BLUEPIXY Apr 06 '16 at 01:24
  • 1
    Oh man, this is great. You define your own `boolean`-type (what a great idea) with a bitfield (uh oh) of width 1 and unspecified signedness (no words), and then you compare with self-defined `#define true 1` and `#define false 0`. What could go wrong? – EOF Apr 06 '16 at 01:25
  • `newNode = &toReturn;` should be `*newNode = toReturn;` – BLUEPIXY Apr 06 '16 at 01:29
  • @BLUEPIXY Thank you so much, may I ask why this works? Is that not the same thing I did? – Enusi Apr 06 '16 at 01:33
  • @EOF What's wrong with defining a boolean type this way? C doesn't come with a boolean type, and why would I want to use more than I bit for this? – Enusi Apr 06 '16 at 01:35
  • @E.Nusinovich 1 and 0 are not one bit. They will implicitly cast to the appropriate data type depending on how they are used. The smallest data type in C is char (usually one byte). – Adam Martin Apr 06 '16 at 01:36
  • It is not the same. In the case of you, you overwrite the address of the memory allocated by the address of the local variable. – BLUEPIXY Apr 06 '16 at 01:37
  • 2
    @E.Nusinovich: C99 certainly has `_Bool`, and `bool` if `` is included. Your boolean definition has the curious property that on conforming systems, after `boolean b = {true};`, `b == true` **may be false**. – EOF Apr 06 '16 at 01:38
  • Unfortunately the server which runs our code isn't C99 conforming. I thought this would be the best implementation using least memory. So just to be clear, even if I say unsigned int value:1, this still might give unwanted results? @EOF – Enusi Apr 06 '16 at 01:43
  • @E.Nusinovich Actually, the case when the bitfield is `signed` is the troubling one, since in that case the non-zero value in the bitfield will be `-1`, rather than `1`. Either way, you gain no advantage at all over `typedef`ing your boolean as `char`. – EOF Apr 06 '16 at 01:46
  • @EOF Gotcha - thank you. – Enusi Apr 06 '16 at 02:07

2 Answers2

3

You don't seem to quite grasp how the memory model works in C. Your offending piece of code is probably:

ListNode *newNode = malloc(sizeof(ListNode)); 
newNode = &toReturn;    
return newNode;

This returns a pointer to the local variable toReturn, not the malloc'd memory address. You need to copy the data from toReturn into your malloc'd memory space. However, even worse you don't malloc space for each of your strings, so each of your nodes point to the same input buffer. This should work, since you malloc with for every node, however if you are going to start deleting nodes managing your memory is going to be a little awkward. You also don't make sure there is enough room in your buffer.

I suggest looking at some online resources (or ideally a book) to refresh on how C memory works.

Edit: I did not learn C online, but a quick google search turned up this, which at a quick glance seems to be a decent resource.

I would recommend looking into book list. I used C Programming A Modern Approach.

Community
  • 1
  • 1
Adam Martin
  • 1,188
  • 1
  • 11
  • 24
  • Thank you very much. Each of the strings has separately malloc'd data though, because we call "askForDetails" each time we have a new ListNode, right? – Enusi Apr 06 '16 at 01:46
  • Yeah, except that you're going to have a heck of a time freeing it all. But yeah, should be fine I think. I misread it at first, thought it was worse than it is. – Adam Martin Apr 06 '16 at 01:49
0

I'm going to assume you're on a 64 bit system so that pointers are 8 bytes & integers are 4 bytes. Use %p for pointers, not %u

Demur Rumed
  • 421
  • 6
  • 17
  • This was just to verify that I wasn't getting different results, I know that it's not the whole address but I wanted to make sure it was the same. – Enusi Apr 06 '16 at 01:30