Build a linked list in c - c

I am attempting to create a linked list from a file using structs, when I run the print_list it is not printing the name or threat level, but it is printing the ID. I have little experience with structs but I believe I am not understanding if the pointers are being used correctly here.
void insert(struct poi_t_struct **head_ref, char *name, long int id, int threat_level) {
// printf("Name from insert %s \n", name); // debug
struct poi_t_struct newNode = { name, id, threat_level, NULL };
struct poi_t_struct *ptr_newNode = &newNode;
struct poi_t_struct *temp = *head_ref;
}
void buildLList(char *filename) {
FILE *poiProfiles;
// char line[MAX_LINE_LENGTH];
// have 3 char arrays. One for each name, id, threat level
char idLine[MAX_LINE_LENGTH];
char nameLine[MAX_LINE_LENGTH];
char threat_levelLine[MAX_LINE_LENGTH];
while (fgets(idLine, MAX_LINE_LENGTH, poiProfiles)) {
long int id;
id = atoi(idLine);
fgets(nameLine, MAX_LINE_LENGTH, poiProfiles);
char* name;
name = nameLine;
fgets(threat_levelLine, MAX_LINE_LENGTH, poiProfiles);
int threat_level;
threat_level = atoi(threat_levelLine);
insert(&head, name, id, threat_level);
}
void print_list(struct poi_t_struct *p) {
struct poi_t_struct *temp = p;
while (temp != NULL) {
print_record(temp);
temp = temp->next;
}
}

There are multiple problems in your code:
you do not open nor close the file for poiProfiles
there is a missing } at the end of the buildLList() function.
the insert function must allocate memory for the new node, inserting a local struct object is incorrect as this object becomes invalid as soon as the function returns. You attempt to insert the new node at the beginning of the list, but you neither set the next member of the struct, not set *head_ref to point to the new node.
Here is a modified version:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct poi_t_struct {
char *name;
long int id;
int threat_level;
struct poi_t_struct *next;
} *head;
int insert(struct poi_t_struct **head_ref, const char *name, long int id, int threat_level) {
// printf("Name from insert %s \n", name); // debug
struct poi_t_struct *ptr_newNode = malloc(sizeof *ptr_newNode);
if (ptr_newNode == NULL)
return -1;
ptr_newNode->name = strdup(name);
ptr_newNode->id = id;
ptr_newNode->threat_level = threat_level;
ptr_newNode->next = *head_ref;
*head_ref = ptr_newNode;
return 0;
}
int buildLList(const char *filename) {
// have 3 char arrays. One for each name, id, threat level
char idLine[MAX_LINE_LENGTH];
char nameLine[MAX_LINE_LENGTH];
char threat_levelLine[MAX_LINE_LENGTH];
FILE *poiProfiles;
int count = 0;
poiProfiles = fopen(filename, "r");
if (poiProfiles == NULL) {
fprintf(stderr, "cannot open %s: %s\n", filename, strerror(errno));
return -1;
}
while (fgets(idLine, MAX_LINE_LENGTH, poiProfiles)
&& fgets(nameLine, MAX_LINE_LENGTH, poiProfiles)
&& fgets(threat_levelLine, MAX_LINE_LENGTH, poiProfiles)) {
long int id = atoi(idLine);
char *name = nameLine;
int threat_level = atoi(threat_levelLine);
if (!insert(&head, name, id, threat_level))
count++;
}
fclose(poiProfiles);
return count;
}
void print_list(const struct poi_t_struct *p) {
const struct poi_t_struct *temp = p;
while (temp != NULL) {
print_record(temp);
temp = temp->next;
}
}

Related

Dynamic list in C headache, printing list in reverse? Why?

