Linked List in Hash Table (with struct) - c

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;

Related

Why does the strcpy() function produce unwanted outputs in the case of this program?

I am trying to create a linked list in C and this post refers to the part where I try to assign a variable in a structure a string value that the user inputs. The program compiles perfectly yet if I use strcpy() instead of strdup() then I get unwanted output.
The program compiles fine and gives no warnings or errors. If strdup() is used then the program works as intended but I'd like to know why it doesn't work when strcpy() is used instead. When passing in strings for the names, when the list is printed it will occasionally print null and then terminate or it will instead print "Name:Name:Name:Name:Nam" or other such unpredictable errors. Any other comments or criticisms would be appreciated as well as I am just starting to learn the language, thanks.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct addressBook {
char *name;
int age;
char *phoneNumber;
struct addressBook *next;
};
static struct addressBook *head = NULL;
static struct addressBook *current;
static struct addressBook *createNew;
//function prototypes
void addNode(void);
struct addressBook * createNode(void);
void printAddressBook(void);
void printStats(void);
int main(void)
{
addNode();
addNode();
printAddressBook();
addNode();
addNode();
printAddressBook();
}
struct addressBook * createNode(void)
{
struct addressBook *newNode;
newNode = (struct addressBook *) malloc(sizeof(struct addressBook));
if (newNode == NULL)
{
puts("Memory error");
exit(1);
}
printf("\nEnter persons name: ");
char name[20];
scanf("%s", name);
strcpy(newNode -> name, name); //produces unpredictable results
//newNode -> name = strdup(name); Works fine with strdup
printf("Enter persons age: ");
scanf("%d", &newNode -> age);
printf("Enter persons phone number: ");
char phoneNumber[15];
scanf("%s", phoneNumber);
strcpy(newNode -> phoneNumber, phoneNumber); //produces unpredictable
results
//newNode -> phoneNumber = strdup(phoneNumber); Works fine with strdup
return(newNode);
}
void addNode(void)
{
createNew = createNode();
current = createNew;
current -> next = head;
head = current;
}
void printAddressBook(void)
{
struct addressBook *temp;
temp = head;
while(temp)
{
printf("Name: %s\nAge: %d\nPhoneNumber: %s\n\n\n",
temp -> name,
temp -> age,
temp -> phoneNumber);
temp = temp -> next;
}
}
When you define a pointer like char *name; it points to some random location as you haven't initialized it. It is illegal to write to the pointer and doing so will invoke Undefined Behavior.
strcpy basically writes the string to this random pointer location invoking UB.
strdup on the other hand, allocates the required memory dynamically for the string, copies the string to that location and then returns the start of the location. You can read/write to this memory location and hence, this is valid.

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.

Segmentation Fault when using Linked Lists and Char arrays

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()

Segmentation fault in program using linked list

