Linked list same value - c

I am trying to understand the linked list in C. So i am trying to write a program which will read from a file and create a linked list. But I hit a roadblock which I couldn't find a reason why.
Although I set the head value node *h to n only one time it looks like the value is automatically changing to the next value of n. To check I used printf at the end. All of them are returning the same result. Can anyone help please?
P.S - This is my first time using stackoverflow.
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
char *name;
struct node *next;
} node;
int main (void)
{
//load the file.
FILE *fp = fopen("dictionary.txt", "r");
if (fp == NULL)
{
printf("Unable to open the file\n");
}
char characters[45];
//initialize the linked list.
node *n , *t, *h;
int flag = 0;
while(fgets(characters, 45, fp) != NULL)
{
//define node for n
n = malloc(sizeof(node));
if (n == NULL)
{
printf("Out of memory!!!");
}
//set the value of n
n -> name = characters;
//set the temp & head value to n first time
if (flag == 0)
{
t = n;
h = n;
}
//set the temp -> next value to n after first time
else
{
t -> next = n;
}
flag = 1;
}
printf("%s\n", h -> name);
printf("%s\n", t -> name);
printf("%s\n", n -> name);
}

name member in your node struct is only a pointer to a string (character array).
each node you assign name to point to the very same character array:
char characters[45];
you should allocate the character array for any node:
#define MAX_LEN 45
typedef struct node
{
char name[MAX_LEN];
struct node *next;
} node;
and copy the string:
//set the value of n
strncpy(n -> name,characters, MAX_LEN);
// ensure null terminated
n->name[MAX_LEN-1] = '\0';

Related

how to take input from a text scanf and put it in linkedlist in C