I'm trying to learn how to work with dynamic lists in C, but can't seem to wrap my head around it - so help would be appreaciated. I've got a struct that has some info that i'm reading from a txt file in the command line and would need to add the info to a dynamic list..
this is what i have so far. I'm at a loss with pointers and don't know if the arguments are correct and where to go from there.
Have spent the better part of the weekend looking for a way to get this done. It isn't hard as I get the concept, just that the nuts and bolts of it are just eluding me...
#include <stdio.h>
#include <stdlib.h>
#define SIZE_MAX 20
#define BUFFER_MAX 256
FILE *file;
/*struct*/
struct student {
char name[SIZE_MAX];
int grade;
struct student *next;
};
typedef struct student Student;
int addToList(Student **head, char *, int);
void printList(Student **head);
void releaseMem(Student **head);
/*functions*/
void addToList(Student **head, char *name, int grade ){
//???
}
/*Main*/
int main (int argc, char *argv[]){
Student *head=NULL,*tail=NULL;
int grade = 100 ;
char buffer [BUFFER_MAX];
char name[SIZE_MAX];
/*opening file*/
file = fopen(argv[1], "r");
if (file == NULL){
printf("\n\tWARNING: No data found.\n");
exit(1);
}
else{
printf("Reading file %s \n",argv[1]);
}
/*creating first node*/
Student* new_student(Student*)malloc(sizeof(Student));
while(fgets(buffer, BUFFER_MAX,file)!= NULL){
sscanf(buffer,"%s%d",name,&grade);
//printf("%s %d\n",string, grade);
addToList(&head,name,grade);
}
return 0;
}
Edit: So far I've managed to add the data from the file to a dynamic list (thank you for the help). Here is what I have:
#include <stdio.h>
#include <stdlib.h>
#define SIZE_MAX 20
#define BUFFER_MAX 256
FILE *file;
/*Struct*/
struct student {
char name[SIZE_MAX];
int grade;
struct student *next;
};
typedef struct student Student;
int addToList(Student **head, char *, int);
void printList(Student *head);
void releaseMem(Student *head);
/*functions*/
int addToList(Student **head, char *name, int grade ){
Student *new_student = malloc( sizeof( Student ) );
{
Student *new_student = malloc( sizeof( Student ) );
int success = new_student != NULL;
if ( success )
{
strcpy( new_student->name, name );
new_student->grade = grade;
new_student->next = *head;
*head = new_student;
}
return success;
}
}
void printList(Student *head){
Student * current = head;
int i = 1;
while (current != NULL) {
printf("%d. Student: %s grade %d\n",i,current->name ,current->grade);
i++;
current = current->next;
}
}
void releaseMem(Student *head){
Student * current = head;
while (current != NULL) {
free(current);
current = current->next;
}
printf("mem cleared.\n");
}
/*Main*/
int main (int argc, char *argv[]){
Student *head=NULL,*first=NULL, *temp = NULL;
int grade = 100 ;
char buffer [BUFFER_MAX];
char name[SIZE_MAX];
/*opening file*/
file = fopen(argv[1], "r");
if (file == NULL){
printf("\n\tWARNING: No data found.\n");
exit(1);
}
else{
printf("reading file %s. \n",argv[1]);
}
printf("data added to list.\n");
while(fgets(buffer, BUFFER_MAX,file)!= NULL){
sscanf(buffer,"%s%d",name,&grade);
addToList(&head,name,grade);
}
printList(head);
releaseMem(head);
return 0;
}
Works (almost) like i'd like it to work. For some reason the printList function prints the content of the file in reverse order and after fiddling with it for some time I don't know how to print it from the beginning to the end instead from the end to the beginning. I suppose it has to do with pointers but more than that i'm at a loss what to do... What am I missing here? How would I go about reversing the printing order with keeping the (formatting) as it currently is?
you should allocate new students in the student list and place it to the last member's next like this :
//since we are adding new members after the last member in linked list
//we are not going to change value of head so sending **head is not useful
void addToList(Student *head,char *name,int grade){
Student *node;
for(node = head; node->next != NULL; node = node->next );
// now node points the last member of your linked list
// now we are adding new student to the linked list with allocating memory
node->next = (Student *)malloc(sizeof(student));
node->next->grade = grade;
strcpy(node->next->name,name);
}
The program will not compile at least because this statement
Student* new_student(Student*)malloc(sizeof(Student));
is invalid. And even if to write it like
Student* new_student = (Student*)malloc(sizeof(Student));
it does not make sense because new items should be added to the list by using the function addToList.
The declaration of the variable tail also does not make sense because it is impossible to pass it to the function (as it is declared) addToList along with the head.
As for the function itself then it is better to declare it the following way
int addToList( Student **head, const char *name, int grade );
The function can be defined like
int addToList( Student **head, const char *name, int grade )
{
Student *new_student = malloc( sizeof( Student ) );
int success = new_student != NULL;
if ( success )
{
strcpy( new_student->name, name );
// or
// strncpy( new_student->name, name, SIZE_MAX );
// new_student->name[SIZE_MAX - 1] = '\0';
new_student->grade = grade;
new_student->next = *head;
*head = new_student;
}
return success;
}