Code:
#include<stdio.h>
#include<malloc.h>
struct details{
char *name;
int no;
struct details *info;
};
//ADDING THE LINKED LIST
void add(struct details **info,int no,char * name){
struct details *temp=malloc(sizeof(struct details));
temp = *info;
if(temp == NULL){
temp = malloc(sizeof(struct details));
}
else{
if(temp->info == NULL){
temp->info = malloc(sizeof(struct details));
temp = temp->info;
}
}
temp->no = no;
temp->name = name;
}
//DISPLAYING THE LINKED LIST
void display(struct details *info){
while(info!=NULL){
printf("\nThe List is:\n","\n no: \tname:\n","%d","%s and link:%d",info->no,info->name,info->info);
info = info->info;
}
}
//MAIN PROGRAM
int main()
{
struct details* ptr;
char *name,ch;
int no;
int select_option;
ptr = NULL;
printf("\n ***MAIN MENU*** \n1.Add Element \n2.Delete Element \n3.Search Element \n4.Linked List Concatenation \n5.Invert Linked List \n6.Diplay Elements \n Please Enter your choice:(eg:1,2,3,4,5,6)\n");
scanf("%d",&select_option);
do{
switch(select_option){
case 1:
printf("Enter no to add:");
scanf("%d",&no);
printf("Enter name to add:");
scanf("%s",name);
add(&ptr,no,name);
break;
case 6:
display(ptr);
break;
default:
printf("INVALID CHOICE!");
break;
}
printf("Do u wish to continue?(y/n):");
scanf("%c",&ch);
}while(ch == 'y' || ch == 'y');
return 0;
}
I'm trying to write a simple program using a linked list to add and display data. But its throwing me a segmentation fault. I hope that I have initialized all the pointers with the memory. All help appreciated.
This:
temp->name = name;
does not copy name to temp->name but assigns temp->name to the same address as name, which is local to the function. You need to malloc() and strcpy():
temp->name = malloc(strlen(name) + 1);
strcpy(temp->name, name);
Remember to free(temp->name); when no longer required.
Additionally (as pointed out by Luchian), when reading from stdin:
char *name;
...
scanf("%s",name);
name has no memory allocated to. Declare it as an array but you need to protect against writing beyond the end of it:
char name[128];
...
scanf("%127s",name);
You haven't:
char *name;
///....
scanf("%s",name);
You never allocated memory for name.
You could do char name[50]; or whatever, but beware of overflows. Guard against them.
Both hmjd and Luchian Grigore answers are a prior problems, but also:
You don't initialize temp->info at any point after a malloc, so it is never NULL, but yet temp->info is an invalid address.
Either initialize it explicitly or use calloc, which initializes the allocated buffer, instead of malloc.
You forgot to allocate name
char *name

C, Printing more than one integer from a linked list

I'm very new to C, so I'm not totally sure what's the matter. I can't figure out how to print more than a single integer value in a function.
add function:
void add(char *name,int id,int copies)
{
/* Pointer to next item */
struct list *newAlbum;
newAlbum = malloc(sizeof(struct list));
strcpy((*newAlbum).name, name); // Set album name
newAlbum->id = id;
newAlbum->copies = copies;
newAlbum->pNext = pFirst;
pFirst = newAlbum;
}
show function:
void show()
{
system("clear");
struct list *current_node;
current_node = pFirst;
while(current_node != NULL)
{
printf("Album #%d \n",current_node->id);
printf("Album Name: %s \n",current_node->name);
printf("Album Copies:%d \n",current_node->copies);
printf("\n");
current_node=current_node->pNext;
}
}
My program prints out the current_node->id as if it were current_node->copies, and current_node->copies is printed out as 134516043, which is obviously, wrong.
I think I must be passing something wrong to the function or something, but I can't figure it out. Any tips?
I call the function add like this:
add(name,id,copies);
The list is as so:
/* THE LIST */
struct list{
char name[52];
int id;
int copies;
int sold;
struct list* pNext;
};
struct list *pFirst = NULL;
I call the function with user input with this piece of code:
printf("Enter the name of the new album. \n");
scanf("%s",&name);
printf("Enter the album id. \n");
scanf("%d",&id);
printf("Enter number of copies. \n");
scanf("%d," &copies);
// Pass data to add()
add(name,id,copies);
Your code that you've shown is OK, as long as you don't pass an album name to add() which is longer than 51 characters. If you do, you'll get very weird output, and possibly a crash.
To guard against this, you should use a length-limited copy - for example:
void add(char *name,int id,int copies)
{
/* Pointer to next item */
struct list *newAlbum;
newAlbum = malloc(sizeof *newAlbum);
if (newAlbum) {
snprintf(newAlbum->name, sizeof newAlbum->name, "%s", name); // Set album name
newAlbum->id = id;
newAlbum->copies = copies;
newAlbum->pNext = pFirst;
pFirst = newAlbum;
}
}
(note that sizeof *newAlbum is a little better than sizeof(struct list), since the former is "obviously correct" when reading the line - it will still be corret if the type of newAlbum is ever changed).
The only thing I can see wrong here is that you don't check the length of name. You should use:
strncpy(newAlbum->name, 52, name);
This will prevent overrunning the name buffer.

Resources