i'm trying to take input from a text file and put the value in a linked list variables,
my file(text.txt) in in the following format:
the first value is my burst time, the second arrival and the last value is the priority, i want to make operations on all of these value from the same line like burst time + prioriy and so on, and when the operation for the first line ends up, the program should pass to the next line until the time the prom will fin the EOF.
now the big issue is when i'm trying to read each character and store each in a variable of a linked list for manipulation. find down my code:
#include <stdio.h>
#include <stdlib.h>
typedef struct Node{
int x;
struct Node* next;
}Node;
void insert_end(Node** root, int value)
{
Node* new_node = malloc(sizeof(Node));
if(new_node == NULL)
{
exit(1);
}
new_node->next = NULL;
new_node->x = value;
if(*root == NULL)
{
*root = new_node;
return;
}
Node* curr = *root;
while(curr->next != NULL)
{
curr = curr->next;
}
curr->next = new_node;
}
//the part i'm reading the file
void deserialize(Node** root)
{
FILE* file = fopen("text.txt","r");
if(file == NULL)
{
exit(2);
}
int val;
int val2;
while(fscanf(file, "%d", &val)>0)
{
insert_end(root, val);
}
fclose(file);
}
int main(int argc, char* argv[])
{
Node* root = NULL;
if(root == NULL)
{
exit(2);
}
root->x = 15;
root->next = NULL;
deserialize(&root);
for(Node* curr = root; curr != NULL; curr = curr->next)
{
printf("%d\n",curr->x);
}
deallocate(&root);
return 0;
}
i really need your help, thank you
A complete example including serialize() deserialize() and linked list functions are here after the "Now What?" paragraph
May be you could write this in 2 steps. First try to consume the data on file, then put the code to insert this into a linked list..
About the struct
typedef struct Node
{
int x;
struct Node* next;
} Node;
maybe not the best way to describe a linked list. This is just a node and not a list. You will be better served with a bit of encapsulation. A list has metadata and pointers to nodes. Nodes points to or contain data. A list is NOT a node. A node is NOT a list. Program a linked list with just a node is problematic at best. Many loose pointers and your case even more problematic Node** pointers.
Compare with something like
typedef struct
{
unsigned burst;
unsigned arrival;
unsigned priority;
} Info;
typedef struct st_node
{
Info* info;
struct st_node* next;
struct st_node* prev;
} Node;
typedef struct
{
Node* head;
Node* tail;
unsigned size;
} List;
List* create();
List* destroy(List* list);
int insert(Info* one_item, List* list);
And see that a list is a list of nodes. Nodes points to info and info is the unit of data. Any data.
insert() inserts an item into a list, create() and destroy() manages lists and the encapsulation makes everything far more easier than just using pointers and pointers to pointers.
Consuming the file
Using this file as input.txt
2:101:34
20:10:3
5:1:4
and this data unit
typedef struct
{
unsigned burst;
unsigned arrival;
unsigned priority;
} Info;
See that the input is a CSV --- from Comma Separated Values --- file, a format from '70s. The separator is a ':'.
scanf() and family was written for this: Scan Formatted Files, hence the name. It is a scanner. So it is easier to just use it in this way.
See this example
List* deserialize(const char* file)
{
FILE* in = fopen(file, "r");
if (in == NULL) return NULL;
Info info = {0};
List* new_l = create(); // new list here
while (3 == fscanf(
in, "%d:%d:%d", &info.arrival,
&info.burst, &info.priority))
{
fprintf(
stderr, "%d:%d:%d\n", info.arrival, info.burst,
info.priority);
insert(&info, new_l); // insert data into list
};
fclose(in);
return new_l; // returns a list with the data on file
}
and the output
2:101:34
20:10:3
5:1:4
when called as
List* new_list = deserialize("input.txt");
as expected. And a List is returned with the data on file...
The complete code
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
unsigned burst;
unsigned arrival;
unsigned priority;
} Info;
typedef struct st_node
{
Info* info;
struct st_node* next;
struct st_node* prev;
} Node;
typedef struct
{
Node* head;
Node* tail;
unsigned size;
} List;
int insert(Info* one_item, List* list);
List* create();
List* destroy(List*);
List* deserialize(const char* file)
{
FILE* in = fopen(file, "r");
if (in == NULL) return NULL;
Info info = {};
List* new_l = create(); // new list here
while (3 == fscanf(
in, "%d:%d:%d", &info.arrival,
&info.burst, &info.priority))
{
fprintf(
stderr, "%d:%d:%d\n", info.arrival, info.burst,
info.priority);
insert(&info, new_l); // insert data into list
};
fclose(in);
return new_l; // returns a list with the data on file
}
int main(void)
{
List* new_list = deserialize("input.txt");
new_list = destroy(new_list);
return 0;
}
int insert(Info* one_item, List* list) { return 0; }
List* create()
{
List* L = (List*)malloc(sizeof(List));
if (L == NULL) return NULL;
L->size = 0;
L->head = NULL;
L->tail = NULL;
return L;
}
List* destroy(List* list) { return NULL; }
Now what?
Now we have
List* deserialize(const char* file)
that can consume the data from a file like this
input.txt:
3:2:1
6:4:2
12:8:3
24:16:4
by using
List* new_list = deserialize("input.txt");
But deserialize() just prints the data on stderr
We want a linked list of the dataset.
I will write an example below, but step by step in order to cover other cases for other readers.
A linked list
I will add a sequence number to the nodes just to help in testing.
The linked list has nothing to do with our problem, or else we will need one implementation of linked list for every program in life. In fact would be great if the code for the list was in another source code file, in order to be used anywhere else.
this is the example for List
typedef struct st_node
{
int num;
Info* info;
struct st_node* next;
struct st_node* prev;
} Node;
typedef struct
{
size_t size;
Node* head;
Node* tail;
} List;
A list of nodes, nodes pointing to info.
info is from now on
// info is the thing in the list
typedef struct
{
unsigned burst;
unsigned arrival;
unsigned priority;
unsigned seq; // sequence number for testing
} Info;
// this is a helper to format a single node listing
int show_i(Info*, const char*);
The code for show_i() is simple
int show_i(Info* info, const char* msg)
{
if (info == NULL) return -1;
if (msg != NULL) printf("%s", msg);
printf(
"#%4d: B:%4d A:%4d P:%4d\n", info->seq, info->burst,
info->arrival, info->priority);
return 0;
}
And the reason for this to exist is to provided some encapsulation on the way the nodes are printed.
And the functions we will use here are the obvious ones:
List* create_l();
List* destroy_l(List*);
int empty(List*);
int insert_n(Info*, List*);
int remove_n(List*);
int show_l(List*, const char*);
int size(List*);
This is a very simple example so we will assume a standard queue, FIFO (First In First Out) one, with items added at the end and removed from the front.
empty() returns 1 if the list is empty
size() returns the expected size
show_l() shows the list contents with an optional title message
the other functions work as expected.
A simple C implementation of the linked list
Functions have no more than 10 to 15 lines
List* destroy_l(List* L)
{
if (L == NULL) return NULL;
Node* p = L->head;
for (size_t i = 0; i < L->size; i += 1)
{ // remove one by one
Node* nx = p->next;
free(p->info); // free data
free(p); // free node
p = nx;
}; // for
free(L); // free list
return NULL; // to invalidate pointer
}
int empty(List* L)
{
if (L == NULL) return 0;
return (L->size == 0);
}
List* create_l()
{
List* nv = (List*)malloc(sizeof(List));
if (nv == NULL) return NULL;
nv->size = 0; // vazia
nv->head = NULL;
nv->tail = NULL;
return nv;
}
int insert_n(Info* info, List* L)
{ // inserts at the end of list
static unsigned seq = 1000;
if (L == NULL) return -1;
// new node here
Node* nv = (Node*)malloc(sizeof(Node));
// new data here: always copy
nv->info = (Info*)malloc(sizeof(Info));
*(nv->info) = *info;
nv->info->seq = seq++; // USN
nv->prev = L->tail;
nv->next = NULL;
// ajusta os ponteiros da lista
L->size += 1; // conta o novo
if (L->size == 1)
L->head = nv;
else { L->tail->next = nv; }
L->tail = nv;
return (int)L->size;
}
int remove_n(List* L)
{ // remove from start
if (L == NULL) return -1;
if (L->size == 0) return -2;
Node* p = L->head->next;
free(L->head->info); // data
free(L->head); // node
L->head = p;
L->size -= 1;
if (L->size == 0) L->tail = NULL;
return (int)L->size;
}
int show_l(List* L, const char* tit)
{
if (L == NULL) return -1;
if (tit != NULL) printf("%s", tit);
if (L->size == 0)
printf(" no elements\n");
else
printf(" %zd elements:\n", L->size);
if (L->head != NULL)
printf(" [First seq: %d", L->head->info->seq);
if (L->tail != NULL)
printf(" Last seq: %d]\n", L->tail->info->seq);
Node* p = L->head;
for (size_t i = 0; i < L->size; i += 1)
{
show_i(p->info, "\t");
p = p->next;
}
printf("\n");
return 0;
}
int size(List* L)
{
if (L == NULL) return 0;
return (int)L->size;
}
A test program for the list code
#include <stdio.h>
#include "v2-l.h"
int main(void)
{
Info info = {1, 1, 1, 1};
List* my_list = create_l();
show_l(my_list, "empty list...\n");
my_list = destroy_l(my_list);
my_list = create_l();
// test size
const int test_size = 3;
printf("[Testing with %d elements]\n\n\n", test_size);
for (int i = 0; i < test_size; i += 1)
{
info.priority = i; // just for testing
insert_n(&info, my_list);
};
char message[] = "NNNNNN elements inserted\n";
sprintf(message, "%d elements inserted\n", test_size);
show_l(my_list, message);
int res = 0;
while (res >= 0)
{
printf("\tabout to remove 1st element:\n");
res = remove_n(my_list);
printf(
"\
\tremove_l() returned %d\n\
\tsize() returned %d\n\
\tempty() returned %d\n",
res, size(my_list), empty(my_list));
show_l(my_list, "\n ==> List now:\n");
if (res < 0) break;
}; // while()
show_l(my_list, "On exit\n");
my_list = destroy_l(my_list);
return 0;
}
The idea: creates a list with test_size elements and then remove one by one until error, calling the functions. Then the list is destroyed.
output from test
empty list...
no elements
[Testing with 3 elements]
3 elements inserted
3 elements:
[First seq: 1000 Last seq: 1002]
#1000: B: 1 A: 1 P: 0
#1001: B: 1 A: 1 P: 1
#1002: B: 1 A: 1 P: 2
about to remove 1st element:
remove_l() returned 2
size() returned 2
empty() returned 0
==> List now:
2 elements:
[First seq: 1001 Last seq: 1002]
#1001: B: 1 A: 1 P: 1
#1002: B: 1 A: 1 P: 2
about to remove 1st element:
remove_l() returned 1
size() returned 1
empty() returned 0
==> List now:
1 elements:
[First seq: 1002 Last seq: 1002]
#1002: B: 1 A: 1 P: 2
about to remove 1st element:
remove_l() returned 0
size() returned 0
empty() returned 1
==> List now:
no elements
about to remove 1st element:
remove_l() returned -2
size() returned 0
empty() returned 1
==> List now:
no elements
On exit
no elements
Using the list on the original program
// here goes the program target
List* deserialize(const char* file);
int serialize(List* list, const char* file);
double pri_avg(List*);
The next obvious step is to use the 1st program and consume the file, but this time writing the data into a linked list, and then calling serialize() to create a new file with the data in the list.
Sure, both files must have the same data and the program will test itself.
As you asked, #jonathan pascal, the function pri_avg() computes an useless priority average, just to show how to compute something using the data from all nodes in the list.
Note that this is the same logic as in showing the list contents in show_l(). This is called a filter and in languages like C we can just pass a function address to a function that loops over the code, and use the same code to do anything with the dataset. In C++ is, for example, a for_each() function that does just this. All these functions here has the same logic.
Example implementation of the 3 functions
List* deserialize(const char* file)
{
FILE* in = fopen(file, "r");
if (in == NULL) return NULL;
Info info = {0};
List* new_l = create_l(); // new list here
while (3 == fscanf(
in, "%d:%d:%d", &info.burst,
&info.arrival, &info.priority))
{
// fprintf(
// stderr, "%d:%d:%d\n", info.arrival,
// info.burst, info.priority);
insert_n(&info, new_l); // insert data into list
};
fclose(in);
return new_l; // returns a list with the data on file
};
int serialize(List* L, const char* file)
{
if (L == NULL) return -1;
if (file == NULL)
{
printf("Missing file name\n");
return -2;
}
if (L->size == 0)
{
printf("Dataset is empty\n");
return -3;
}
FILE* out = fopen(file, "w");
if (out == NULL) return -3;
fprintf(
stderr,
"serialize(): writing %d elements into \"%s\"\n",
size(L), file);
Node* p = L->head;
for (size_t i = 0; i < L->size; i += 1)
{
fprintf(
out, "%d:%d:%d\n", p->info->burst,
p->info->arrival, p->info->priority);
p = p->next;
}
fprintf(out, "\n");
fclose(out);
fprintf(stderr, "\"%s\" closed\n", file);
return 0;
}
// get the priority average from the list
double pri_avg(List* L)
{
if (L == NULL) return -1;
if (L->size == 0) return 0.; // easy
double avg = 0.;
Node* p = L->head;
for (size_t i = 0; i < L->size; i += 1)
{ // here we have node data, one
// at a time
avg = avg + p->info->priority;
p = p->next;
};
return (double)avg / size(L);
}
Testing the 3 functions
#include <stdio.h>
#include "v2-l.h"
int main(void)
{
const char* in_file = "input.txt";
printf(
"deserialize(): building list from \"%s\"\n",
in_file);
List* my_list = deserialize(in_file);
show_l(my_list, " ==> As read from file...\n");
printf("average priority is %6.2f\n", pri_avg(my_list));
const char* out_file = "another.txt";
int res = serialize(my_list, out_file);
printf(
"serialize(): dumping list into \"%s\" "
"returned %d\n",
out_file, res);
my_list = destroy_l(my_list);
return 0;
}
And we have full circle over the problem: a CSV file is read from disk, a linked list is built, some values are computed, the list is written to disk in another file.
test output
deserialize(): building list from "input.txt"
==> As read from file...
4 elements:
[First seq: 1000 Last seq: 1003]
#1000: B: 3 A: 2 P: 1
#1001: B: 6 A: 4 P: 2
#1002: B: 12 A: 8 P: 3
#1003: B: 24 A: 16 P: 4
average priority is 2.50
serialize(): writing 4 elements into "another.txt"
"another.txt" closed
serialize(): dumping list into "another.txt" returned 0
The format string %d does not match the input :101 ,since : cannot be part of an integer. So scanf("%d") consumes nothing and the : is left in the input stream. You could use: while(fscanf(file, "%4d:", &val) == 1). If you are reading the last value on a line, the : will not match, but in this case you don't care. You might want to use fscanf(file, "%4d:%4d:%4d", ...) == 3 if you want to check the format of the input (ie, always exactly 3 inputs per line, so you can reject lines like 1:2:3:4:5:6:7). YMMV

