Getting input for linked list fgets & scanf C - c

I created this linked list but I am having trouble getting the char array and the ints at the same time. Any suggestions? I have been up and down in forums and google but I can't seem to get it to agree with anything.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node {
int id;
char name[40];
struct node *next;
struct node *prev;
} info;
int insert (int num, char *Name);
void print ();
struct node *root; // Declare root a pointer to the first node
int main () {
int n, Id, i;
char nAme[40];
char *name_ptr;
root = NULL; // List is empty
printf ("How many list entries do you want to make?\n");
scanf (" %d ", &n);
n = 2;
for (i = 0; i < n; i++) {
printf ("Enter name: ");
fgets (nAme, 40, stdin);
printf ("Enter id number: ");
scanf ("%d", &Id);
name_ptr = &nAme[0];
insert (Id, name_ptr);
print ();
}
}
int insert (int num, char *Name)
{
// Get memory
struct node *temp = (struct node *) malloc (sizeof (struct node));
if (temp == NULL) {
printf ("Some malloc problem.\n");
return 1;
}
temp->id = num;
strcpy (temp->name, Name);
temp->next = root;
root = temp;
}
void print ()
{
struct node *temp = root;
while (temp != NULL) {
printf ("%d\n%s\n", temp->id, temp->name);
temp = temp->next;
}
printf ("\n");
}
Sorry I'm a bit new to this site, so the formatting might say javascript, but its C as you can probably tell.

There are a number of problems conspiring against you. The first, important, but not a show stopper, is fgets will read up to and including the newline. Which means all of your nAme (presuming you meant name) entries have an embedded newline at the end. This will cause all kinds of havok when you attempt to search for or compare specific names in your list.
A huge issue is you have no validation on whether you even receive input to add to your list from the user. Always, always validate user input. That means checking at minimum that you actually have input to store. e.g.
printf ("Number of list entries to make?: ");
if (scanf (" %d%*c", &n) != 1) {
fprintf (stderr, "error: invalid no. of entries.\n");
return 1;
}
for (i = 0; i < n; i++) {
printf ("Enter name: ");
if (!fgets (name, MAXC, stdin)) {
fprintf (stderr, "error: invalid name.\n");
return 1;
}
rmcrlf (name); /* strip trailing newline from name */
printf ("Enter id number: ");
if (scanf ("%d%*c", &id) != 1) {
fprintf (stderr, "error: invalid ID.\n");
return 1;
}
insert (id, name);
}
(note: the rmcrlf (remove carriage-return newline) function trims the trailing new line or erroneous carriage return from the name value)
The more substantive issues being apparent confusion on what type of list you are creating (single/double linked, traditional head/tail, circular, what?) The difference being that a traditional head/tail will use a NULL value to mark the end/beginning of the list, while a circular list points the last node to the first allowing iteration from any point around the list.
You appear to want a doubly-linked list with your prev and next pointers, but you make absolutely no attempt to handle the prev pointer in any way. It is unclear whether you want a circular or head/tail NULL list. Regardless which you choose, you must account for setting the values for your prev and next pointer with each insert you do. It makes a difference whether you are setting the 1st (and 2nd on a circular list) compared to the remaining insertions. The following is an example of the insert function that will correctly handle additions to a circular list. A head/tail NULL list does not need specific handling of the second node.
struct node *insert (int num, char *name)
{
struct node *temp = malloc (sizeof *temp); /* allocate node */
if (!temp) {
fprintf (stderr, "error: virtual memory exhausted.\n");
exit (EXIT_FAILURE);
}
temp->id = num;
strcpy (temp->name, name);
if (!root) { /* empty list - insert first node */
temp->next = temp->prev = temp;
root = temp;
}
else if (root == root->next) { /* insert 2nd node */
temp->next = root;
root->prev = temp;
root->next = temp;
temp->prev = root;
}
else { /* insert all remaining nodes at end */
root->prev->next = temp;
temp->prev = root->prev;
temp->next = root;
root->prev = temp;
}
return temp;
}
(note: the function type being struct node *. It is of little use to return an int value here. You can judge success/failure by returning NULL in the event of a failure and you have the inserted node available for any post-insert processing required. Also, do NOT cast the return of malloc and you need only take the sizeof the object pointed to by the pointer being allocated)
Don't use magic numbers in your code. They make the code harder to maintain. If you need a constant to set the maximum characters in name, then define one with #define MAXC 40 or declare a global enum to define the constant (e.g. enum { MAXC = 40 };).
Putting those pieces together and fixing a few more nits, you could code your doubly-linked circular list something like the following example. You can simplify the code slightly by simply using a traditional head/tail NULL list instead.
Look the code over closely and understand the changes made (you need no name_ptr at all, and you don't set n=2; after taking input for n with scanf). Also note how the '\n' character scanf leaves in the input buffer (e.g. stdin) is handled. If you fail to account for the '\n', you will find scanf skipping over your input due to it taking the '\n' left in the input buffer as your input.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXC 40
struct node {
int id;
char name[MAXC];
struct node *next;
struct node *prev;
} info;
struct node *insert (int num, char *name);
void print (void);
void delete_list (void);
void rmcrlf (char *s);
struct node *root; /* Declare root a pointer to the first node */
int main (void) {
int i, id, n;
char name[MAXC];
root = NULL; /* List is empty */
printf ("Number of list entries to make?: ");
if (scanf (" %d%*c", &n) != 1) {
fprintf (stderr, "error: invalid no. of entries.\n");
return 1;
}
for (i = 0; i < n; i++) {
printf ("Enter name: ");
if (!fgets (name, MAXC, stdin)) {
fprintf (stderr, "error: invalid name.\n");
return 1;
}
rmcrlf (name);
printf ("Enter id number: ");
if (scanf ("%d%*c", &id) != 1) {
fprintf (stderr, "error: invalid ID.\n");
return 1;
}
insert (id, name);
}
print();
delete_list();
return 0;
}
struct node *insert (int num, char *name)
{
struct node *temp = malloc (sizeof *temp); /* allocate node */
if (!temp) {
fprintf (stderr, "error: virtual memory exhausted.\n");
exit (EXIT_FAILURE);
}
temp->id = num;
strcpy (temp->name, name);
if (!root) { /* empty list - insert first node */
temp->next = temp->prev = temp;
root = temp;
}
else if (root == root->next) { /* insert 2nd node */
temp->next = root;
root->prev = temp;
root->next = temp;
temp->prev = root;
}
else { /* insert all remaining nodes at end */
root->prev->next = temp;
temp->prev = root->prev;
temp->next = root;
root->prev = temp;
}
return temp;
}
void print (void)
{
struct node *temp = root;
printf ("\n Id Name\n ---- ---------------------\n");
while (temp->next != root) {
printf (" %4d %s\n", temp->id, temp->name);
temp = temp->next;
}
printf (" %4d %s\n", temp->id, temp->name);
printf ("\n");
}
/* free memory for all nodes in list */
void delete_list (void)
{
struct node *temp = root->next;
while (temp != root) {
struct node *victim = temp;
temp = temp->next;
free (victim);
}
if (temp) free (temp);
}
/** stip trailing newlines by overwriting with null-terminating char.
* str is modified in place.
*/
void rmcrlf (char *s)
{
if (!s || !*s) return;
for (; *s && *s != '\n'; s++) {}
*s = 0;
}
Example Use/Output
$ ./bin/ll_double_cir
Number of list entries to make?: 3
Enter name: cats
Enter id number: 3
Enter name: dogs
Enter id number: 17
Enter name: mice
Enter id number: 123
Id Name
---- ---------------------
3 cats
17 dogs
123 mice
Memory Use/Error Check
In any code your write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to insure you haven't written beyond/outside your allocated block of memory, attempted to read or base a jump on an unintitialized value and finally to confirm that you have freed all the memory you have allocated. For Linux valgrind is the normal choice. Usage is simple, just run your code through it and check the results:
$ valgrind ./bin/ll_double_cir
==14595== Memcheck, a memory error detector
==14595== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==14595== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==14595== Command: ./bin/ll_double_cir
==14595==
Number of list entries to make?: 3
Enter name: cats
Enter id number: 3
Enter name: dogs
Enter id number: 17
Enter name: mice
Enter id number: 123
Id Name
---- ---------------------
3 cats
17 dogs
123 mice
==14595==
==14595== HEAP SUMMARY:
==14595== in use at exit: 0 bytes in 0 blocks
==14595== total heap usage: 3 allocs, 3 frees, 192 bytes allocated
==14595==
==14595== All heap blocks were freed -- no leaks are possible
==14595==
==14595== For counts of detected and suppressed errors, rerun with: -v
==14595== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1)
Always confirm All heap blocks were freed -- no leaks are possible and equally important ERROR SUMMARY: 0 errors from 0 contexts.
Look over the changes and if you have any questions, just ask.

What is is not doing?
Lookign at the code:
root should be initialized to NULL.
insert could be called as inert(Id, nName); instread of insert(Id, name_ptr);
in insert, you should initalize ->prev = NULL;

Related

Displaying polynomials with linked list in C

