Segmentation Fault when using Linked Lists and Char arrays - c

I'm struggling through my programming homework and need a hand with Linked Lists. Basically we have to create a program that contains certain functions to manage linked lists. Fairly standard. I tried it last week and just couldn't get it. I'm trying to get it working this weekend and was making good progress until I ran into segmentation faults.
struct STUDENT
{
char *FirstName;
char *LastName;
char *PUID;
int age;
struct STUDENT *next;
};
This is the structure I'm trying to use. The first three values are char arrays and the fourth is just a number. Following this I tried to declare a starting and current node globally.
struct STUDENT *head = NULL;
struct STUDENT *curr = NULL;
Following this I have my create node function, which takes a user input and puts it into the list.
void *createListNode()
{
char first[MAXNAME];
char last[MAXNAME];
char ID[MAXID];
char *pfirst;
char *plast;
char *pID;
int tage;
struct STUDENT *temp = (struct STUDENT *) malloc (sizeof(struct STUDENT));
printf("Enter a first name: ");
scanf("%s", first);
pfirst = first;
printf("entered name: %s\n", pfirst);
printf("Enter a last name: ");
scanf("%s", last);
plast = last;
printf("entered name: %s\n", plast);
printf("Enter the Purdue ID: ");
scanf("%s", ID);
pID = ID;
printf("ID: %s\n", pID);
printf("Enter an age: ");
scanf("%d", &tage);
printf("age: %d\n", tage);
temp->FirstName = strdup(first);
printf("first\n");
temp->LastName = strdup(last);
printf("last\n");
temp->PUID = strdup(ID);
printf("id\n");
temp->age = tage;
printf("age\n");
temp->next = NULL;
printf("next\n");
if (curr == NULL)
{
printf("inside if\n");
head->next = temp; //-------SEGMENTATION FAULT---------------------
printf("line 107\n");
head = curr = temp;
printf("line 109\n");
}
else
{
curr = temp;
}
}
Background of what I'm done up to this point:
I was getting segmentation faults when I tried to assign my arrays to my 'temp' node, but by using malloc on it I solved that problem. Using print statements, I've tracked the problem to the indicated line. When I try to run the code, I get a segmentation fault. I tried the same malloc code above on the 'head' and 'curr' nodes, but that gave me:
carlton#carlton-Inspiron-N7010:~/CNIT315$ gcc lab5.c
lab5.c:20:64: error: invalid initializer
struct STUDENT head = (struct STUDENT *) malloc (sizeof(struct STUDENT));
This is where I believe the problem is, but I've been searching and experimenting for several hours and haven't gotten anywhere. And I just realized this is now a very long post. Thanks for reading it through and I appreciate any push in the right direction!

You initialize head to NULL. You can't dereference head before assigning a valid pointer to it. head->next = temp; gives you a segfault because head is a null pointer.
Thus, you need to review this part of the code:
if (curr == NULL)
{
printf("inside if\n");
head->next = temp; //-------SEGMENTATION FAULT---------------------
printf("line 107\n");
head = curr = temp;
printf("line 109\n");
} else
{
curr = temp;
}
Since it seems like you want to insert at the end of the list, I would suggest something like this:
temp->next = NULL;
if (head == NULL) {
curr = head = temp;
} else {
curr->next = temp;
curr = temp;
}
This makes curr always point to the last node, and head always points to the beginning of the list.

Am I wrong or do you set head->next = temp; but never set head to a valid object before?
You either have to initialize head with an 'empty' Student at the beginning or you just have to set head = temp;

Assuming that you've defined the head variable outside the createListNode() function, here's the problem:
Memory is never assigned to it, since you have never called malloc()

Related

Linked lists in C with chars and integers (troubleshooting)