Array of linked lists added to from directory

I've been trying to create an array of linked lists. The array being size 26 each part corresponding to a letter of the alphabet. The user inputs a directory of the PC and the name of any folders or files in that directory are then added to the a linked list in the array based on what letter they start with.
How i've been trying to do it->
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <stdlib.h>
My node and its declaration:
struct node{
char data[50];
struct node *next;
};
struct node* nodeArray[26];
My alphabet:
const char* basis[26] = {"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"};
A string comparing function to check which linkedlist in the array my word goes(compares to alphabet)
int StartsWith(const char *a, const char *b)
{
if(strncasecmp(a, b, strlen(b)) == 0) return 1;
return 0;
}
Where I add the node and also where the problem is(the printf("1") is there to stop my computer from basically crashing):
void addNode(struct node **q,const char *d){
if(((*q)->data)==NULL){
*q = malloc(sizeof(struct node));
strncpy((*q)->data,d,50);
(*q)->next = NULL;
} else {
(*q)->next = malloc(sizeof(struct node));
*q = (*q)->next;
printf("1");
addNode(q,d);
}
}
The function that calls addNode, directory is a computer directory that's already been checked to exist:
void returner(char* directory){
int i;
DIR *dp;
struct dirent *ep;
char* tempD;
dp = opendir (directory);
struct node **z;
while ((ep = readdir(dp))){
tempD = (char*)malloc(50);
if ( !strcmp(ep->d_name, ".") || !strcmp(ep->d_name, "..") ){
} else {
strncpy(tempD, ep->d_name, 50);
for(i=0; i<26 ; i++){
if(StartsWith(tempD, basis[i])){
z = &nodeArray[i];
addNode(z,tempD);
print();
}
}
}
free(tempD);
}
closedir (dp);
}
Print function:
void print(){
int i;
struct node *temp;
for(i=0 ; i < 26; i++){
temp = malloc(sizeof(struct node));
temp = nodeArray[i];
while(temp != NULL){
printf("%s\n",temp->data);
temp = temp->next;
}
}
}
The program seems fine when adding the first node to a spot on the array such as "aaa.txt" "bbb.txt" "ccc.txt" "ddd.txt", but once a second is attempted to be added like a "ccd.txt" after a "ccc.txt" exists when it keeps going forever or until the pc crashes
You're not checking the right value in your addNode for finding the list insertion point.
Pointer-to-pointer enumeration through a linked list is frequently used to walk from the head pointer to the last next pointer in the list, each time holding the address of the said-pointer. When you reach one that is NULL (which will be head in the case of an empty list), you stop, and you can use your pointer-to-pointer via dereference to assign your new node address.
If you want to insert on the tail, the way to do it would be something like this:
#define DATA_MAX_LEN 50
void addNode(struct node **q,const char *d)
{
// assumes a null-terminated linked list
while (*q)
q = &(*q)->next;
*q = malloc( sizeof **q );
// ensures truncation and termination
strncpy((*q)->data,d,DATA_MAX_LEN-1);
(*q)->data[ DATA_MAX_LEN-1] = 0;
// make sure we terminate the list at our new node
(*q)->next = NULL;
}
Invoked from your updated returner function like this:
void returner(char* directory)
{
DIR *dp = opendir (directory);
if (dp)
{
struct dirent *ep;
while ((ep = readdir(dp)))
{
// skip parent and self symbolic links
if (ep->d_name[0] == '.' && (ep->d_name[1] == 0 || (ep->d_name[1] == '.' && ep->d_name[2] == 0)))
continue;
for(int i=0; i<26 ; i++)
{
if(StartsWith(ep->d_name, basis[i]))
addNode(nodeArray+i, ep->d_name);
}
}
closedir (dp);
}
}