Trouble with Malloc and Linked List

I have a function that reads a text file filled with a word on every line. Here is an example of a text file I'm using
and
but
five
follows
four
has
is
like
line
lines
littlest
not
once
one
only
other
six
the
three
twice
two
word
words
Code:
typedef struct node node_t;
struct node {
char data[MAX_WORD];
int term;
node_t *next;
};
node_t *head;
int
int_struct(int lines){
FILE *fp;
char ch;
int n = 0, i, switch_num=1, test_first=0, test_first_2=0;
node_t *node, *curr_add;
fp = fopen("text.txt", "r");
node = (node_t*)malloc(sizeof(node_t));
for (i=1; i<=lines; i++){
switch_num = 1;
n=0;
if (test_first != 0){
if (test_first_2){
node = (node_t*)malloc(1000000);
}
test_first_2=1;
while ((ch = getc(fp)) != '\n'){
node -> term = i;
node -> data[n] = ch;
n++;
}
curr_add -> next = node;
curr_add = node;
}
else{
test_first = 1;
head = curr_add = node;
}
}
curr_add -> next = NULL;
fclose(fp);
return num;
}
What I want to do is to read each word and add it to a linked list.
However I am having trouble with malloc (at the moment I just add in a lot of bytes) and need advice on how to properly use it inside the function I have. I've done a general search and tried my best to try and do what most examples do. But I still can't seem to get my function working. For example, every time I execute the program it will read and add all the words into the linked list. However, the program crashes on the last word, and returns NULL. If anyone is able to point me in the right direction, I'd be very grateful.
Issues
There are no checks for return values. Particularly, fopen and malloc
may return NULL. If they do, you'll catch a segmentation fault error on the
first attempt to access the returned value.
Overcomplicated logic. You don't need these switch_num, test_first and test_first_2
variables (see sample code below).
No need in getc when you're reading a text file line-by-line - use
fgets instead.
Too many memory allocations. You don't need more than sizeof(node_t) + length of the line bytes per line.
The allocated memory is not freed. The dynamic memory should be freed as
soon as it is not needed.
Example using linked list
The following reads a text file into a linked list. Memory is allocated for
each list item, and for each line in the file resulting in n * 2 memory
allocations, where n is the number of lines in the file.
#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* strerror, strdup */
#include <errno.h>
typedef struct _node {
unsigned line;
char *data;
struct _node *next;
} node_t;
static void
destroy_list(node_t *list)
{
node_t *node;
for (node = list; node; node = node->next) {
if (node->data != NULL)
free(node->data);
free(node);
}
}
static node_t *
create_list_item(const char *data, unsigned line)
{
node_t *node = calloc(1, sizeof(node_t));
if (node == NULL) {
fprintf(stderr, "calloc: %s\n", strerror(errno));
} else {
node->line = line;
node->data = strdup(data);
if (node->data == NULL) {
fprintf(stderr, "strdup: %s\n", strerror(errno));
free(node);
node = NULL;
}
}
return node;
}
/* Returns pointer to new linked list */
static node_t *
read_file(FILE *fp, char *buf, size_t buf_len)
{
node_t *list = NULL;
node_t *prev = NULL;
node_t *node;
unsigned i;
for (i = 0; fgets(buf, buf_len, fp); prev = node) {
if ((node = create_list_item(buf, ++i)) == NULL) {
fprintf(stderr, "calloc: %s\n", strerror(errno));
break;
}
if (list == NULL)
list = node;
if (prev != NULL)
prev->next = node;
}
return list;
}
static void
print_list(const node_t *list)
{
const node_t *node;
for (node = list; node; node = node->next)
printf("%d: %s", node->line, node->data);
}
int main(int argc, char const* argv[])
{
const char *filename = "text.txt";
char buf[1024] = {0};
FILE *fp = NULL;
node_t *list = NULL;
if (NULL == (fp = fopen(filename, "r"))) {
fprintf(stderr, "failed to open file %s: %s\n",
filename, strerror(errno));
return 1;
}
list = read_file(fp, buf, sizeof(buf));
fclose(fp);
if (list) {
print_list(list);
destroy_list(list);
}
return 0;
}
Example using dynamic array
It is inefficient to allocate memory for each line (twice) in the file,
not only because the system calls (malloc, realloc, etc.) are costly,
but also because the items are placed non-contiguously. Accessing contiguous
region of memory is usually faster.
In the following code, the linked list is replaced with dynamic array. We
initialize memory for 10 lines at once. The size is increased as necessary.
#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* strerror, strdup */
#include <errno.h>
typedef struct _node {
size_t line;
char *data;
} node_t;
static void
destroy_array(node_t *array, size_t size)
{
size_t i;
node_t *item;
for (i = 0; i < size; i++) {
item = &array[i];
if (item->data)
free(item->data);
}
free(array);
}
static void
print_array(node_t *array, size_t size)
{
size_t i;
node_t *item;
for (i = 0; i < size; i++) {
item = &array[i];
if (item->data) {
printf("%ld: %s", item->line, item->data);
}
}
}
static node_t *
read_file(FILE *fp, char *buf, size_t buf_len,
const size_t array_step, size_t *array_size)
{
node_t *item;
node_t *array = calloc(array_step, sizeof(node_t));
size_t size = 0;
if (array == NULL) {
fprintf(stderr, "calloc:%s\n", strerror(errno));
return array;
}
while (fgets(buf, buf_len, fp)) {
if (size && size % array_step == 0) {
array = realloc(array, sizeof(node_t) * (array_step + size));
if (array == NULL) {
fprintf(stderr, "realloc:%s\n", strerror(errno));
break;
}
}
item = &array[size++];
item->line = size;
item->data = strdup(buf);
if (item->data == NULL) {
fprintf(stderr, "strdup: %s\n", strerror(errno));
break;
}
}
*array_size = size;
return array;
}
int main(int argc, char const* argv[])
{
node_t *array;
const size_t array_step = 10;
size_t array_size;
const char *filename = "text.txt";
char buf[1024] = {0};
FILE *fp = NULL;
if (NULL == (fp = fopen(filename, "r"))) {
fprintf(stderr, "failed to open file %s: %s\n",
filename, strerror(errno));
return 1;
}
array = read_file(fp, buf, sizeof(buf), array_step, &array_size);
fclose(fp);
if (array) {
print_array(array, array_size);
destroy_array(array, array_size);
}
return 0;
}
Note the changes in node_t structure.