I want to programm a linked list in C, trying to apply everything I've learned so far.
I wrote this program to create a linked list:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node *head = NULL;
//Define struct node
struct node{
char * name;
int num;
struct node * next;
};
//Print List
void printList(){
struct node * temp = head;
while (temp != NULL){
printf("%s", temp->name);
printf("%d", temp->num);
temp = temp->next;
}
}
//Create New Node
struct node * newNode (char * name, int num){
struct node * newNode = (struct node*)malloc(sizeof(struct node));
newNode->name = name;
newNode->num = num;
newNode->next = NULL;
return newNode;
}
//Function to insert and sort Elements
void insertSorted (char * name, int num){
//Empty Liste -> Head is NULL
if (head == NULL){
head = newNode(name, num);
}
else if (strcmp(name, head->name) <=0){
// strcmp-output = -1 ->string 1 > string 2; 0 -> both strings are the same
struct node * temp = newNode(name, num);
temp->next = head;
head = temp;}
struct node * current = head; struct node *prev = NULL;
if (strcmp(name, current->name)>0){ //-> 1, string1 < string 2 ->insert after
while(current != NULL && strcmp(name, current->name)<=0){
prev = current;
current = current->next;
}
struct node * temp = newNode(name, num);
prev->next = temp;
temp->next = current;
}
}
//Test of the linked list
int main()
{
char name; int num;
//Testprogram
printf("Enter a name\n");
scanf("%s", &name);
printf("Enter a number\n");
scanf("%d", &num);
insertSorted(&name, num);
char name2; int num2;
printf("Enter a name\n");
scanf("%s", &name);
printf("Enter a number\n");
scanf("%d", &num2);
insertSorted(&name2, num2);*/
char name3; int num3;
printf("Enter a name\n");
scanf("%s", &name);
printf("Enter a number\n");
scanf("%d", &num3);
insertSorted(&name3, num3);
printList();
return 0;
}
Output example:
Input: Anna 1, Claudio 2, Berta 3
Output: 32Berta1
It somehow...makes the Names vanish and the numbers are in the wrong order too. I'm pretty new to programming, so I have troubles fixing this by myself.
Any help would be hugely appreciated :) Not only to fix the error, but also tips on how to program more...elegantly, so to say.
Thanks :)
//Edit:
Thank you for all the input so far! I messed up the input of the string while testing the program.
As suggested I tried to skip the part with the input, testing the linked list like this in main() (thanks Julien!):
insertSorted("Anna", 1);
insertSorted("Claudio", 2);
insertSorted("Berta", 3);
printList();
it results in the programm not executing and exiting with a negative number error code. Does this point to an infinite loop?
I haven't looked at the linked list details, but one issue I see is that you are using single char variable to store the names (which should be an array or characters). This lack of enough space to store the input make you program have an undefined behaviour after the call to scanf.
As #franji1 stated, try working step by step. If you want to check the code of your list, try testing:
insertSorted("Anna", 1);
insertSorted("Claudio", 2);
insertSorted("Berta", 3);
And check the result is what you expect. Once this is working, add the code asking for input from the user using scanf.
Im not an expert at C but since you mentioned code elegancy I can tell you this. You didn't need to use all these different if statements, you could use the while loop from the begining and insert after you find a name that is bigger than current. This will work even if it has to be inserted before the head node as long as you check that prev is not null. I hope I helped you and that you will find a solution to your problem!

access to data allocated by pointer in a structure issue