Creating Dynamically Allocated Strings from a file in C

I am having some issues with dynamically allocating a string for a node in a tree. I have included my node structure below for reference.
struct node
{
char *string;
struct node *left;
struct node *right;
};
typedef struct node node;
I am supposed to read words from a text file and then store those words into a tree. I am able to store char arrays that have been defined, such as char string[20] without problems, but not strings that are supposed to be dynamically allocated.
I am only going to post the code I am using to read my file and try to create the dynamically allocated array. I have already created the file pointer and checked that it is not NULL. Every time I try to run the program, it simply crashes, do I need to try and read the words character by character?
//IN MAIN
node *p, *root ;
int i;
int u;
root = NULL;
char input[100];
while(fscanf(fp, "%s", &input) != EOF)
{
//Create the node to insert into the tree
p = (node *)malloc(sizeof(node));
p->left = p->right = NULL;
int p = strlen(input); //get the length of the read string
char *temp = (char*) malloc(sizeof(char)*p);
//malloc a dynamic string of only the length needed
strcpy(local, input);
strcpy(p->word,local);
insert(&root, p);
}
To be completely clear, I only want advice regarding the logic of my code, and only would like someone to help point me in the right direction.
You are invoking many undefined behaviors by
passing pointer to object having wrong type to scanf(). i.e. In fscanf(ifp, "%s", &input), char(*)[100] is passed where char* is expected
accessing out-of-range of allocated buffer when storeing terminating null-character in strcpy(local, input);
using value of buffer allocated via malloc() and not initialized in strcpy(curr->word,local);
Your code should be like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
typedef struct node_t {
struct node_t* left, *right;
int count;
char* word;
} node;
void insert(node ** tree, node * item);
int main(void) {
FILE* ifp = stdin;
node * curr, * root;
int i;
int u;
root = NULL;
char input[100];
/* you should specify the maximum length to read in order to avoid buffer overrun */
while(fscanf(ifp, "%99s", input) != EOF)
{
//Create the node to insert into the tree
curr = malloc(sizeof(node));
if(curr == NULL) /* add error check */
{
perror("malloc 1");
return 1;
}
curr->left = curr->right = NULL;
curr->count = 1;
int p = strlen(input); //get the length of the read string
char *local = malloc(sizeof(char)*(p + 1)); /* make room for terminating null-character */
if (local == NULL) /* add error check again */
{
perror("malloc 2");
return 1;
}
//malloc a dynamic string of only the length needed
//To lowercase, so Job and job is considered the same word
/* using strlen() in loop condition is not a good idea.
* you have already calculated it, so use it. */
for(u = 0; u < p; u++)
{
/* cast to unsigned char in order to avoid undefined behavior
* for passing out-of-range value */
input[u] = tolower((unsigned char)input[u]);
}
strcpy(local, input);
curr->word = local; /* do not use strcpy, just assign */
insert(&root, curr);
}
/* code to free what is allocated will be here */
return 0;
}
//Separate insert function
void insert(node ** tree, node * item)
{
if(!(*tree))
{
*tree = item;
return;
}
if(strcmp(item->word,(*tree)->word) < 0)
insert(&(*tree)->left, item);
else if(strcmp(item->word,(*tree)->word) > 0)
insert(&(*tree)->right, item);
/* note: memory leak may occur if the word read is same as what is previously read */
}

