I have started learning about Linked Lists, which through videos and multiple examples I have pretty much understood what a Linked List is and how it can be represented in a real life analogy. But when it comes to coding it I get lost I suppose through all the pointers I kind of get confused, it took a bit for me to get a stronger grasp on arrays so I assume it will be the same with Linked lists. So here is my code
/*
• The program will use dynamic memory to create a singly linked list(NO ARRAYS PERMITTED)
• The program will store unlimited number of student records(limited only by RAM).
• A student record will consist of Student Name, Age, and GPA…you may need to add additional fields to make this work(Next).
• The program will have a way for the user to add records(in order by name).You can assume that no two students have the same name.The list will always be in order.
• The program will have a way for the user to display ALL records.
• The program needs a way to quit.
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#pragma warning(disable: 4996)// disables warning
typedef struct{
char name[40];
int age;
float gpa;
struct NODE* next;
}NODE;
void addStudent();
int main(void){
NODE* head = NULL;
int userinput;
printf(" **********************************\n");
printf(" * MENU *\n");
printf(" * 1. Add Student *\n");
printf(" * 2. Display all student records*\n");
printf(" * 3. Quit *\n");
printf(" **********************************\n");
scanf_s("%d%*[^\n]", &userinput); '\n' == getchar();
switch (userinput)
{
case 1: do
{
addStudent(head);
printf("Add another record? 1(y) 2(n)\n");
scanf_s("%d%*[^\n]", &userinput); '\n' == getchar();
} while (userinput == 1);
break;
}
}
void addStudent(NODE* head){
head = malloc(sizeof(NODE));
if (head == NULL)
{
return;
}
NODE * current = head;
printf("Please Enter student name:\n");
fgets(current->name, 40, stdin);
printf("Enter student age:\n");
scanf("%d%*[^\n]", ¤t->age); '\n' == getchar();
printf("Enter student gpa:\n");
scanf("%f%*[^\n]", ¤t->gpa); '\n' == getchar();
current->next;
current->next = NULL;
while (current != NULL){
current = head;
printf("%s\n", current->name);
printf("%d\n", current->age);
printf("%0.2f\n", current->gpa);
current = current->next;
}
}
When I compile, it will always print the head I assume its because of current = head within the while loop, I understand why its printing the head over but I am lost on how to arrange this code So that I can create a new node when I add and print all the nodes, through the loop.
The problem is that you never create new nodes to add to the list but always just updating the head. In order to make it work you should:
Allocate a new NODE,
NODE *newNode = malloc(sizeof(NODE));
Load the data into this node
printf("Please Enter student name:\n");
fgets(&newNode->name, 40, stdin);
printf("Enter student age:\n");
scanf("%d%*[^\n]", &newNode->age); '\n' == getchar();
printf("Enter student gpa:\n");
scanf("%f%*[^\n]", &newNode->gpa); '\n' == getchar();
Update the node to point to the node currently pointed by the HEAD
newNode->next = head
Update the head to point to the new Node
head = newNode;
Related
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!
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 {
I have made a simple list like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
struct node{
int am;
struct node *next;
};
typedef struct node node;
int main(){
int n;
node *head=(node *)malloc(sizeof(node));
node *cur=head;
printf("Give me a number:\n");
scanf(" %d",head->am);
cur=head;
while(1){
printf("Give me a number\n");
scanf(" %d",&n);
if(n==0)
break;
cur->am=n;
cur->next=(node *)malloc(sizeof(node));
cur=cur->next;
cur->next=null;
}
travel(head);
printf("Total nodes available :%d\n",count(head));
system("pause");
return 0;
}
Now travel is supposed to go through each node in the list and display the integer saved in each node.
void travel(node *h){
if(h==NULL)
return;
printf("Received data from node: \t %d\n",h->am);
travel(h->next);
}
Now the problem is that when travel is called it wont print the integer from the first node.It will also print another "Received data from node:" followed by a strange number.
For example
If i give 1,2,3,4 as inputs these are the results
Received data from node: 2
Received data from node: 3
Received data from node: 4
Received data from node: 4026432
Any ideas?
Now the problem is that when travel is called it wont print the
integer from the first node
This can be precisely known from this part of the main() function
printf("Give me a number:\n");
scanf(" %d",head->am); //this is wrong use of scanf("%d",&head->am);
cur=head;
while(1){
printf("Give me a number\n");
scanf(" %d",&n);
if(n==0)
break;
cur->am=n;
as I've mentioned you're scanning wrongly but that doesn't matter because later in the code in while loop you replace it this way...
you scan number and store it at head->am
then you assign head to cur so head->am and cur->am are both the same now... so in while loop when you first assign n to cur->am, it gets assigned to head->am. so this explains why you never get to print first node.
Solution:
to overcome it ... in while loop, before assigning cur->am=n try doing:
cur->next=(node *)malloc(sizeof(node));
cur=cur->next;
//then... assign
curr->am=n;
this way you'll not lose first node.
suggestion:
As someone has already said it's much easier to traverse/ travel the list using loops (never mind... if you want to do it recursively)
here's how you do it with the loops:
void travel(node *h)
{
if(h==NULL)
return; //list is empty,consider printing "list empty" :)
while(h!=NULL)
{
printf("Received data from node: \t %d\n",h->am);
h=h->next;
}
}
To put all together your code without changing the travel() function as suggested would be:
#include <stdio.h>
#include <stdlib.h>
struct node
{
int am;
struct node *next;
};
typedef struct node node;
void travel(node *h);
int main() //I have a habit of returning values from main() :)
{
int n;
node *head=(node *)malloc(sizeof(node));
node *cur=head;
printf("Give me a number:\n");
scanf(" %d",&head->am);
cur=head;
while(1)
{
printf("Give me a number\n");
scanf(" %d",&n);
if(n==0)
break;
cur->next=(node *)malloc(sizeof(node));
cur=cur->next;
cur->am=n; //NOTE:here's the change!
cur->next=NULL;
}
travel(head);
return 0; //just to signify successful compilation
}
void travel(node *h)
{
if(h==NULL)
return;
printf("Received data from node: \t %d\n",h->am);
travel(h->next);
}
Sample Input : 5 6 3 1 0
Sample Output :
Give me a number:
5
Give me a number
6
Give me a number
3
Give me a number
1
Give me a number
0
Received data from node: 5
Received data from node: 6
Received data from node: 3
Received data from node: 1
There are (at least) those issues:
The line scanf(" %d",head->am) is wrong since scanf() expects an address of the memory location of the expected value meaning &head->am.
Your loop scans a number and puts it in the current node and only after it creates a new node. Therefore, the first number you enter will be overridden (after fixing the first issue) and the last node created will contain random data because the loop will terminate after entering 0 but before putting anything in the last node.
I propose like this:
int main(void){
int n;
node anchor = {0, NULL};//dummy head
node *head, *cur = &anchor;
while(1){
printf("Give me a number\n");
scanf("%d", &n);
if(n==0)
break;
cur->next = malloc(sizeof(node));
cur = cur->next;
cur->am = n;
cur->next = NULL;
}
head = anchor.next;
travel(head);
printf("Total nodes available :%d\n", count(head));
return 0;
}
You are missing & at the first scanf:
scanf(" %d", &head->am);
But it could be made to do all the scanf inside the while:
int main(){
node *head=0;
node *cur=0;
node *prev=0;
while(1){
prev = cur;
cur=(node *)malloc(sizeof(node));
cur->next=NULL;
printf("Give me a number\n");
scanf("%d",&cur->am);
if(cur->am==0)
break;
if(head == NULL) head = cur;
if(prev != NULL) prev->next = cur;
}
travel(head);
printf("Total nodes available :%d\n",count(head));
return 0;
}
I hope I didnt make any mistake as I wrote it in this SO editor..
and as someone said, you should free the linked list .. but thats out of scope here..
HTH
I was trying to do an example about linked list. First, I added the values to the variables and there was no problem. But when I tried to get values from user, the program crashed when entering midterm 2 grade. I tried other input functions but the result is same. Where is the problem?
#include <stdio.h>
struct student
{
char *name;
int m1,m2,final;
struct student* next;
};
main()
{
addStudent();
system("PAUSE");
}
addStudent()
{
struct student *node = NULL;
struct student *firstnode;
firstnode = (struct student *)malloc(sizeof(struct student));
node = firstnode;
printf("press 0 to exit \n");
while(1)
{
printf("Student name: ");
scanf("%s", node->name)
if(node->name == "0") break;
printf("Midterm 1: ");
scanf("%d", node->m1);
printf("Midterm 2: ");
scanf("%d", node->m2);
printf("Final: ");
scanf("%d", node->final);
node->next = (struct student *)malloc(sizeof(struct student));
node = node->next;
}
node->next = NULL;
node = firstnode;
while(node->next);
while(node->next != NULL)
{
printf("%s - ",node->name);
printf("%d ", node->m1);
printf("%d ", node->m2);
printf("%d ", node->final);
node = node->next;
}
system("PAUSE");
return 0;
}
Fix 1
Remove the line
while(node->next);
Reason: It will put you on an infinite loop in most cases and it is unnecessary.
Fix 2
Replace the loop
while(node->next != NULL) {
}
with
if (node->next != NULL) {
while (node->next->next != NULL) {
}
}
Reason: You are allocating one additional struct each time and keeping it empty for reading next time. So the Linked List will end before the next becomes NULL.
Fix 3
Replace following in struct
char *name;
with
char name[80];
Reason: Memory not being allocated.
Fix 4
Replace at all occurrences of scanf (except for name)
scanf("%d", node->m1);
with
scanf("%d", &node->m1);
Reason: scanf needs memory location of data to be read.
Good luck
Your code has multiple errors.
To start with, the first scanf("%s", node->name) is missing its terminating semicolon.
Next, your function signatures are sloppy. main() should be int main(void). addStudent() should be int addStudent(void). (Or, get rid of its return 0 and let it return void.) Since you don't pre-declare addStudent(), you should define it before main() so that main() can know about it.
The crash, though, is because you haven't allocated memory for node->name. You've allocated memory for a node, but that doesn't give you space to put the name.
I already posted something similar before but this is another part of a problem that I'm having and I would appreciate your ideas and if you can help me fix my mistake.
As stated on my title i'm building a Doubly Linked List and I would like to know if my function insert_after works or not. When I run the full code I can't insert after the value that I chose which is why I'm posting this. Please let me know if I'm not clear or if this question is wrongly asked. I'm new in C and just need your help understanding.
This is my struct:
struct node
{
char data[100];
struct node *previous; // Points to the previous node
struct node *next; // Points out to the next node
}*head, *last;
This is my function to insert after a the chosen word:
char insert_after(char words[99], char loc[99])
{
struct node *temp, *var, *temp1;
var=(struct node *)malloc(sizeof(struct node));
strncpy(var->data, words,100);
if (head==NULL)
{
head=var;
head->previous=NULL;
head->next=NULL;
}
else
{
temp=head;
while ((temp!=NULL) && (temp->data!=loc))
{
temp=temp->next;
}
if (temp==NULL)
{
printf("\n %s not presented at list\n", loc);
}
else
{
temp1=temp->next;
temp->next=var;
var->previous=temp;
var->next=temp1;
temp1->previous=var;
}
}
last=head;
while (last->next!=NULL)
{
last=last->next;
}
return 0;// take it out after
}
And this is my main: --> Case 3 is my problem
int main()
{
char loc[99];
char words[99];
int i, dat;
head=NULL;
printf("Select the choice of operation on link list");
printf("\n1.) Insert At Begning\n2.) Insert At End\n3.) Insert At Middle");
printf("\n4.) Delete From End\n5.) Reverse The Link List\n6.) Display List\n7.)Exit");
while(1)
{
printf("\n\n Enter the choice of operation you want to do ");
scanf("%d",&i);
switch(i)
{
case 1:
{
printf("Enter a word you want to insert in the 1st node ");
scanf(" %s",words);
insert_beginning(words);
display();
break;
}
case 2:
{
printf("Enter a word you want to insert in the last node ");
scanf(" %s",words);
insert_end(words);
display();
break;
}
case 3:
{
printf("After which data you want to insert your new data ");
scanf(" %s",words);
printf("Enter the data you want to insert in list ");
scanf(" %s",loc);
insert_after(words, loc);
display();
break;
}
I didn't put the full code because it's pretty long which is why i posted the important stuff.
Please let me know if my question is not clear.
Thanks
This is a problem:
while ((temp!=NULL) && (temp->data!=loc))
temp->data != loc is not comparing strings, it just compares pointer addresses.
You could use strcmp or a similar string comparision function. strcmp returns non-zero if
the two parameters differ.
while ((temp!=NULL) && (strcmp(temp->data, words))
Note that it is words that is to compared to the values in the list as words is the value that loc is to be inserted after.
If you use char arrays as the parameters to insert_after function care will be needed to ensure that the entire length of the array is initialised correctly.
Note that a check on the following node is necessary in case there is only one node in the list (the following node will be NULL in this case).
char insert_after(char *words, char *loc)
{
struct node *temp, *var;
var=(struct node *)malloc(sizeof(struct node));
strcpy(var->data, loc);
if (head==NULL)
{
head=var;
head->previous=NULL;
head->next=NULL;
}
else
{
temp=head;
while ((temp!=NULL) && (strcmp(temp->data, words)))
{
temp=temp->next;
}
if (temp==NULL)
{
printf("\n %s not presented at list\n", words);
}
else
{
struct node * followingNode = temp->next;
temp->next=var;
var->previous=temp;
var->next= followingNode;
if (followingNode)
followingNode->previous = var;
}
}
}
Issues
char words[99] has 99 elements but you're allowing up to 100 here, strncpy(var->data, words,100);. That may cause a problem if words is not '\0' terminated. You could unintentially write word[99] to var->data which shouldn't be allowed. Change the statement to this:
strncpy(var->data, words, 99);
var->data[99] = '\0'; // In case words wasn't a string
You cannot compare strings like this, temp->data!=loc. You're actually comparing addresses. Change this line to the following:
while((temp != NULL) && (strcmp(temp->data, loc) != 0));
var->next=temp1 is incorrect. We're at the end of the list so this line should be rewritten as follows:
var->next = NULL;
You must use memcmp or, better yet, strcmp for string comparison instead of !=.