I'm working on code that using structures and Linked list.
Please help me to understand how can I print any added point that is not in the head of the list created.
Any attempt was a failure.
*Issue on the second print call.
Is my only option is to do head = head->next in order to get the next variables?
Structures:
typedef struct
{
int x;
int y;
}point;
typedef struct {
point *p;
struct Item *next;
}Item;
Main:
void main()
{
Item *head = (Item*)malloc(sizeof(Item)); //head of co-list
if (!head) { //allocation check
printf("Allocation failed (head)\n");
exit(1);
}
head = addBegin(head);
printf("head point: (%d,%d)\n",head->p->x,head->p->y);
system("pause");
head = addBegin(head);
**printf("head second point: (%d,%d)\n",head->next->p->x,head->next->p->y);**
system("pause");
free(head->p);
free(head);
}
The function:
Item * addBegin(Item *head)
{
Item *tmp = (Item*)
malloc(sizeof(Item));
if (tmp) {
tmp->p = (point*)malloc(sizeof(point));
printf("Enter x's point: ");
scanf(" %d", &tmp->p->x);
printf("Enter y's point: ");
scanf(" %d", &tmp->p->y);
tmp->next = head;
return tmp;
}
else{ //memory allocation failed
printf("allocation failed (new head)\n");
exit(2);
return head;
}
You would want to walk the list, with code similar to:
for ( Item* current = &head;
current != NULL;
current = current->next ) {
do_stuff_with(current->p);
}
This stops when you reach the end of the list: that is, when you have processed the last node containing data, whose next pointer is NULL, and updated current to NULL.
On a side note, you want to tweak the definition of Item slightly, to:
typedef struct Item {
point *p;
struct Item *next;
} Item;
Some compilers, including GCC, will realize that Item.next has the same type, and stop giving you spurious warnings about anonymous structs and incomplete types.
it might also pay to decide whether you want to use Item and Point, or item and point. Inconsistent capitalization is confusing.

Inserting Node Linked List C

I am trying to create a linked list which stores name and age of a student.
I am having trouble with insertion.
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <stdlib.h>
typedef struct node{
char Name[50];
int studentAge;
struct node* next;
}MyNode;
this is how i defined my Struct which constains the requried data and a pointer 'next' which points to the next node.
Below is my insertion function
so in the first if condition i am saying if there isnt a head ie head = NULL then create memory space for the head using malloc.. after this i copy all the data into the head node and making sure that the next of head points to null.
In the second condition i am saying if there is a head ie Head ! = NULL
then traverse the list to the end using the current pointer and then copy all the data in.
void InsertStudent(char givenName[50], int age, MyNode* head){
if(head == NULL){
head = (MyNode*) malloc(sizeof(MyNode));
strcpy(head->Name,givenName);
head->studentAge = age;
head->next = NULL;
}
if(head != NULL){
MyNode* current = head;
while(current->next != NULL){
current = current->next;
}
current->next = (MyNode*) malloc(sizeof(MyNode));
strcpy(current->next->Name,givenName);
current->next->studentAge = age;
current->next->next = NULL;
}
}
Now i am not sure if there is a problem in my printing or inserting because it doesn't print my nodes when i try the code out
void PrintList(MyNode* head){
MyNode* current = head;
while(current != NULL){
printf("Name is %s Age is %d\n",current->Name,current->studentAge);
current = current->next;
}
}
this is my main function.. is there a problem with the MyNode* head = NULL; line of code is that allowed?
int main()
{
MyNode* head = NULL;
int r = 0;
while(r!=1)
{
printf("Data Structures - Linked List\n");
printf("Choose one Option:\n\n");
printf("1.Insert Student\n");
printf("2.Remove Student\n");
printf("3.Print all student\n");
printf("4.Exit\n");
int option=0;
char givenName[50];
int givenAge;
scanf("%d",&option);
switch(option){
case 1:
printf("Enter name of student: ");
scanf("%s",givenName);
printf("\nEnter Age of student: ");
scanf("%d",&givenAge);
InsertStudent(givenName,givenAge,head);
break;
case 2:
printf("Enter name of student: ");
scanf("%s",givenName);
printf("\nEnter Age of student: ");
scanf("%d",&givenAge);
RemoveStudent(givenName,givenAge);
break;
case 3:
PrintList(head);
break;
case 4:
r=1;
break;
default:
r=1;
printf("\nNot an option\n");
break;
}
}
}
You're not setting the initial value of the head pointer to the first node, and since that is never done, the list remains empty and you leak memory like a sieve leaks rain water.
As you have communicated you want to use pointer-to-pointer syntax, the result should look like this . (sans error checking, which you shoudl probably consider adding):
void InsertStudent(char givenName[50], int age, MyNode** head)
{
while (*head)
head = &(*head)->next;
*head = malloc(sizeof **head);
strcpy((*head)->Name, givenName);
(*head)->studentAge = age;
(*head)->next = NULL;
}
Invoked from your main program using the address of the head pointer (do NOT confused that with the address held in the head pointer which you're initially setting to NULL correctly; think of the latter a value held by a pointer, the former as a residence where the head pointer itself is in memory).
InsertStudent(givenName,givenAge, &head); // NOTE THIS
I leave the task of removal and list cleanup.
You are passing head by value; which means that the line in InsertStudent:
head = (MyNode*) malloc(sizeof(MyNode))
which does not update the variable ‘head’ in main.
What you want is to pass &head to InsertStudent, but then InsertStudent has to deal with a MyNode **. The other option is have InsertStudent return head, so that its invocation is:
head = InsertStudent(name, age, head);
It doesn’t matter much either way, some people prefer the latter because it looks more functional.
Inside of InsertStudent, you add the first element twice. This is almost certainly unwanted. By the time you get to the line:
if(head != NULL){
head is never NULL; if it were, you would have assigned it in the if statement above. You probably want this statement to be:
else {

Linked List in Hash Table (with struct)

I'm implementing a hash table with pointers to struct instances.
Struct:
typedef struct student
{
int matrikelnummer;
char *name;
struct student *next;
} student;
Array (with pointers on my struct):
student *hash_table[SIZE];
...
for (int i = 0; i < SIZE; i++)
hash_table[i] = NULL;
I'm creating a instance of my struct with proper memory management:
char *name = malloc(100);
student *temp = malloc(sizeof(student));
if (temp == NULL || name == NULL)
return;
printf("Neuer Student hinzufuegen:\n");
printf("Name: ");
scanf("%99s", name);
temp->name = malloc(strlen(name) + 1);
if (temp->name == NULL)
return;
strcpy(temp->name, name);
free(name);
name = NULL;
printf("Matrikelnumer: ");
scanf("%d", &temp->matrikelnummer);
temp->next = NULL;
Until here it is working properly, if I check my temp (instance of struct) while debugging the program it looks fine.
At the end of this function changing the pointer in hash_table[0] to my temp instance seems to work:
hash_table[0] = &temp;
/* hash_table[get_hash_key(temp->matrikelnummer)] = &temp; */
My program crashes after I try to print the members of my hash_table afterwards like following:
printf("matrikelnumer: %d\n", hash_table[0]->matrikelnummer);
Output: matrikelnummer: 9741328
(it looks like the address itself printed with %d)
and it crashes after trying to print the name with following code line:
printf("name: %s\n", hash_table[0]->name);
Do I access the variables wrong?
I tried already several ways to access the members, but its mostly crashing or doing something I'm not able to follow.
Any hints and help appreciated, also when it comes to coding style etc.
Bug is on line:
hash_table[0] = &temp;
temp is pointer already, so you are assigning struct student** to struct student* array element, which causes all remaining errors.
Change to:
hash_table[0] = temp;

Failing While loop when working with Linked lists

As part of an assignment, I am having a program read in the names and id of people from a file, and saving them in separate linked lists. I have a nested while loop to traverse the list until it reaches the end, and then assign the values at the end. Unfortunately the program keeps crashing while reading and it seems to revolve around the second while loop.
Here is the struct established before the main()
struct node
{
char name[50];
int id;
struct node *next;
}*start;
Here is the function itself:
void read()
{
int tempNum = 0, id, jack = 0;
char name[50];
struct node *temp, *right;
temp = start;
FILE *ifp = fopen("AssignmentOneInput.txt", "r");
while(fscanf(ifp," %s", &name) != EOF)
{
fscanf(ifp, " %[^,]s, %[^/n]d", &name, &id);
temp = (struct node *)malloc(sizeof(struct node));
strcpy(temp->name,name);
temp->id = id;
right = (struct node *)start;
printf("test number one\n");
while(right->next != NULL)
{
printf("test number two\n");
right = right->next;
}
printf("test number three\n");
right->next = temp;
right = temp;
right->next = NULL;
}
}
As for its implementation in the main function, it is the very first function called, so it looks a little like:
main()
{
read();
I guess thatstart is a global variable? Then it will be zero-initialized by the compiler and C runtime system. That means it will, as a pointer, be initialized to NULL. So when you use it uninitialized in your code it will be NULL and you have undefined behavior when you dereference the pointer. And undefined behavior is arguably the most common cause of crashes.

Resources