Circular Doubly Linked List, Print Function

I need to create a circular doubly linked list with a sentinel node which is supposed to read data from a file and insert it in the list, than perform some operations with it. For now I'm stuck on a simple print function which won't print from a list for some reason. The data in the file is in the form of strings,
example: "Popular Sorting Algorithms,
Bubble Sort, Merge Sort, "empty line", etc
Here is my code so far:
Header file contains:
typedef struct NODE {
struct NODE *prev;
char *value;
struct NODE *next;
} NODE;
typedef struct LIST {
int count;
struct NODE *next;
struct NODE *prev;
} LIST;
int InsertEnd(NODE *head, char * value, int *lineCount);
void printLines(int *lineCount);
void Traverse(NODE *head);
Main contains:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include "header.h"
int main()
{
int lineCount = 0;
NODE *head;
head = (NODE *)malloc(sizeof(NODE)); /* creates head node dynamically */
head->next = NULL; /* points to first element */
head->prev = NULL; /* points to last element */
head->value = "HEAD"; /* not needed, but it was pretty useful when debugging */
//*********BEGIN OF OPEN FILE FUNCTION
FILE* fp;
char *fname = NULL;
fname = (char *)malloc(200); <<<<<===== I would prefer to set the size dynamically adjusting but I dont know how
printf("Reading file input.txt\n");
//Checks if the file us unable to be opened, then it shows the error message
if ( !(fp = fopen("input.txt", "r")))
{
printf("\nError, Unable to open the file for reading \n");
exit(100);
}
//*********BEGIN OF READ FROM FILE FUNCTION
while (!feof(fp))
{
fgets(fname, 150, fp); //reads the file and stores in buffer
fname[strlen(fname) - 1] = '\0'; // reduces empty strings for input
if (fname != '\0')
{
InsertEnd(head, fname, &lineCount);
//printf("%s\n", head->next->value); <<<<==== If uncomment this print function would work properly but only in this context
}
else
{
printf("Error'\n"); // For debugging
}
}
Traverse(head); // Print Function Should Be Working in Here
printf("Debugging print\n");
printLines(&lineCount); // Shows Line Count
return 0;
}
// Function inserts a new node at the end of the LIST
int InsertEnd(NODE *head, char * value, int* lineCount)
{
int lineCounter = *lineCount;
/* create new node */
NODE *newnode;
newnode = (struct NODE *)malloc(sizeof( struct NODE));
newnode->value = value;
/* placing new node in LIST */
if (head->next == NULL) /* LIST was empty */
{
newnode->next = head;
newnode->prev = head;
head->next = newnode;
head->prev = newnode;
lineCounter++; // Increment line counter
}
else /* LIST wasn't empty */
{
newnode->next = head;
newnode->prev = head->prev;
head->prev->next = newnode; /* adjust node that was previously last */
head->prev = newnode; /* adjust head node */
lineCounter++; // Increment line counter
}
*lineCount = lineCounter;
return lineCount;
}
// This function prints how many lines there are in the LIST, but I need to get rid of the empty spaces
void printLines(int *lineCount)
{
printf("Line counter is %d", *lineCount); // Shows the number of lines, but doesn't skip empty ones.
}
void Traverse(NODE *head)
{
NODE *current = head;
printf("Forward:");
while (current!= head->prev)
{
printf("%s \n", current->value);
current = current->next;
}
printf("\n");
}
Therefore, I have several problems so far:
1) I need to get rid of empty strings in my list most likely. What would be a better approach, to get rid of them while reading or just not displaying when printing? How would I do this exactly?
2) How can I fix my print(traverse) function and whats wrong there?
3) Additionally all of this should be going on through the menu manager which would prompt for a command ( I got this right I think). But there are some functions that I don't know how to implement. For example when used hits "I" it should call Insert functions and prompt the user to enter two more values and , and later insert at the appropriate . How would I do that? Example "I 1 8"
4) Similarly to the previous one, there should be List function which should print lines between specific values. User input format should be "L to " list inclusively. Example "L 2 5"
5) Similarly to previous there should be a delete function with the format "D " inclusively. Example "D 3 7"
6) And the very last is the Save function in the format "S " Example "S output.txt"
Thank You for the help!
I see at least these issues in your code,
In main()
if (fname != '\0')
this should be
if (fname[0] != '\0')
In InsertEnd()
newnode->value = value;
should be
newnode->value = strdup(value);
In you code there should be some correctness which is very help full first as per your request you need to allocate buffer dynamically but not know file length so it can be achived by this one
int sz;
printf("Reading file input.txt\n");
//Checks if the file us unable to be opened, then it shows the error message
if ( !(fp = fopen("sample.txt", "r")))
{
printf("\nError, Unable to open the file for reading \n");
exit(100);
}
fseek(fp, 0L, SEEK_END);
sz = ftell(fp);
printf("size of file %d\n",sz);
fname = (char *)malloc(sz);
rewind(fp);
Now for reading content from file you checked fname to \0 which is not correct i corrected your while..loop.
while (!feof(fp))
{
if(fgets(fname,256, fp) != 0)
{
fname[strlen(fname) - 1] = '\0'; // reduces empty strings for input
InsertEnd(head, fname, &lineCount);
}
else
{
printf("Error'\n"); // For debugging
}
}