I am trying to write a code creating and displaying polynomials. My first question is: "Did I use linked list correctly?". Second is: "Why can't I display poynomials?" I want them displayed like: If there are 2 monomials, poynomial should be displayed as; -->(1.0 X 0) -->(1.0 X 3)--E First one is coefficient second one is the exponent.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//this will be the structure named node
struct node
{
int exp; //this line represents the exponent/power b for a*x^b
int coeff; //this line represents the coefficient a for a*x^b
struct node *next; //this line represents the pointer which will point to the next node
};
struct node *create_new_nodes(struct node *m);
struct node *insert(struct node *ptr, struct node *k);
void display(char const *tag, struct node *ptr);
struct node *create_new_nodes(struct node *m)
{
int i;
int n;
printf("Enter the number of nodes: ");
scanf("%d", &n);
for (i = 0; i < n; i++)
{
struct node *ptr = malloc(sizeof(struct node));
printf("Enter the coefficient (a for a*x^b): ");
scanf("%d", &ptr->coeff);
printf("Enter the exponent/power (b for a*x^b): ");
scanf("%d", &ptr->exp);
ptr->next = NULL;
}
return m;
}
void display(char const *tag, struct node *ptr)
{
struct node *temp;
temp = ptr;
printf("%s: ", tag);
while (temp != NULL)
{
printf("-->(%d X %d)--E", temp->coeff, temp->exp);
temp = temp->next;
}
putchar('\n');
}
int main(void)
{
struct node *p1 = NULL, *p2 = NULL;
p1 = create_new_nodes(p1);
p2 = create_new_nodes(p2);
display("p1", p1);
display("p2", p2);
return 0;
}
My output for this code:
Enter the number of nodes: 2
Enter the coefficient (a for a*x^b): 1
Enter the exponent/power (b for a*x^b): 2
Enter the coefficient (a for a*x^b): 2
Enter the exponent/power (b for a*x^b): 3
Enter the number of nodes: 2
Enter the coefficient (a for a*x^b): 3
Enter the exponent/power (b for a*x^b): 4
Enter the coefficient (a for a*x^b): 6
Enter the exponent/power (b for a*x^b): 5
p1:
p2:
As you can see p1 and p2 are not displayed.
I have to mention that I took help from internet while writing some parts of this code. So, there are parts that I didn't understand. If possible, I would like to be clarified for those too.
void display(char const *tag, struct node *ptr)
{
struct node *temp;
const char *pad;
temp = ptr;
printf("%s: ", tag);
while (temp != NULL)
{
printf("-->(%d X %d)--E", temp->coeff, temp->exp);
temp = temp->next;
pad = " + ";
}
putchar('\n');
}
In this part of code, I didn't get why I use temp and tag function.
Let's get you sorted out. Rather than a full general linked-list implementation, you simply need the create, display, and delete functions. Since your lists are just links of structs with exp and coeff, you can simply build a new list each time you call your create function. You do NOT need to provide a parameter to your create function, just declare your list pointer local to the function and then return a pointer to the first node in the allocated list when done.
As noted in the comment, you are headed for a lot of grief unless you check the return for every input function used (and not mentioned, but equally important, check the return of EVERY allocation)
You were not terribly far off where you were headed with your create function, you just never linked the nodes together in your list. You do want to initialize the next pointer NULL following allocation, but you also have to set any existing end node in your list next pointer to point to the new node. That is how you create the "link" in the "linked-list".
Let's take your create function, (I've renamed it create_poly_list()) and essentially you can declare both head and tail list pointers local to the function (the tail pointer is temporary used to build the list) and then return head when done for assignment back in the caller (main() here). So all you really needed would be to declare your list pointers, and then add each node in-order, e.g.
struct node *head = NULL, *tail = NULL; /* temporary list pointers */
...
if (head == NULL) /* add first node */
head = tail = ptr;
else {
tail->next = ptr; /* set last node ->next to new node */
tail = ptr; /* update tail to new node */
}
...
return head; /* return pointer to start of list */
Then in main() you would simply call create_poly_list() for each polynomial, e.g.
p1 = create_poly_list();
p2 = create_poly_list();
Now let's tidy it up so you validate each input and allocation, returning NULL on either input or allocation failure (and remembering to free() all memory if memory was allocated prior to the failure to prevent a memory leak), e.g.
struct node *create_poly_list (void) /* no parameter required */
{
int i, n;
struct node *head = NULL, *tail = NULL; /* temporary list pointers */
fputs ("\nEnter the number of nodes: ", stdout);
if (scanf("%d", &n) != 1)
return NULL;
for (i = 0; i < n; i++)
{
struct node *ptr = malloc (sizeof *ptr);
if (!ptr) { /* validate EVERY allocation */
while (head) { /* if nodes in list */
struct node *victim = head; /* free all nodes (or leak) */
head = head->next;
free (victim);
}
return NULL; /* now return NULL on error */
}
ptr->next = NULL; /* initialize next ptr NULL */
fputs ("\nEnter the coefficient (a for a*x^b) : ", stdout);
if (scanf ("%d", &ptr->coeff) != 1) {
fputs ("error: invalid integer input.\n", stderr);
/* you would likewise need to free prior nodes here */
return NULL;
}
fputs ("Enter the exponent/power (b for a*x^b): ", stdout);
if (scanf("%d", &ptr->exp) != 1) {
fputs ("error: invalid integer input.\n", stderr);
/* you would likewise need to free prior nodes here */
return NULL;
}
if (head == NULL) /* add first node */
head = tail = ptr;
else {
tail->next = ptr; /* set last node ->next to new node */
tail = ptr; /* update tail to new node */
}
}
return head; /* return pointer to start of list */
}
Your display() function was good, but you should check if ptr is NULL (e.g. list empty) to inform the user of the list state in case an attempt is made to display an empty list, e.g.
void display (char const *tag, struct node *ptr)
{
if (!ptr) { /* validate list not NULL */
puts ("(list-empty)");
return;
}
struct node *temp = ptr;
printf("%s: ", tag);
while (temp) {
printf("-->(%d X %d)--E", temp->coeff, temp->exp);
temp = temp->next;
}
putchar('\n');
}
Here you need to free the memory of each list when you are done with it. (yes, the memory will be freed on program exit, but presumably you won't always be writing simple programs that create all lists in main()). Build good memory management habits early. A simple delete list function is all you need, e.g.
void del_list (struct node *list)
{
while (list) {
struct node *victim = list;
list = list->next;
free (victim);
}
}
Putting it altogether, you would have:
#include <stdio.h>
#include <stdlib.h>
struct node {
int exp;
int coeff;
struct node *next;
};
struct node *create_poly_list (void) /* no parameter required */
{
int i, n;
struct node *head = NULL, *tail = NULL; /* temporary list pointers */
fputs ("\nEnter the number of nodes: ", stdout);
if (scanf("%d", &n) != 1)
return NULL;
for (i = 0; i < n; i++)
{
struct node *ptr = malloc (sizeof *ptr);
if (!ptr) { /* validate EVERY allocation */
while (head) { /* if nodes in list */
struct node *victim = head; /* free all nodes (or leak) */
head = head->next;
free (victim);
}
return NULL; /* now return NULL on error */
}
ptr->next = NULL; /* initialize next ptr NULL */
fputs ("\nEnter the coefficient (a for a*x^b) : ", stdout);
if (scanf ("%d", &ptr->coeff) != 1) {
fputs ("error: invalid integer input.\n", stderr);
/* you would likewise need to free prior nodes here */
return NULL;
}
fputs ("Enter the exponent/power (b for a*x^b): ", stdout);
if (scanf("%d", &ptr->exp) != 1) {
fputs ("error: invalid integer input.\n", stderr);
/* you would likewise need to free prior nodes here */
return NULL;
}
if (head == NULL) /* add first node */
head = tail = ptr;
else {
tail->next = ptr; /* set last node ->next to new node */
tail = ptr; /* update tail to new node */
}
}
return head; /* return pointer to start of list */
}
void display (char const *tag, struct node *ptr)
{
if (!ptr) { /* validate list not NULL */
puts ("(list-empty)");
return;
}
struct node *temp = ptr;
printf("%s: ", tag);
while (temp) {
printf("-->(%d X %d)--E", temp->coeff, temp->exp);
temp = temp->next;
}
putchar('\n');
}
void del_list (struct node *list)
{
while (list) {
struct node *victim = list;
list = list->next;
free (victim);
}
}
int main(void)
{
struct node *p1 = NULL, *p2 = NULL;
p1 = create_poly_list();
p2 = create_poly_list();
putchar ('\n');
display("p1", p1);
display("p2", p2);
del_list (p1);
del_list (p2);
return 0;
}
(note: why you have included string.h is a bit bewildering...)
Example Use/Output
$ ./bin/poly_list
Enter the number of nodes: 2
Enter the coefficient (a for a*x^b) : 2
Enter the exponent/power (b for a*x^b): 6
Enter the coefficient (a for a*x^b) : 3
Enter the exponent/power (b for a*x^b): 7
Enter the number of nodes: 3
Enter the coefficient (a for a*x^b) : 1
Enter the exponent/power (b for a*x^b): 3
Enter the coefficient (a for a*x^b) : 3
Enter the exponent/power (b for a*x^b): 5
Enter the coefficient (a for a*x^b) : 5
Enter the exponent/power (b for a*x^b): 7
p1: -->(2 X 6)--E-->(3 X 7)--E
p2: -->(1 X 3)--E-->(3 X 5)--E-->(5 X 7)--E
Memory Use/Error Check
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to ensure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/poly_list
==23402== Memcheck, a memory error detector
==23402== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==23402== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==23402== Command: ./bin/poly_list
==23402==
Enter the number of nodes: 2
Enter the coefficient (a for a*x^b) : 2
Enter the exponent/power (b for a*x^b): 6
Enter the coefficient (a for a*x^b) : 3
Enter the exponent/power (b for a*x^b): 7
Enter the number of nodes: 3
Enter the coefficient (a for a*x^b) : 1
Enter the exponent/power (b for a*x^b): 3
Enter the coefficient (a for a*x^b) : 3
Enter the exponent/power (b for a*x^b): 5
Enter the coefficient (a for a*x^b) : 5
Enter the exponent/power (b for a*x^b): 7
p1: -->(2 X 6)--E-->(3 X 7)--E
p2: -->(1 X 3)--E-->(3 X 5)--E-->(5 X 7)--E
==23402==
==23402== HEAP SUMMARY:
==23402== in use at exit: 0 bytes in 0 blocks
==23402== total heap usage: 7 allocs, 7 frees, 2,128 bytes allocated
==23402==
==23402== All heap blocks were freed -- no leaks are possible
==23402==
==23402== For counts of detected and suppressed errors, rerun with: -v
==23402== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
Look things over and let me know if you have further questions.
I might be wrong, but in the function
struct node *create_new_nodes(struct node *m)
it looks like both the return type and the parameter are pointers. So really, you are returning
struct node **m
Not sure if that's what's wrong, but if it is, the same issue might appear when you do
printf("-->(%d X %d)--E", temp->coeff, temp->exp);
when temp is ptr which is struct node*. So really you are saying (**node).coeff. But this is just my tired observation, if it works just ignore me.

How to store the contents of a CSV file in a Linked List?

I am trying to insert the contents from a csv file into a linklist using C. However, I am getting quite a few garbage outputs. The source code is given below.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct product *customer_head;
struct customer
{
long long int c_id;//first 6 characters=date & next 6 characters=time & next characters=counter no & city code
/*Compulsory Fields (Cannot be Skipped)*/
char name[57];
long long int ph_no;//10 digit phone number
/*Non Compulsory Fields (Can be Skipped)*/
char address[58];
char city[25];
char state_code[2];
char pin[6];
char email[60];
struct customer *next;
};
struct customer * load()
{
FILE * cust=fopen("customer_db.csv","r");
struct customer *temp,*ptr;
customer_head=NULL;
char str[208];
char *token,*eptr1,*eptr2;
int line_cnt=0,i=0;
while(fgets(str,234,cust)!=NULL)
{
line_cnt=0;
i=0;
ptr=(struct customer *)malloc(sizeof(struct customer));
for(;str[i];i++)
{
if(str[i]=='\n')
{
str[i]='\0';
i=0;
break;
}
}
token=strtok(str,",");
while(token!=NULL)
{
if(line_cnt==0)
ptr->c_id=strtoll(token,&eptr1,10);
else if(line_cnt==1)
ptr->ph_no=strtoll(token,&eptr2,10);
else if(line_cnt==2)
sprintf(ptr->name,"%s",token);
else if(line_cnt==3)
sprintf(ptr->address,"%s",token);
else if(line_cnt==4)
sprintf(ptr->city,"%s",token);
else if(line_cnt==5)
sprintf(ptr->state_code,"%s",token);
else if(line_cnt==6)
sprintf(ptr->pin,"%s",token);
else
sprintf(ptr->email,"%s",token);
line_cnt++;
token=strtok(NULL,",");
}
if(customer_head==NULL)
customer_head=ptr;
else
temp->next=ptr;
temp=ptr;
}
}
int print(struct customer *h)
{
while(h->next!=NULL)
{
printf("\nCustomer ID: ");
printf("%lld",h->c_id);
printf("\nName: ");
puts(h->name);
printf("Phone Number: ");
printf("%lld",h->ph_no);
printf("\nAddress: ");
puts(h->address);
printf("City: ");
puts(h->city);
printf("State Code: ");
puts(h->state_code);
printf("PIN: ");
puts(h->pin);
printf("Email: ");
puts(h->email);
h=h->next;
}
printf("\nCustomer ID: ");
printf("%lld",h->c_id);
printf("\nName: ");
puts(h->name);
printf("Phone Number: ");
printf("%ld",h->ph_no);
printf("\nAddress: ");
puts(h->address);
printf("City: ");
puts(h->city);
printf("State Code: ");
puts(h->state_code);
printf("PIN: ");
puts(h->pin);
printf("Email: ");
puts(h->email);
return 1;
}
int main()
{
load();
print(customer_head);
}
I am also attaching the csv file here. In order for the program to be less complicated I have removed the headings from my csv file. They are in the order
Customer_ID,Phone_Number,Name,Address,City,State_Code,PIN,Email
1403201156540201,2226179183,Katherine_Hamilton,87_Thompson_St.,Fremont,IA,502645,k_hamilton#gmail.com
2204201532220103,8023631298,Marc_Knight,-,-,-,-,-
0305201423120305,8025595163,Albie_Rowland,-,Hamburg,NY,140752,-
0607201232220901,4055218053,Grant_Phelps,-,-,-,-,-
The dashes(-) indicate that those fields should remain empty.
The output is as follows:
Customer ID: 1403201156540201
Name: Katherine_Hamilton
Phone Number: 2226179183
Address: 87_Thompson_St.
City: Fremont
State Code: IA502645k_hamilton#gmail.com
PIN: 502645k_hamilton#gmail.com
Email: k_hamilton#gmail.com
Customer ID: 2204201532220103
Name: Marc_Knight
Phone Number: 8023631298
Address: -
City: -
State Code: -
PIN: -
Email: -
Customer ID: 305201423120305
Name: Albie_Rowland
Phone Number: 8025595163
Address: -
City: Hamburg
State Code: NY140752-
PIN: 140752-
Email: -
Customer ID: 607201232220901
Name: Grant_Phelps
Phone Number: 4055218053
Address: -
City: -
State Code: -
PIN: -
Email: -
As you can see, the contents are getting merged in quite a few places. I don't understand why.
Since from the comments you know that your declaration of your character arrays suffer from one-too-few character, at least in the case of char state_code[2]; leaving your array without a nul-terminating character leading to Undefined Behavior, you should ensure you have valid storage for all your input. (don't skimp on buffer size)
In general, you are making things a bit harder on yourself than it needs to be. Rather than attempting to use strtok() and count field and handle each field in a 8-part chain of if, else if ..., you have fixed input fields, so just parse the data with sscanf() and validate the number of conversions to confirm a successful parse, e.g.
/** fill list from csv file */
list_t *list_from_csv (list_t *list, FILE *fp)
{
char buf[MAXC];
node_t data = { .c_id = 0, .next = NULL };
while (fgets (buf, MAXC, fp)) { /* read each line in file */
/* parse and VALIDATE values from line */
if (sscanf (buf, "%lld,%lld,%63[^,],%63[^,],%31[^,],%7[^,],%7[^,],%63[^,\n]",
&data.c_id, &data.ph_no, data.name, data.address, data.city,
data.state_code, data.pin, data.email) == 8) {
if (!add (list, &data)) /* validate add to list or break */
break;
}
}
return list;
}
Here, list_t is just an additional "wrapper" struct that holds a head and tail pointer for your linked list. This allows you to declare multiple lists in the scope needed and allows the same O(1) insertion by having the tail pointer always point to the last node in your list (your temp). Here, head and tail are just part of the wrapper and passed as a parameter rather than having to declare the list-pointer as global (bad practice). Each of the nodes in your list and the wrapper struct can be written as:
#define BYTE8 8 /* if you need a constant, #define one (or more) */
#define BYTE32 32
#define BYTE64 64
#define MAXC 1024
typedef struct node_t { /* list node */
/* 6 characters=date & 6 characters=time & counter no & city code */
long long int c_id;
/*Compulsory Fields (Cannot be Skipped)*/
char name[BYTE64];
long long int ph_no; //10 digit phone number
/*Non Compulsory Fields (Can be Skipped)*/
char address[BYTE64];
char city[BYTE32];
char state_code[BYTE8];
char pin[BYTE8];
char email[BYTE64];
struct node_t *next;
} node_t;
typedef struct { /* list wrapper with head & tail pointers */
node_t *head, *tail;
} list_t;
Then rather than writing your load() to contain both the FILE and list operations, keep your list operations separate. Simply create an add() function to add a node to your list, e.g.
/** add node at end of list, update tail to end */
node_t *add (list_t *l, node_t *data)
{
node_t *node = malloc (sizeof *node); /* allocate node */
if (!node) { /* validate allocation */
perror ("malloc-node");
return NULL;
}
*node = *data; /* initialize members values */
if (!l->head) /* if 1st node, node is head/tail */
l->head = l->tail = node;
else { /* otherwise */
l->tail->next = node; /* add at end, update tail pointer */
l->tail = node;
}
return node; /* return new node */
}
Now your load function need only read each line from the file and parse the line before calling add() passing a pointer to a struct of data along with the list pointer as parameters. Your load() function reduces to:
/** fill list from csv file */
list_t *list_from_csv (list_t *list, FILE *fp)
{
char buf[MAXC];
node_t data = { .c_id = 0, .next = NULL };
while (fgets (buf, MAXC, fp)) { /* read each line in file */
/* parse and VALIDATE values from line */
if (sscanf (buf, "%lld,%lld,%63[^,],%63[^,],%31[^,],%7[^,],%7[^,],%63[^,\n]",
&data.c_id, &data.ph_no, data.name, data.address, data.city,
data.state_code, data.pin, data.email) == 8) {
if (!add (list, &data)) /* validate add to list or break */
break;
}
}
return list;
}
(note: when using strtok() or sscanf(), there is no need to strip the trailing '\n' from your input string -- simply include that as a delimiter for strtok() or exclude it from the conversion with sscanf())
Further, you don't need multiple calls to puts() and printf() to print each node's worth of data in your list. Look at how many function calls you make to print your data. You only need ONE call to printf(), e.g.
/** print all nodes in list */
void prn_list (list_t *l)
{
if (!l->head) {
puts ("list-empty");
return;
}
for (node_t *n = l->head; n; n = n->next)
printf ("\nCustomer ID: %lld\n"
"Name: %s\n"
"Phone Number: %lld\n"
"Address: %s\n"
"City: %s\n"
"State Code: %s\n"
"PIN: %s\n"
"Email: %s\n", n->c_id, n->name, n->ph_no, n->address, n->city,
n->state_code, n->pin, n->email);
}
In main() simply declare an instance of your list_t wrapper, open/validate your FILE and then pass a pointer to the list and file-stream to your list_from_csv() (your load()) and then print the list and finally free all memory you have allocated and you are done. (yes, the memory will be freed on exit, but develop good habits early -- it won't be long before you are using allocate memory in function where a failure to free before return results in a memory-leak)
int main (int argc, char **argv) {
list_t list = { .head = NULL, .tail = NULL };
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
if (!list_from_csv (&list, fp))
return 1;
if (fp != stdin) /* close file if not stdin */
fclose (fp);
prn_list (&list);
del_list (&list);
}
Putting it altogether, you would have something similar to the following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BYTE8 8 /* if you need a constant, #define one (or more) */
#define BYTE32 32
#define BYTE64 64
#define MAXC 1024
typedef struct node_t { /* list node */
/* 6 characters=date & 6 characters=time & counter no & city code */
long long int c_id;
/*Compulsory Fields (Cannot be Skipped)*/
char name[BYTE64];
long long int ph_no; //10 digit phone number
/*Non Compulsory Fields (Can be Skipped)*/
char address[BYTE64];
char city[BYTE32];
char state_code[BYTE8];
char pin[BYTE8];
char email[BYTE64];
struct node_t *next;
} node_t;
typedef struct { /* list wrapper with head & tail pointers */
node_t *head, *tail;
} list_t;
/** add node at end of list, update tail to end */
node_t *add (list_t *l, node_t *data)
{
node_t *node = malloc (sizeof *node); /* allocate node */
if (!node) { /* validate allocation */
perror ("malloc-node");
return NULL;
}
*node = *data; /* initialize members values */
if (!l->head) /* if 1st node, node is head/tail */
l->head = l->tail = node;
else { /* otherwise */
l->tail->next = node; /* add at end, update tail pointer */
l->tail = node;
}
return node; /* return new node */
}
/** print all nodes in list */
void prn_list (list_t *l)
{
if (!l->head) {
puts ("list-empty");
return;
}
for (node_t *n = l->head; n; n = n->next)
printf ("\nCustomer ID: %lld\n"
"Name: %s\n"
"Phone Number: %lld\n"
"Address: %s\n"
"City: %s\n"
"State Code: %s\n"
"PIN: %s\n"
"Email: %s\n", n->c_id, n->name, n->ph_no, n->address, n->city,
n->state_code, n->pin, n->email);
}
/** delete all nodes in list */
void del_list (list_t *l)
{
node_t *n = l->head;
while (n) {
node_t *victim = n;
n = n->next;
free (victim);
}
}
/** fill list from csv file */
list_t *list_from_csv (list_t *list, FILE *fp)
{
char buf[MAXC];
node_t data = { .c_id = 0, .next = NULL };
while (fgets (buf, MAXC, fp)) { /* read each line in file */
/* parse and VALIDATE values from line */
if (sscanf (buf, "%lld,%lld,%63[^,],%63[^,],%31[^,],%7[^,],%7[^,],%63[^,\n]",
&data.c_id, &data.ph_no, data.name, data.address, data.city,
data.state_code, data.pin, data.email) == 8) {
if (!add (list, &data)) /* validate add to list or break */
break;
}
}
return list;
}
int main (int argc, char **argv) {
list_t list = { .head = NULL, .tail = NULL };
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
if (!list_from_csv (&list, fp))
return 1;
if (fp != stdin) /* close file if not stdin */
fclose (fp);
prn_list (&list);
del_list (&list);
}
Example Use/Output
With your input file in dat/customer_list.txt, running the program you would receive:
$ ./bin/customer_list dat/customer_list.txt
Customer ID: 1403201156540201
Name: Katherine_Hamilton
Phone Number: 2226179183
Address: 87_Thompson_St.
City: Fremont
State Code: IA
PIN: 502645
Email: k_hamilton#gmail.com
Customer ID: 2204201532220103
Name: Marc_Knight
Phone Number: 8023631298
Address: -
City: -
State Code: -
PIN: -
Email: -
Customer ID: 305201423120305
Name: Albie_Rowland
Phone Number: 8025595163
Address: -
City: Hamburg
State Code: NY
PIN: 140752
Email: -
Customer ID: 607201232220901
Name: Grant_Phelps
Phone Number: 4055218053
Address: -
City: -
State Code: -
PIN: -
Email: -
Memory Use/Error Check
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to ensure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/customer_list dat/customer_list.txt
==14823== Memcheck, a memory error detector
==14823== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==14823== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==14823== Command: ./bin/customer_list dat/customer_list.txt
==14823==
Customer ID: 1403201156540201
Name: Katherine_Hamilton
Phone Number: 2226179183
Address: 87_Thompson_St.
City: Fremont
State Code: IA
PIN: 502645
Email: k_hamilton#gmail.com
<snipped rest>
==14823==
==14823== HEAP SUMMARY:
==14823== in use at exit: 0 bytes in 0 blocks
==14823== total heap usage: 7 allocs, 7 frees, 6,728 bytes allocated
==14823==
==14823== All heap blocks were freed -- no leaks are possible
==14823==
==14823== For counts of detected and suppressed errors, rerun with: -v
==14823== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
While you could cure a significant part of your problem just by ensuring you have adequate storage for each string, take the time to think through approaching the parse of values with sscanf() and since you control the conversion, there is no need to remove the trailing '\n' from the line read from the file. (just don't include the newline in the value parsed from your input string) If you did want to parse the '\n' from the end, you should be using, e.g.
str[strcspn (str, "\n")] = 0;
Lastly with both the format-string used with sscanf() and with strcspn() above, make sure you understand exactly how they work, see man 3 scanf and man 3 strspn
Let me know if you have further questions.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum operations {EXIT, ADD_BOOK, ISSUE_BOOK, RETURN_BOOK, DISPLAY_BOOKS,
SORT_BOOKS, DISPLAY_BOOK_SUBJECTWISE};
typedef enum operations MENU;
typedef struct book
{
int bookId;
char bookName[30];
char subject[30];
char author[30];
float price;
}BOOK;
typedef struct node
{
struct node *prev;
BOOK info;
struct node *next;
}NODE;
NODE *head=NULL;
NODE *issuehead=NULL;
static int counter=0;
MENU menu_function()
{
int choice;
printf(" 1. Add Book\n");
printf(" 2. Issue Book\n");
printf(" 3. Return Book\n");
printf(" 4. Display Book\n");
printf(" 5. Sort Book\n");
printf(" 6. Display Books Subject-wise\n");
printf(" 0. EXIT\n");
printf(" Enter your choice::");
scanf("%d",&choice);
if(choice < 0 || choice > 6)
{
printf(" Error: Enter valid choice\n");
}
return choice;
}
void FreeList()
{
while(CountNodes(head))
{
DeleteBook();
}
while(CountNodes(issuehead))
{
DeleteIssues();
}
}
int CountNodes(NODE *trav)
{
int count=0;
while(trav!=NULL)
{
count++;
trav=trav->next;
}
return count;
}
void DeleteBook()
{
NODE *temp=head;
head = head->next;
free(temp);
temp=NULL;
}
void DeleteIssues()
{
NODE *temp=issuehead;
issuehead = issuehead->next;
free(temp);
temp=NULL;
}
void AcceptData(BOOK *book)
{
book->bookId=++counter;
getchar();
printf(" Enter Book name::");
scanf("%[^\n]s",&book->bookName);
getchar();
printf(" Enter Subject::");
scanf("%[^\n]s",&book->subject);
getchar();
printf(" Enter author::");
scanf("%[^\n]s",&book->author);
printf(" Enter price::");
scanf("%f",&book->price);
}
void DisplayData(BOOK book)
{
printf(" %d\t\t",book.bookId);
printf(" %s\t\t",book.bookName);
printf(" %s\t\t",book.subject);
printf(" %s\t\t",book.author);
printf(" %g\n",book.price);
}
NODE *CreateNode()
{
NODE *temp;
temp = (NODE *) malloc(sizeof(NODE));
temp->next=NULL;
temp->prev=NULL;
return temp;
}
void AddtoBooklist(BOOK book)
{
NODE *new_node;
new_node=CreateNode();
new_node->info=book;
if(head == NULL)
{
head=new_node;
}
else
{
new_node->next=head;
head->prev=new_node;
head=new_node;
}
}
void DisplayBooks(NODE *trav)
{
if(trav==NULL)
{
printf(" Book list is empty...\n");
}
else
{
printf(" Available Books\n");
while(trav!=NULL)
{
DisplayData(trav->info);
trav=trav->next;
}
printf("\n");
}
}
void IssueBook()
{
NODE *trav=head, *prev=NULL;
NODE *temp, *right;
int bookId;
printf(" Enter Book ID::");
scanf("%d",&bookId);
while(bookId != trav->info.bookId)
{
prev=trav;
trav=trav->next;
if(trav==NULL)
{
printf(" Book not found...\n");
break;
}
}
if(trav==head)
{
temp = trav;
head->prev=NULL;
head = head->next;
trav=NULL;
IssueAtFirst(temp);
printf(" Book issued successfully...\n");
}
else if(trav->next==NULL)
{
temp=trav;
prev->next=NULL;
trav->prev=NULL;
trav=NULL;
IssueAtFirst(temp);
printf(" Book issued successfully...\n");
}
else
{
temp=trav;
right=trav->next;
prev->next=right;
right->prev=prev;
trav->next=NULL;
trav->prev=NULL;
trav=NULL;
IssueAtFirst(temp);
printf(" Book issued successfully...\n");
}
}
void IssueAtFirst(NODE *temp)
{
if(issuehead == NULL)
{
issuehead=temp;
temp->next=NULL;
temp->prev=NULL;
temp=NULL;
}
else
{
temp->next=issuehead;
temp->prev=NULL;
issuehead=temp;
temp=NULL;
}
}
void ReturnBook()
{
NODE *trav=issuehead, *prev=NULL;
NODE *temp, *right;
int bookId;
printf(" Enter Book ID::");
scanf("%d",&bookId);
while(bookId != trav->info.bookId)
{
prev=trav;
trav=trav->next;
if(trav==NULL)
{
printf(" Book not found...\n");
break;
}
}
if(trav==issuehead)
{
temp = trav;
issuehead->prev = NULL;
issuehead = issuehead->next;
trav=NULL;
ReturnAtFirst(temp);
printf(" Book returned successfully...\n");
}
else if(trav->next==NULL)
{
temp=trav;
prev->next=NULL;
trav->prev=NULL;
trav=NULL;
ReturnAtFirst(temp);
printf(" Book returned successfully...\n");
}
else
{
temp=trav;
right=trav->next;
prev->next=right;
right->prev=prev;
trav->next=NULL;
trav->prev=NULL;
trav=NULL;
ReturnAtFirst(temp);
printf(" Book returned successfully...\n");
}
}
void ReturnAtFirst(NODE *temp)
{
if(head == NULL)
{
head=temp;
temp->next=NULL;
temp->prev=NULL;
temp=NULL;
}
else
{
head->prev=temp;
temp->next=head;
temp->prev=NULL;
head=temp;
temp=NULL;
}
}
void SortBooks()
{
NODE *trav=head,*right=head->next;
BOOK temp;
while(trav->next!=NULL)
{
right=trav->next;
while(right!=NULL)
{
if(trav->info.bookId > right->info.bookId)
{
temp = trav->info;
trav->info = right->info;
right->info = temp;
}
right=right->next;
}
trav=trav->next;
}
}
void AddBooksToFile()
{
NODE *trav=head;
FILE *fp;
fp=fopen("Booklist.dat","wb");
if(fp!=NULL)
{
while(trav!=NULL)
{
fwrite(&trav->info, sizeof(BOOK),1,fp);
trav=trav->next;
}
}
fclose(fp);
}
void AddIssuesToFile()
{
NODE *trav=issuehead;
FILE *fp=issuehead;
fp=fopen("Issuelist.dat","wb");
if(fp!=NULL)
{
while(trav!=NULL)
{
fwrite(&trav->info, sizeof(BOOK),1,fp);
trav=trav->next;
}
}
fclose(fp);
}
void ReadIssuesFromFile()
{
BOOK book;
FILE *fp;
fp=fopen("Issuelist.dat","rb");
if(fp!=NULL)
{
while((fread(&book,sizeof(BOOK),1,fp))!=0)
{
AddtoIssuelist(book);
}
}
fclose(fp);
}
void ReadBooksFromFile()
{
BOOK book;
FILE *fp;
fp=fopen("Booklist.dat","rb");
if(fp!=NULL)
{
while((fread(&book,sizeof(BOOK),1,fp))!=0)
{
AddtoBooklist(book);
}
}
fclose(fp);
}
void AddtoIssuelist(BOOK book)
{
NODE *new_node;
new_node=CreateNode();
new_node->info=book;
if(issuehead == NULL)
{
issuehead=new_node;
}
else
{
new_node->next=issuehead;
issuehead->prev=new_node;
issuehead=new_node;
}
}
void DisplaySubjectWise(NODE *head)
{
NODE *trav=head;
char subject[30];
printf(" Enter subject::");
scanf("%s",&subject);
while(trav!=NULL)
{
if(stricmp(subject, trav->info.subject)== 0)
{
DisplayData(trav->info);
}
trav=trav->next;
}
}
int main()
{
MENU choice;
int data;
BOOK book;
ReadBooksFromFile();
ReadIssuesFromFile();
while((choice=menu_function())!=EXIT)
{
switch(choice)
{
case ADD_BOOK:
AcceptData(&book);
AddtoBooklist(book);
printf(" Book added to library successfully...\n");
break;
case ISSUE_BOOK:
if(head==NULL)
{
printf(" No Books are available now...\n");
break;
}
else
{
IssueBook();
}
break;
case RETURN_BOOK:
if(issuehead==NULL)
{
printf(" No Books are issued...\n");
break;
}
else
{
ReturnBook();
}
break;
case DISPLAY_BOOKS:
DisplayBooks(head);
DisplayBooks(issuehead);
printf("\n");
break;
case SORT_BOOKS:
if(head==NULL)
{
printf(" No Books to sort...\n");
break;
}
SortBooks();
break;
case DISPLAY_BOOK_SUBJECTWISE:
if(head==NULL)
{
printf(" No Books to display...\n");
break;
}
DisplaySubjectWise(head);
break;
}
}
AddBooksToFile();
AddIssuesToFile();
FreeList();
return 0;
}
for your reference

Adding a node to the middle of a singly linked list

So I have code that I will show below
struct GraphicElement {
char* fileName;
struct GraphicElement* pNext;
};
struct RasterGraphic {
struct GraphicElement* GraphicElements;
};
AND ALSO
void InsertGraphicElement(struct RasterGraphic* pA)
{
int counter = 1;
int response = 0;
char tempString[256];
struct GraphicElement *newNode = malloc(sizeof(*newNode));
if (newNode == NULL) return;
newNode->fileName = malloc(256 * sizeof(char));
if (newNode->fileName == NULL) return;
newNode->pNext = NULL;
printf("Insert a GraphicElement in the RasterGraphic\nPlease enter the GraphicElement filename: ");
scanf("%s", newNode->fileName);
if (pA->GraphicElements == NULL)
{
pA->GraphicElements = newNode;
printf("This is the first GraphicElement in the list\n");
}
else
{
struct GraphicElement *tempHead = pA->GraphicElements;
while (tempHead->pNext != NULL)
{
tempHead = tempHead->pNext;
counter++;
}
printf("There are %d GraphicElement(s) in the list. Please specify the position (<= %d) to insert at :", counter, counter);
scanf("%d", &response);
if (response == counter) {
tempHead->pNext = newNode;
return;
}
}
return;
}
So as you can see I have a struct definition and then a function to insert a node into the list. I have it so that if its the first node it inserts and tells the user it is the first element in the list. Where I am having a problem is adding more elements. Right now the code has no problems adding new nodes in sequence. The user is asked where they would like to insert into the list. Right now as long as they choose to just add it in sequence it works perfectly. I've tried a lot of things i just cant figure out the logic to loop through and be able to add a node to the middle of the list so an example output would be like this..
List contains 1, 2, 3
the user adds a fourth element 4 but wants to add it to spot 1 which is where the 2 is sitting so the new updated list would look like 1, 4, 2, 3.
There is no magic to inserting anywhere within the linked list, the only real challenge is keeping your pointers straight when handling three conditions:
inserting the first node (or new first node);
inserting a node between at some position between the existing first and last node; and
inserting at the end of the list.
The first case, inserting the first (or new first) node simply requires allocating a new node and either inserting it is the first node in the list, or if the head node already exists, setting newnode->next = head; and head = newnode;
Inserting at the end is not much different, you just iterate to the last node and set last->next = newnode;
The case of inserting a node in between takes a bit more thought. The easiest way to keep your pointers straight is to pull out a pencil and paper and draw out your pointer diagram of your list and then break the list in two where you need to insert the new node, and figure out the steps required before you pickup the keyboard (it will go a lot easier that way)
Nothing fancy is needed, just a block diagram with your next (or your pNext) pointer connecting the nodes. A simple list will two nodes (A and B) will do, e.g.
A B
+------+ +------+
| node | | node |
| next |--> | next |-->NULL
+------+ +------+
Then just break the list at the point where the new node will be inserted, e.g.
A B
+------+ | +------+
| node | / | node |
| next |--> \ | next |-->NULL
+------+ / +------+
|
new
+------+
| node |
| next |-->
+------+
That allows you to visualize the needed steps. Locate node A, set new->next = B;, set A->next = new; (note: you must stop at the node before the location you wish to insert the new node) The result will then be:
A new B
+------+ +------+ +------+
| node | | node | | node |
| next |--> | next |--> | next |-->NULL
+------+ +------+ +------+
When an understanding of exactly what you need to do to handle the insertion, now pick up the keyboard and implement that logic.
Since you will have a single insert function to handle all three cases, as #WhozCraig commented, when handling list operations (or pointers in general where you may need to assign a new block of memory within a function changing the address of the pointer), it helps to pass the address of the pointer to your function (so that your function receives the pointer itself -- instead of a copy of the pointer).
Whether in your case you need to initially allocate for the list wrapper, or in a simple list where you may assign a new node as the first node in the list, passing the address of the pointer allows the change within the function without having to return and assign the return as the new address back in the calling function.
Adding a couple of typedefs gelement_t for your struct GraphicElement and rgraphic_t for struct RasterGraphic types, both to cut down on typing an remove some of the MixedCase style awkwardness, you can think about your InsertGraphicElement function in the following way.
First, your InsertGraphicElement function will either succeed or fail, so choose a meaningful return type that can indicate success or failure. When dealing with lists, returning a pointer to the newly inserted node is helpful and allows a return of NULL in the even of failure, e.g.
gelement_t *InsertGraphicElement (rgraphic_t **pA)
Since you are passing a pointer to pointer to your RasterGraphic struct, you can add data to the struct to make it a bit more useful as a wrapper to your actual list. Adding a node-counter is a convenient way to keep track of the number of nodes in a singly-linked list without having to iterate over the list each time, e.g.
typedef struct RasterGraphic {
size_t nelements;
gelement_t *GraphicElements;
} rgraphic_t;
Within your function you should validate that you have an allocated pointer, and if not, then allocate for the RasterGraphic struct, e.g.
int position = 0;
if (!*pA) { /* if list NULL - allocate new list */
puts ("allocating new list.");
*pA = malloc (sizeof **pA);
if (!*pA) { /* validate every allocation */
perror ("malloc-*list");
exit (EXIT_FAILURE);
}
(*pA)->nelements = 0; /* initialize values */
(*pA)->GraphicElements = NULL;
}
Next you can allocate and validate the new node to add either as the first node or at position, e.g.
gelement_t *node = malloc (sizeof *node); /* allocate node */
if (!node) { /* validate */
perror ("malloc-node");
exit (EXIT_FAILURE);
}
Next collect your filename and position information and set node->fileName to a newly allocated block holding the filename entered by the user (a couple of helper-functions make this much easier), e.g.
node->fileName = get_filename_stdin(); /* request filename */
if (!node->fileName) { /* validate */
free (node);
return NULL;
}
node->pNext = NULL; /* set next pointer NULL */
position = get_int_stdin (*pA); /* request position */
You are now at the point within the function where you handle the 3-cases identified at the beginning of the answer. If there is no (*pA)->GraphicElements node yet, you will add the first node (so you don't need to ask for position). If it isn't the first node, and the position requested is 0, you insert as a new first node. (both can be handled in a single case)
If the position requested is greater than zero, then you iterate to the node before the insertion point and insert as indicated with the diagram above and insert the node there.
One approach would be:
gelement_t *p = (*pA)->GraphicElements;
if (!p || position == 0) { /* insert as new head */
node->pNext = p;
(*pA)->GraphicElements = node;
}
else { /* insert at position (default end) */
int n = 0;
while (n < position - 1 && p->pNext) { /* locate node before */
p = p->pNext;
n++;
}
node->pNext = p->pNext; /* set node->pNext to current pNext */
p->pNext = node; /* set current pNext to node */
}
(*pA)->nelements++; /* increment number of elements in list */
Which will handle your insertion based on the user input. All that remains is to:
return node; /* meaningful return to indicate success/failure */
}
(note: when you are comfortable with the list operation logic, it helps to break this function up into several functions that handle the operations individually, like create_list(), create_node() and add_node(). (where you create your RasterGraphic list, your GraphicElement node and finally add that node at a given position in the list -- that is left to you)
Putting it altogether and adding the helper functions, a short example would be:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h> /* for PATH_MAX */
typedef struct GraphicElement {
char* fileName;
struct GraphicElement* pNext;
} gelement_t;
typedef struct RasterGraphic {
size_t nelements;
gelement_t *GraphicElements;
} rgraphic_t;
char *get_filename_stdin (void)
{
char filename[PATH_MAX] = "";
char *newname = NULL;
fputs ("enter filename : ", stdout);
if (fgets (filename, PATH_MAX, stdin)) {
size_t len = strlen (filename);
if (len && filename[len-1] == '\n') {
filename[--len] = 0;
if (!len) {
fputs ("error: filename empty.\n", stderr);
return NULL;
}
}
else if (len == PATH_MAX) {
fputs ("error: filename exceeds PATH_MAX\n", stderr);
return NULL;
}
newname = malloc (len + 1);
if (!newname) {
perror ("malloc-newname");
exit (EXIT_FAILURE);
}
memcpy (newname, filename, len + 1);
}
return newname;
}
int get_int_stdin (rgraphic_t *list)
{
char buf[PATH_MAX];
int pos = 0;
if (!list->nelements) {
puts ("inserting as head.");
return 0;
}
fputs ("index to insert: ", stdout);
if (fgets (buf, PATH_MAX, stdin))
if (sscanf (buf, "%d", &pos) != 1 || pos < 0 ||
pos > (long)list->nelements)
return list->nelements;
return pos;
}
gelement_t *InsertGraphicElement (rgraphic_t **pA)
{
int position = 0;
if (!*pA) { /* if list NULL - allocate new list */
puts ("allocating new list.");
*pA = malloc (sizeof **pA);
if (!*pA) { /* validate every allocation */
perror ("malloc-*list");
exit (EXIT_FAILURE);
}
(*pA)->nelements = 0; /* initialize values */
(*pA)->GraphicElements = NULL;
}
gelement_t *node = malloc (sizeof *node); /* allocate node */
if (!node) { /* validate */
perror ("malloc-node");
exit (EXIT_FAILURE);
}
node->fileName = get_filename_stdin(); /* request filename */
if (!node->fileName) { /* validate */
free (node);
return NULL;
}
node->pNext = NULL; /* set next pointer NULL */
position = get_int_stdin (*pA); /* request position */
gelement_t *p = (*pA)->GraphicElements;
if (!p || position == 0) { /* insert as new head */
node->pNext = p;
(*pA)->GraphicElements = node;
}
else { /* insert at position (default end) */
int n = 0;
while (n < position - 1 && p->pNext) { /* locate node before */
p = p->pNext;
n++;
}
node->pNext = p->pNext; /* set node->pNext to current pNext */
p->pNext = node; /* set current pNext to node */
}
(*pA)->nelements++; /* increment number of elements in list */
return node; /* meaningful return to indicate success/failure */
}
/* loop over list printing values */
void prn_list (rgraphic_t *list)
{
size_t n = 0;
gelement_t *node = list->GraphicElements;
printf ("\n\n%zu nodes in list\n", list->nelements);
for (; node; node = node->pNext)
printf ("%2zu: %s\n", 1 + n++, node->fileName);
}
/* loop over list freeing memory (pay attention to victim) */
void free_list (rgraphic_t *list)
{
gelement_t *node = list->GraphicElements;
while (node) {
gelement_t *victim = node;
node = node->pNext;
free (victim->fileName);
free (victim);
}
free (list);
}
int main (void) {
rgraphic_t *list = NULL;
puts ("\nNOTE: pressing [Enter] for index - inserts at end!\n"
" [Ctrl+d] at \"filename: \" prompt to end input.\n");
while (InsertGraphicElement(&list)) {} /* create list/insert nodes */
prn_list (list); /* print list */
free_list (list); /* free list */
}
Example Use/Output
$ ./bin/ll_single_insert_ptp
NOTE: pressing [Enter] for index - inserts at end!
[Ctrl+d] at "filename: " prompt to end input.
allocating new list.
enter filename : one
inserting as head.
enter filename : four
index to insert: 1
enter filename : two
index to insert: 1
enter filename : three
index to insert: 2
enter filename : five
index to insert:
enter filename :
5 nodes in list
1: one
2: two
3: three
4: four
5: five
Memory Use/Error Check
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to insure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/ll_single_insert_ptp
==9747== Memcheck, a memory error detector
==9747== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==9747== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==9747== Command: ./bin/ll_single_insert_ptp
==9747==
NOTE: pressing [Enter] for index - inserts at end!
[Ctrl+d] at "filename: " prompt to end input.
allocating new list.
enter filename : one
inserting as head.
enter filename : four
index to insert: 1
enter filename : two
index to insert: 1
enter filename : three
index to insert: 2
enter filename : five
index to insert:
enter filename :
5 nodes in list
1: one
2: two
3: three
4: four
5: five
==9747==
==9747== HEAP SUMMARY:
==9747== in use at exit: 0 bytes in 0 blocks
==9747== total heap usage: 12 allocs, 12 frees, 136 bytes allocated
==9747==
==9747== All heap blocks were freed -- no leaks are possible
==9747==
==9747== For counts of detected and suppressed errors, rerun with: -v
==9747== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
Look things over and let me know if you have further questions.

How to use char * in linked list

In a struct Node type, there is a char* data. And each node uses a linked list to combine.
If the type of "data" is INT it is ok. (ex. the age: 23,45,33....) But when the type turn to "char * ", ex. save name: “Jack”,"Jay","Jame". The value is all the same, the later will cover the fronter. ex:
First time input: Jack. The list is Jack
Second time input: Jay. The list is Jay Jay
Third time input:Jame. The list is Jame Jame Jame
The code is like:
#include <stdio.h>
#include <stdlib.h>
typedef struct listNode{
char *data;
struct listNode *next;
} *ListNodePtr;
typedef struct list {
ListNodePtr head;
} List;
List new_list(){
List temp;
temp.head = NULL;
return temp;
}
//Student Courses
void insert_at_front(ListNodePtr* head, char *data){
ListNodePtr new_node = malloc(sizeof(struct listNode));
new_node->data = data;
new_node->next = *head;
*head = new_node;
}
void print_list(List *self)
{
ListNodePtr current = self->head;
while(current!=NULL)
{
printf("%s \n", current->data);
current = current->next;
}
printf("\n");
}
int main()
{
char i = 'y';
char *name;
List mylist = new_list();
while(i=='y'){
printf("your name is :");
scanf("%s",name);
insert_at_front(&mylist.head,name);
print_list(&mylist);
}
return 0;
}
The good news is your thinking on list operation is not too far off... the bad news is it isn't right-on either. The biggest stumbling blocks you have are just handling the basics of user-input, and insuring your have storage for each bit of data you want to store.
In main() when you declare char *name;, name is an uninitialized pointer. It does not point to any valid memory yet in which you can store the characters that make up name (plus the terminating nul-character). The only thing you can store in a pointer, is a memory address -- and, to be useful, that memory address must be the start of a valid block of memory sufficiently sized to hold what it is you are attempting to store.
In your code, since name does not point to any valid block of memory capable of storing the characters in name, you immediately invoke Undefined Behavior with scanf("%s",name); (Boom! - "Game Over" for your program).
Since you are reading a name, rarely over 64 characters, just use a fixed-size buffer to hold name to pass it to insert_at_front. Don't skimp on buffer size, so just to be sure, you can use something reasonable like 512 bytes. Don't use magic numbers in your code, so if you need a constant:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXN 512 /* if you need a constant, #define one (or more) */
...
int main (void) {
char i = 'y';
char name[MAXN] = ""; /* fixed size buf for reading name input */
...
Now for your structs, you are using a "wrapper" struct holding head that essentially wraps your list. It is fine to do, though not required. However, since you are using one, you need to either declare it using automatic storage (and pass it as a parameter) or dynamically allocate for it. Since you use a new_list function, if you were using automatic storage, you would have to declare mylist as type List in main() and pass it as a parameter to new_list() for initialization.
Why? You cannot return temp from new_list because temp was declared within new_list (it is local to new_list) and the function stack for new_list (the memory that contains the temp variable) is destroyed (released for reuse) when new_list returns.
If you want to return a pointer from new_list, then you must either (1) pass a previously declared temp from main() to new_list -- or -- (2) dynamically allocate for temp in new_list giving temp allocated storage duration so that the memory containing temp survives until free() is called on that memory, or the program ends. The normal option is (2), though there is nothing wrong with (1) if you adequately account for the storage duration of the variable.
Makes a few tweaks, and avoiding typedeffing a pointer, because It is NOT a good idea to typedef pointers?, and adding a convenient example of the flexibility you have to track list statistics in your wrapper struct, you could do something similar to:
typedef struct lnode { /* don't typedef pointers -- it will confuse you */
char *data;
struct lnode *next;
} lnode;
typedef struct list { /* you pass this list to insert_at_front */
lnode *head;
size_t size; /* you can track any list stats you like */
} list;
/* create a dynamically allocated list struct */
list *new_list (void)
{
list *temp = malloc (sizeof *temp); /* create storage for list */
if (!temp) { /* validate ALL allocations */
perror ("malloc-new_list");
return NULL;
}
temp->head = NULL; /* initialize head NULL */
temp->size = 0;
return temp; /* return pointer to new list */
}
To help make lists more logical while you are learning, it often helps to create a separate function that is responsible for creating each node you add to your list. This allows you to concentrate on which items within your node struct need storage allocated, and provides a convenient place to handle the allocation (and validation of that allocation), as well as initializing all values in a single place -- without cluttering your list logic. You could implement a create_node function similar to:
/* create new dynamically allocated node, initialize all values */
lnode *create_new_node (const char *data)
{
lnode *new_node = NULL;
if (!data) { /* validate data not NULL */
fputs ("error: data is NULL in create_new_node.\n", stderr);
return NULL;
}
new_node = malloc (sizeof *new_node); /* allocate/validate node */
if (!new_node) {
perror ("malloc-new_node");
return NULL;
}
/* allocate/validate storage for data */
if (!(new_node->data = malloc (strlen (data) + 1))) {
perror ("malloc-new_node->data");
free (new_node);
return NULL;
}
strcpy (new_node->data, data); /* copy data to new_node->data */
new_node->next = NULL; /* set next pointer NULL */
return new_node; /* return pointer to new_node */
}
(note: you have allocated for (1) the list, (2) the node, and (3) the data)
That leaves your logic for insert_at_front clean and readable. Additionally, you need to always use a proper type for any list operation, especially where any allocation is involved, that allows you to gauge success/failure of the list operation. Generally returning a pointer to the node added (a new head here) or NULL on failure, is all you need, e.g..
/* insert new node at front, returning pointer to head
* to guage success/failure of addition.
*/
lnode *insert_at_front (list *mylist, const char *data)
{
lnode *new_node = create_new_node(data);
if (!new_node)
return NULL;
new_node->next = mylist->head;
mylist->head = new_node;
mylist->size++;
return mylist->head;
}
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed. Get in the habit now to cleaning up after yourself -- it will pay big dividends as your programs become more complex. If you are dealing with a list, and nodes, then write a function to free all data, nodes and the list when you are done with it. Something simple is all that is needed, e.g.
/* you are responsible for freeing any memory you allocate */
void free_list (list *mylist)
{
lnode *current = mylist->head;
while (current) {
lnode *victim = current;
current = current->next;
free (victim->data);
free (victim);
}
free (mylist);
}
With user input, your are responsible for validating that you received good input and that it satisfies any conditions you have placed on the input. You are also responsible for insuring that the state of the input buffer is ready for the next input operation. That means clearing any extraneous characters that may be left in the input buffer (e.g. stdin) that would cause your next attempt at input to fail. A simple helper function to empty stdin can save you from a world of trouble.
/* you are responsible for the state of stdin when doing user input */
void empty_stdin (void)
{
int c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
}
Further, every input function you will use has a return. You must validate the return of any input function you use to determine if (1) valid input was read, (2) whether the user canceled input by generating a manual EOF, and (3) when using scanf whether a matching or input failure occurred. So always check the return! For example:
while (i == 'y' || i == '\n') { /* 'y' or (default '\n') */
fputs ("\nenter name: ", stdout);
if (scanf ("%511[^\n]", name) != 1) { /* ALWAYS CHECK RETURN! */
fputs ("error: invalid input or user canceled.", stderr);
return 1;
}
empty_stdin(); /* empty any chars that remain in stdin */
...
Putting it altogether in a short example, you could do something like the following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXN 512 /* if you need a constant, #define one (or more) */
typedef struct lnode { /* don't typedef pointers -- it will confuse you */
char *data;
struct lnode *next;
} lnode;
typedef struct list { /* you pass this list to insert_at_front */
lnode *head;
size_t size; /* you can track any list stats you like */
} list;
/* create a dynamically allocated list struct */
list *new_list (void)
{
list *temp = malloc (sizeof *temp); /* create storage for list */
if (!temp) { /* validate ALL allocations */
perror ("malloc-new_list");
return NULL;
}
temp->head = NULL; /* initialize head NULL */
temp->size = 0;
return temp; /* return pointer to new list */
}
/* create new dynamically allocated node, initialize all values */
lnode *create_new_node (const char *data)
{
lnode *new_node = NULL;
if (!data) { /* validate data not NULL */
fputs ("error: data is NULL in create_new_node.\n", stderr);
return NULL;
}
new_node = malloc (sizeof *new_node); /* allocate/validate node */
if (!new_node) {
perror ("malloc-new_node");
return NULL;
}
/* allocate/validate storage for data */
if (!(new_node->data = malloc (strlen (data) + 1))) {
perror ("malloc-new_node->data");
free (new_node);
return NULL;
}
strcpy (new_node->data, data); /* copy data to new_node->data */
new_node->next = NULL; /* set next pointer NULL */
return new_node; /* return pointer to new_node */
}
/* insert new node at front, returning pointer to head
* to guage success/failure of addition.
*/
lnode *insert_at_front (list *mylist, const char *data)
{
lnode *new_node = create_new_node(data);
if (!new_node)
return NULL;
new_node->next = mylist->head;
mylist->head = new_node;
mylist->size++;
return mylist->head;
}
/* print_list - tweaked for formatted output */
void print_list (list *self)
{
lnode *current = self->head;
while (current != NULL)
{
if (current == self->head)
printf (" %s", current->data);
else
printf (", %s", current->data);
current = current->next;
}
putchar ('\n');
}
/* you are responsible for freeing any memory you allocate */
void free_list (list *mylist)
{
lnode *current = mylist->head;
while (current) {
lnode *victim = current;
current = current->next;
free (victim->data);
free (victim);
}
free (mylist);
}
/* you are responsible for the state of stdin when doing user input */
void empty_stdin (void)
{
int c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
}
int main (void) {
char i = 'y';
char name[MAXN] = ""; /* fixed size buf for reading name input */
list *mylist = new_list();
while (i == 'y' || i == '\n') { /* 'y' or (default '\n') */
fputs ("\nenter name: ", stdout);
if (scanf ("%511[^\n]", name) != 1) { /* ALWAYS CHECK RETURN! */
fputs ("error: invalid input or user canceled.", stderr);
return 1;
}
empty_stdin(); /* empty any chars that remain in stdin */
insert_at_front (mylist, name); /* insert name */
fputs ("continue (y)/n: ", stdout); /* prompt to continue */
scanf ("%c", &i); /* read answer (or '\n' from pressing Enter) */
}
printf ("\nfinal list (%zu nodes):", mylist->size);
print_list (mylist);
free_list (mylist); /* don't forget to free memory you allocate */
return 0;
}
(note: the prompt to continue allows the user to simply press Enter to indicate he wants to continue entering names, any other character will exit. That is why (y) is shown as the default in the prompt -- can you explain why and how that works?)
Example Use/Output
$ ./bin/llinshead
enter name: Mickey Mouse
continue (y)/n:
enter name: Donald Duck
continue (y)/n:
enter name: Pluto (the dog)
continue (y)/n:
enter name: Minnie Mouse
continue (y)/n: n
final list (4 nodes): Minnie Mouse, Pluto (the dog), Donald Duck, Mickey Mouse
Memory Use/Error Check
It is imperative that you use a memory error checking program to insure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/llinshead
==5635== Memcheck, a memory error detector
==5635== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==5635== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==5635== Command: ./bin/llinshead
==5635==
enter name: Mickey Mouse
continue (y)/n:
enter name: Donald Duck
continue (y)/n:
enter name: Pluto (the dog)
continue (y)/n:
enter name: Minnie Mouse
continue (y)/n: n
final list (4 nodes): Minnie Mouse, Pluto (the dog), Donald Duck, Mickey Mouse
==5635==
==5635== HEAP SUMMARY:
==5635== in use at exit: 0 bytes in 0 blocks
==5635== total heap usage: 9 allocs, 9 frees, 134 bytes allocated
==5635==
==5635== All heap blocks were freed -- no leaks are possible
==5635==
==5635== For counts of detected and suppressed errors, rerun with: -v
==5635== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
Look things over and let me know if you have any further questions.

Trying to read in words from text file and add to linked list, program crashes and i don't know why [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
My program is supposed to read in each word from a text file and then add it to a linked list, but it crashes after I enter the user input. I have no idea why. I have tried a bunch of different functions and ways but it still crashes. I am lost.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node
{
char *data;
struct node *next;
};
void insertNode(struct node**, char *);
void printList(struct node*);
int main()
{
struct node *head = NULL;
FILE *fptr;
char file_name[20];
char str[1000];
int numOfChar;
printf("Enter the name of the file: ");
scanf("%s",file_name);
printf("Enter the number of characters per line: ");
scanf("%d",&numOfChar);
fptr=fopen(file_name,"r");
while(fscanf(fptr, "%s ", str) != EOF)
{
insertNode(&head, str);
}
fclose(fptr);
printList(head);
return 0;
}
void insertNode(struct node** nodeHead, char *data)
{
struct node* new_node = malloc(sizeof *new_node);
new_node->data = strdup(data);
new_node->next = NULL;
while (*nodeHead)
nodeHead = &(*nodeHead)->next;
*nodeHead = new_node;
}
void printList(struct node* node)
{
while(node != NULL)
{
printf(" %s ", node->data);
node = node->next;
}
}
No matter what language you are coding in, if you are not validating your input and your function call returns, you can have no confidence your code is doing anything correctly, and, more importantly, you will have no clue at what point your code begins to fail. This is fundamental. I know you are learning, but start with good habits of validating all input and all function call returns. Your life as a programmer will be made much easier.
Implementing simple validations will tell you where your code is failing and at what point it begins to fail. For example, every time you take input, validate you in fact got what you were expecting. With the scanf family of functions, that means, at a minimum, validating that the successful number of conversions took place. If you are unclear what a function returns, or how to gauge success/failure, look at the man page for the function. The declaration tells you exactly what type of return to expect, and then body of the man page tells you exactly what means success/failure.
printf ("Enter the name of the file: ");
if (scanf("%[^\n]%*c", file_name) != 1) { /* validate conversion */
fprintf (stderr, "error: scanf filename conversion failed.\n");
return 1;
}
printf ("Enter the number of characters per line: ");
if (scanf ("%d%*c",&numOfChar) != 1) { /* validate conversion */
fprintf (stderr, "error: scanf numOfChar conversion failed.\n");
return 1;
}
if (!(fptr = fopen (file_name,"r"))) { /* validate file open */
fprintf (stderr, "error: file open failed for '%s'.\n", file_name);
return 1;
}
(side node: the style specification for C, avoids the use of caMelCase variable names, all lower-case is preferred. See e.g. NASA - C Style Guide, 1994 )
In any code your write that dynamically allocates memory, you have 2 responsibilites regarding any block of memory allocated: (1) always preserves a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to insure you are using the memory you allocate properly and that it is all freed when no longer needed. There are many subtle ways to misuse a new block of memory. For Linux valgrind is the normal choice. (it is dead-bang simple to use, just valgrind ./yourprogram)
To free your list you will need to free all memory allocated by strdup and the memory you allocate directly with malloc. With a list, you need to create a second pointer that holds the address of the block to free so you can assign node = node->next before deleting the node. A short example would be:
void freelist (struct node *node)
{
while (node) {
struct node *victim = node;
node = node->next;
free (victim->data);
free (victim);
}
}
Putting all the pieces together, minimal validation, and proper use of free could look something like:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum { MAXF = 20, MAXC = 1000 };
struct node {
char *data;
struct node *next;
};
void insertnode (struct node**, char *);
void printlist (struct node*);
void freelist (struct node *node);
int main (void) {
struct node *head = NULL;
FILE *fptr;
char file_name[MAXF];
char str[MAXC];
int numOfChar = 0; /* note: does nothing currently */
printf ("Enter the name of the file: ");
if (scanf("%[^\n]%*c", file_name) != 1) { /* validate conversion */
fprintf (stderr, "error: scanf filename conversion failed.\n");
return 1;
}
printf ("Enter the number of characters per line: ");
if (scanf ("%d%*c",&numOfChar) != 1) { /* validate conversion */
fprintf (stderr, "error: scanf numOfChar conversion failed.\n");
return 1;
}
if (!(fptr = fopen (file_name,"r"))) { /* validate file open */
fprintf (stderr, "error: file open failed for '%s'.\n", file_name);
return 1;
}
while (fscanf (fptr, "%s ", str) != EOF)
insertnode (&head, str);
fclose (fptr);
printlist (head);
freelist (head);
return 0;
}
void insertnode (struct node **nodeHead, char *data)
{
struct node *new_node = malloc (sizeof *new_node);
if (!new_node) {
fprintf (stderr, "error: virtual memory exhausted - new_node.\n");
exit (EXIT_FAILURE);
}
new_node->data = strdup(data);
new_node->next = NULL;
while (*nodeHead)
nodeHead = &(*nodeHead)->next;
*nodeHead = new_node;
}
void printlist (struct node *node)
{
while (node) {
printf(" %s ", node->data);
node = node->next;
}
putchar ('\n');
}
void freelist (struct node *node)
{
while (node) {
struct node *victim = node;
node = node->next;
free (victim->data);
free (victim);
}
}
Look it over and let me know if you have further questions.
Second Approach to insertnode
Since you are having problems with insertnode, there is another way to iterate over the current nodes (there are actually a few more). Give the following a try:
void insertnode (struct node **nodeHead, char *data)
{
if (!data || !*data) {
fprintf (stderr, "error: invalid 'data' passed to insertnode '%s'.\n",
data);
exit (EXIT_FAILURE);
}
struct node *new_node = malloc (sizeof *new_node);
if (!new_node) {
fprintf (stderr, "error: virtual memory exhausted - new_node.\n");
exit (EXIT_FAILURE);
}
new_node->data = strdup(data);
new_node->next = NULL;
if (!*nodeHead) {
*nodeHead = new_node;
}
else {
while ((*nodeHead)->next)
nodeHead = &((*nodeHead)->next);
(*nodeHead)->next = new_node;
}
}
Using a Separate Pointer to Iterate
void insertnode (struct node **nodeHead, char *data)
{
if (!data || !*data) {
fprintf (stderr, "error: invalid 'data' passed to insertnode '%s'.\n",
data);
exit (EXIT_FAILURE);
}
struct node *new_node = malloc (sizeof *new_node);
if (!new_node) {
fprintf (stderr, "error: virtual memory exhausted - new_node.\n");
exit (EXIT_FAILURE);
}
new_node->data = strdup(data);
new_node->next = NULL;
if (!*nodeHead)
*nodeHead = new_node;
else {
struct node *iter = *nodeHead;
for (; iter->next; iter = iter->next) {}
iter->next = new_node;
}
}
Answer to Your Second Issue With Printing
While I like the fgets approach to your list, much better than scanf, I liked your first list layout better than the current. Your parsing implementation here is a train-wreck for the reasons given in the comment. strtok (or strsep) are the proper parsing functions for breaking strings into words (or you can do it with pointers -- but it takes much more than you have. Look at the mand page for strtok. Here is an example using it to do the word-splitting:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct list {
char *string;
struct list *next;
} LIST;
void freelist (struct list *node);
int main (void) {
FILE *fp;
char line[128];
char file_name[20];
LIST *current, *head;
char *p;
char *delim = " \t\r\n";
head = current = NULL;
printf ("Enter the name of the file: ");
scanf("%s",file_name);
fp = fopen(file_name, "r");
while(fgets(line, sizeof(line), fp))
{
for (p = strtok (line, delim); p; p = strtok (NULL, delim))
{
LIST *node = malloc (sizeof(LIST));
if (!(node->string = strdup (p))) {
fprintf (stderr, "error: virtual memory exhausted.\n");
exit (EXIT_FAILURE);
}
node->next = NULL;
if (!head)
current = head = node;
else {
current->next = node;
current = current->next;
}
}
}
fclose(fp);
for (current = head; current; current = current->next) {
printf(" %s", current->string);
}
putchar ('\n');
freelist (head);
return 0;
}
void freelist (struct list *node)
{
while (node) {
struct list *victim = node;
node = node->next;
free (victim->string);
free (victim);
}
}
Give it a go -- hopefully no problems -- I'm falling asleep at the keyboard.

Resources