Linked list won't print? C

So my assignment is to take in letters (6 per line) of a text file, save it into linked lists, and then print out the information of specific "die"(in this case) - which is each group of 6 letters.
I've got the data to read in correctly (I think) in the readData function, but am unsure if that linked list is getting passed correctly. When I try to print out the linked list in main (lines ~40-41) I get nothing. Am I passing my function incorrectly to readData?
Here's my code:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#define LENGTH 80
struct boggleDataNode {
char data[3];
struct boggleDataNode *nextData;
};
struct boggleDieSideNode{
char dieSideData[3];
struct boggleDieSideNode *nextSide;
};
void readData(struct boggleDataNode *temp);
void printData(struct boggleDataNode *temp);
int main() {
int counter = 0;
struct boggleDataNode *head;
struct boggleDieSideNode *head1;
struct boggleDataNode *temp;
head = NULL;
head1 = NULL;
temp = head;
printf("test\n\n");
readData(&temp);
// printData(temp);
while(counter = 0, counter<100, counter++)
printf("%s ", temp->data[counter]);
system("pause");
return 0;
}
void readData(struct boggleDataNode *temp) {
//initializing variables including
//opening the input file
FILE *input = fopen("BoggleData.txt","r");
char data[96] = {};
struct boggleDataNode *new;
int counter = 0;
temp = new;
//error checking that the file opened
if (input == NULL) {
fprintf(stderr, "Can't open input file!\n");
exit(1);
}
new = (struct boggleDataNode *)malloc(sizeof(struct boggleDataNode));
while (fscanf(input, "%s", data) != EOF) {
printf("%s ", data);
strcpy(temp->data, data);
printf("Data number %d %s \n",counter,temp->data);
temp->nextData = NULL;
counter++;
}
}
You are passing your structure incorrectly to readData. Your declare your variable like so:
struct boggleDataNode *temp;
You invoke readData thusly:
readData(&temp);
You declare readData as such:
void readData(struct boggleDataNode *temp){
So, you declare both temp and readData's input as struct boggleDataNode *, but you pass &temp to readData. & means you are sending the address of what follows, so &temp is a pointer to a pointer to a struct boggleDataNode, which is a struct boggleDataNode **.
There are other problems with your code, but that is beyond the scope of your question. I will point out that your output loop is very, very wrong.

All Nodes in a linked list point to same object

The problem is somewhere in here....
char buffer[80];
char *name;
while (1) {
fgets(buffer, 80, inf); //reads in at most 80 char from a line
if (feof(inf)) //this checks to see if the special EOF was read
break; //if so, break out of while and continue with your main
name = (char *) malloc(sizeof(char)*20);
....
name = strtok(buffer, " ");//get first token up to space
stock = newStock(name,...)
....
}
I'm working in C with generic linked lists. I made a list implementation that I've tested and know works with chars. I'm trying to add stocks (I created a stock struct) to the linked list, with each node of the linked list holding a stock struct, but when I finish reading in the stocks all of the nodes point to the same struct and I can't figure out why. Here's some snippets of my code
list *list = malloc(sizeof(list));
newList(list, sizeof(stock_t));
while(1) {
...
(read from file)
...
stock_t *stock;
stock = newStock(name, closes, opens, numshares, getPriceF, getTotalDollarAmountF,getPercentChangeF,toStringF);
addToBack(list, stock);
}
Here's the newStock function:
stock_t *newStock(char *name, float closingSharePrice, float openingSharePrice, int numberOfShares, getPrice getP, getTotalDollarAmount getTotal, getPercentChange getPercent, toString toStr) {
stock_t *stock = malloc(sizeof(stock));
stock->stockSymbol = name;
stock->closingSharePrice = closingSharePrice;
stock->openingSharePrice = openingSharePrice;
stock->numberOfShares = numberOfShares;
stock->getP = getP;
stock->getTotal = getTotal;
stock->getPercent = getPercent;
stock->toStr = toStr;
return stock;
}
In a way I see what's wrong. newStock returns a new pointer every time, but it always gets stored in the variable 'stock' which is what every node points to, so it's going to be equal to whatever the last pointer newStock returned was...but I don't see the way around this. I tried having newStock return just a stock_t, and doing addToBack(list, &stock), but that didn't solve the problem either.
Any help would be appreciated!
Here is some code from the list:
typedef struct node {
void *data;
struct node *next;
}node_t;
typedef struct {
int length;
int elementSize;
node_t *head;
node_t *tail;
} list;
void newList(list *list, int elementSize) {
assert(elementSize > 0);
list->length = 0;
list->elementSize = elementSize;
list->head = list->tail = NULL;
}
void addToBack(list *list, void *element) {
node_t *node = malloc(sizeof(node_t));
node->data = malloc(list->elementSize);
node->next = NULL; //back node
memcpy(node->data, element, list->elementSize);
if (list->length == 0) { //if first node added
list->head = list->tail = node;
}
else {
list->tail->next = node;
list->tail = node;
}
list->length++;
}
Here's code from the stock struct:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
typedef float (*getPrice)(void *S);
typedef float (*getTotalDollarAmount)(void *S);
typedef float (*getPercentChange)(void *S);
typedef char *(*toString)(void *S);
typedef struct stock{
char *stockSymbol;
float closingSharePrice;
float openingSharePrice;
int numberOfShares;
getPrice getP;
getTotalDollarAmount getTotal;
getPercentChange getPercent;
toString toStr;
}stock_t;
The generic functions probably seem like overkill but this is for homework (if you couldn't tell already) so we were asked to specifically use them. I don't think that has anything to do with the problem though.
Here are the definitions for those functions anyway
float getPriceF(void *S) {
stock_t *stock = (stock_t*)S;
return stock->closingSharePrice;
}
float getTotalDollarAmountF(void *S) {
stock_t *stock = (stock_t*)S;
return ((stock->closingSharePrice) * (stock->numberOfShares));
}
float getPercentChangeF(void *S) {
stock_t *stock = (stock_t*)S;
return ((stock->closingSharePrice - stock->openingSharePrice)/(stock->openingSharePrice));
}
char *toStringF(void *S) {
stock_t* stock = (stock_t*)S;
char *name = malloc(20*sizeof(char));
//sprintf(name, "Symbol is: %s. ", (stock->stockSymbol));
return stock->stockSymbol;
}
void printStock(void *S) {
char *str = toStringF(S);
printf("%s \n", str);
}
And this is how I'm traversing the list:
typedef void (*iterate)(void *); //this is in the list.h file, just putting it here to avoid confusion
void traverse(list *list, iterate iterator) {
assert(iterator != NULL);
node_t *current = list->head;
while (current != NULL) {
iterator(current->data);
current = current->next;
}
}
And then in my main I just called
traverse(list, printStock);
I can't find any problems with your code (that would cause your problem, anyway - there are places where you don't check the return from malloc() and stuff like that, but those are not relevant to this question). You don't supply the definition of stock_t, so I made a new data struct, and a new couple of functions, otherwise I just copied and pasted the code you provided:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
/* Your code starts here */
typedef struct node {
void *data;
struct node *next;
}node_t;
typedef struct {
int length;
int elementSize;
node_t *head;
node_t *tail;
} list;
void newList(list *list, int elementSize) {
assert(elementSize > 0);
list->length = 0;
list->elementSize = elementSize;
list->head = list->tail = NULL;
}
void addToBack(list *list, void *element) {
node_t *node = malloc(sizeof(node_t));
node->data = malloc(list->elementSize);
node->next = NULL; //back node
memcpy(node->data, element, list->elementSize);
if (list->length == 0) { //if first node added
list->head = list->tail = node;
}
else {
list->tail->next = node;
list->tail = node;
}
list->length++;
}
/* Your code ends here */
/* I made a new struct, rather than stock, since you didn't supply it */
struct mydata {
int num1;
int num2;
};
/* I use this instead of newStock(), but it works the same way */
struct mydata * newNode(const int a, const int b) {
struct mydata * newdata = malloc(sizeof *newdata);
if ( newdata == NULL ) {
fputs("Error allocating memory", stderr);
exit(EXIT_FAILURE);
}
newdata->num1 = a;
newdata->num2 = b;
return newdata;
}
/* I added this function to check the list is good */
void printList(list * list) {
struct node * node = list->head;
int n = 1;
while ( node ) {
struct mydata * data = node->data;
printf("%d: %d %d\n", n++, data->num1, data->num2);
node = node->next;
}
}
/* Main function */
int main(void) {
list *list = malloc(sizeof(list));
newList(list, sizeof(struct mydata));
struct mydata * data;
data = newNode(1, 2);
addToBack(list, data);
data = newNode(3, 4);
addToBack(list, data);
data = newNode(5, 6);
addToBack(list, data);
printList(list);
return 0;
}
which outputs this:
paul#MacBook:~/Documents/src$ ./list
1: 1 2
2: 3 4
3: 5 6
paul#MacBook:~/Documents/src$
demonstrating that you have a 3 node list, with all nodes different and where you'd expect them to be.
Either there is some other problem in code you're not showing, or for some reason you are thinking each node points to the same struct when it actually doesn't.
One possibility is that you have a char * data member in your stock struct. It's impossible to tell from the code you provided, but it's possible that you really are creating different nodes, but they all end up pointing to the same name, so they just look like they're the same. If you're assigning a pointer to name, you should make sure it's freshly allocated memory each time, and that you're not just, for instance, strcpy()ing into the same memory and assigning the same address to each stock struct.
EDIT: Looks like that was your problem. This:
name = (char *) malloc(sizeof(char)*20);
....
name = strtok(buffer, " ");
should be:
name = (char *) malloc(sizeof(char)*20);
....
strcpy(name, strtok(buffer, " "));
Right now, you malloc() new memory and store a reference to it in name, but then you lose that reference and your memory when you overwrite it with the address returned from strtok(). Instead, you need to copy that token into your newly allocated memory, as shown.

Not able to write information into linear linked list

The processFilefunction scans the information from the file correctly to p, however the addNodeLast function doesn't add the information from p to the linked list employees because it crashes.
Can someone help me fix the crashing, so that it will link each node together?
#include <stdio.h>
#include <stdlib.h>
#include "list.h"
void processFile(NODEPTR *employees, FILE *fp);
void outputPayFile(NODEPTR employees);
FILE *fp;
int main(void) {
NODEPTR employees;
if (fopen_s(&fp, "payfile2.txt", "r") != 0) {
printf("Failed to open payfile.txt for reading\n");
exit(0);
}
...missing code...
}
void processFile(NODEPTR *employees, FILE *fp) {
int i = 0;
NODEPTR p;
while(i < 5) {
printf("Entered Loop\n");
p = (NODEPTR) malloc(sizeof(node));
fscanf(fp, "%s %s %c %d %c %f\n", p->firstName, p->lastName, &(p->gender),
&(p->tenure), &(p->rate), &(p->rate), &(p->salary));
addNodeLast(employees, p);
i++;
}
}
In list.h:
void addNodeLast(NODEPTR *list, NODEPTR t) {
NODEPTR p;
if (*list == NULL)
*list = t;
else {
p = *list;
while (p->next)
p = p->next;
p->next = t;
}
}
Definition of NODEPTR:
typedef struct node {
char firstName[11];
char lastName[16];
char gender;
int tenure;
char rate;
float salary;
struct node *next;
} node, *NODEPTR;
You never initialise the next pointer. This is a common mistake. The call to malloc does not zero your memory. As a result, when you add a node to a non-empty list, you are likely to run straight off the end because the first node's next pointer could be non-null.
You need to at least do this:
p = malloc(sizeof(node));
if( p != NULL ) p->next = NULL;
You could consider using calloc, which does zero:
p = calloc(1, sizeof(node));

Resources