Linked list in C, is the list being constructed correctly?

I'm trying to implement a linked list abstraction, however I am running into problems. Once I create the linked list and add elements to it. When I print the list it only prints the first element in it in an infinite loop fashion, meaning that either the first element is linked to itself or the print function is incorrect. However, I can't find the problem, could someone help?
The following is the list abstraction:
typedef struct _friend {
char *firstname;
char *lastname;
char birthdate[9];
} friend;
typedef struct _node {
friend *value;
struct _node *next;
} node;
typedef struct _linkedlist {
node *head;
} linkedlist;
The program must follow this abstraction, as it is part of something bigger.
The following are the functions that should print the list and add a node to the beginning of the list:
/* addHead
*
* This function takes two parameters - a linked list and a friend.
* This creates a node for the linked list and connects the friend to the
* node. Then it adds the node to the head of the linked list.
*/
void addHead(linkedlist *llist, friend *f)
{
// create a node and put the friend in it
node *n = (node *)malloc(sizeof(node));
n->value = f;
n->next = NULL;
// if the list is empty
if (llist == NULL)
{
// this link is the entire list
llist->head = n;
printf("adding friend to null list\n");
}
// if the list is not empty
else
{
// make the new link's next pointer point to
// the first link in the list
n->next = llist->head;
printf("adding %s to head\n", n->value->firstname);
// make the head pointer point to the new link
llist->head = n;
}
}
/*
* printList
*
* This steps down through each of the nodes in a linked list and
* prints out the information stored in the friend to which the node points.
* Instead of automatically printing to the screen, it prints to the
* file pointer passed in. If the programmer wants to print to the screen,
* he/she will pass in stdout.
*/
void printList(linkedlist *llist,FILE *fp)
{
node *n;
friend *f;
// for each node, print out the friend attached to it
for(n = llist->head; n != NULL ; n = llist->head->next)
{
// assign f to the friend of the right node
f = n->value;
// print the friend out
fprintf(fp,"%s %s: %s\n",
f->firstname, f->lastname, f->birthdate);
}
}
Thank You
The for loop in printList isn't quite right:
for(n = llist->head; n != NULL ; n = llist->head->next)
This should read:
for(n = llist->head; n != NULL ; n = n->next)
Otherwise from the second iteration onwards, n gets set to the same value every single time.
The following isn't related to the problem you're having, but I thought I'd mention it anyway. In the following code:
if (llist == NULL)
{
// this link is the entire list
llist->head = n;
printf("adding friend to null list\n");
}
if llist == NULL, the llist->head = n will segfault.
With the current signature of addHead(), there's not a lot you can do if llist is NULL (other than printing an error message and bailing out).
If instead you meant to check whether llist->head is NULL, you don't need to do that since the else block already handles that correctly.
Try:
void printList(linkedlist *llist,FILE *fp)
{
node *n;
friend *f;
// for each node, print out the friend attached to it
for(n = llist->head; n != NULL ; n = n->next)
{
// assign f to the friend of the right node
f = n->value;
// print the friend out
fprintf(fp,"%s %s: %s\n",
f->firstname, f->lastname, f->birthdate);
}
}
I have done the following to your program:
slightly modified the friend structure. Declared firstname and lastname as arrays for convenience.
Wrote a main() which calls other functions
error checking in addHead()
added create_friend() function which creates friend struct
added freeList() to release the memory which was malloc()'ed
corrected looping error in your print function
So here it goes..
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct _friend {
char firstname[10];
char lastname[10];
char birthdate[9];
} friend;
typedef struct _node {
friend *value;
struct _node *next;
} node;
typedef struct _linkedlist {
node *head;
} linkedlist;
void addHead(linkedlist *llist, friend *f)
{
node *n = NULL;
if (( n = (node *)malloc(sizeof(node))) == NULL) {
printf("unable to allocate memory \n");
exit(1);
}
n->value = f;
n->next = NULL;
if (llist == NULL) {
llist->head = n;
printf("adding friend to null list\n");
} else {
n->next = llist->head;
printf("adding %s to head\n", n->value->firstname);
llist->head = n;
}
return;
}
void printList(linkedlist *llist)
{
node *n;
friend *f;
if (llist->head == NULL) {
printf("Empty list \n");
return;
}
for(n = llist->head; n != NULL ; n = n->next) {
f = n->value;
printf("%s %s %d \n", f->firstname, f->lastname, f->birthdate);
}
return;
}
friend * create_friend(char *fn, char *ln, char *dob)
{
friend *fp = NULL;
if ((fp = malloc(sizeof(friend))) == NULL) {
printf("unable to allocate memory \n");
exit(1);
}
strcpy(fp->firstname, fn);
strcpy(fp->lastname, ln);
strcpy(fp->birthdate, dob);
return fp;
}
void freeList(linkedlist *llist)
{
node *cur = llist->head;
node *prev = cur;
friend *f;
while (cur != NULL) {
prev = cur;
cur = cur->next;
f = prev->value;
printf("freeing .. %s %s %d \n", f->firstname, f->lastname, f->birthdate);
free(prev->value);
free(prev);
}
return;
}
int main(void)
{
linkedlist ll;
friend *f;
ll.head = NULL;
f = create_friend("firstname1", "lastname1", "12345678");
addHead(&ll, f);
f = create_friend("firstname2", "lastname2", "12345678");
addHead(&ll, f);
f = create_friend("firstname3", "lastname3", "12345678");
addHead(&ll, f);
printList(&ll);
freeList(&ll);
ll.head = NULL;
printList(&ll);
return 0;
}
Hope this helps!
Should be n = n ->next otherwise you're just getting the next of the head every time.

Resources