Can't create singly linked list - c

I have an issue creating linked list: I don't know where I do an error in code, could you help me? Here's the code:
#include <stdio.h>
#include <stdlib.h>
#define LENGTH 255
struct node {
int info;
struct node *next;
} *head = NULL;
int create(FILE **data){
char read[LENGTH];
printf("Write data file name: ");
scanf("%s", read);
*data = fopen (read, "r");
if (data == NULL) {
printf("Error reading given file.");
}
return 0;
}
int put_Symbols_into_list(FILE *data) {
struct node *new_node, *current;
char c;
printf("Data given: ");
while (!feof(data)){
new_node = (struct node*)malloc(sizeof (struct node));
c = fscanf(data, "%s", &new_node -> info);
printf("%s ", &new_node -> info);
if (head == NULL){
head = new_node;
current = new_node;
} else {
current -> next = new_node;
current = new_node;
}
}
}
int main() {
FILE *data;
struct node *n;
create(&data);
put_Symbols_into_list(data);
//display_List(n);
return 0;
}
Steps that I do: Read data file for string and put it new node; if HEAD node doesn't have any data in it, put the read data in it; else put it in new node. Cycle this until there is not data left in data file. You can create new data file and put data in there, like 1 0 1 1 2 3 4 5 6.

You are not putting current->next to NULL after adding a new node. That will make a problem when you try to go through a list, since you won't know where it ends. I hope that's the problem that you're facing with.
Also you're having redundant code, since current will always point to new_node after adding it. So you don't have to put it both in if and else block. Just an advice.

You forgot to make the last node point to NULL. This will be extremely important when you try to traverse your list and display it.
int put_Symbols_into_list(FILE *data)
{
struct node *new_node, *current;
char c;
printf("Data given: ");
while (!feof(data)){
new_node = (struct node*)malloc(sizeof (struct node));
c = fscanf(data, "%d", &new_node -> info);
printf("%d ", new_node->info);
if (head == NULL){
head = new_node;
current = new_node;
} else {
current->next = new_node;
current = new_node;
new_node->next = NULL; // << added
}
}
return 0;
}

In addition to the answers above, you are declaring current as a local variable in put_Symbols_into_list, and not initializing current. Each time you exit put_Symbols_into_list, the value of current may be lost. You either need to declare current as static struct node *current, pass it as a parameter, or declare it globally. I would favor the static approach in this setting.

Related

C linked list problem, segfault when printing the list to a file

I'm trying to write and use linked list. When trying to print the list to the file the first string gets chained to the last node and it causes a segfault.
I've tried debugging and it led me nowhere.
It only happens using printListToFile(...) and readstl(...).
The code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lists_c.h"
#define test "ijm digidimdimadam jjsklva /s4t\t \nmjam \nla kookaracha la kookaracha\n"
/*a method that creates a "blank" node, declares a the next node and points it to NULL, the char array is already initialized.*/
struct Node *makeNode();
struct Node *makeFullNode(struct Node *Next, char *Ptr);
struct Node *readFile(char *path);
struct Node *readstl(char*);
void printList(struct Node *head);
void insertToList(struct Node *node, char *str);
void printListToFile(char *path, struct Node *head);
int main(int argc, char *argv[])
{
struct Node *head;
head = (struct Node *)malloc(sizeof(struct Node));
printf("this is mmn 23 Q3, a func that stores a file in a linked list and then prints it.\n");/*
printf("%s\n",argv[1]);
if (argc == 2) { */
head = readFile("tester1.txt");
printList(head);
printListToFile("test.tmp", head);
insertToList(head->next, test);
printf("head");
free(head);
/*}
else if (argc > 2) {
printf("Too many arguments supplied.\n");
} else {
printf("One argument expected.\n");
}*/
return 0;
}
struct Node *makeNode()
{
struct Node *node;
node = (struct Node *)malloc(sizeof(struct Node));
if (node == NULL) {
printf("memory allocation failed\n");
return NULL;
}
node->next = NULL;
return node;
}
/*a method that creates a node with all values, declares a the next node and points it to the next node recieved
and changes the char array to the one recieved.*/
struct Node *makeFullNode(struct Node *Next, char Ptr[])
{
struct Node *node;
node = (struct Node *)malloc(sizeof(struct Node));
node->next = (struct Node *)malloc(sizeof(struct Node));
node->ptr[NICE] = Ptr[NICE];
node->next = Next;
return node;
}
/*the method that reads the file into the list into the char array of each node and returns the head of the list */
struct Node *readFile(char *path)
{
FILE *fptr;
struct Node *curr, *head;
curr = (struct Node *)malloc(sizeof(struct Node));
head = (struct Node *)malloc(sizeof(struct Node));
if (curr == NULL || head == NULL) {
printf("memory allocation failed\n");
return NULL;
}
curr = head;
fptr = fopen(path,"r");
if (fptr == NULL) {
printf("error - failed to open file\n");
exit(0);
return NULL;
}
while (fgets(curr->ptr, NICE, fptr))/*if fgets returns NULL it means that we either reached EOF or error, both a reason to end the loop*/
{
curr->next = makeNode();
curr = curr->next;
}
if(ferror(fptr))/*checking if the loop ended for the right reason*/
{
printf("error - failed to read file\nthis is what we got so far\n");
}
printf("file succesfully read\n");
fclose(fptr);
free(curr);
return head;
}
/*the method that reads the file into the list into the char array of each node and returns the head of the list */
struct Node *readstl(char *path)/*!!!problem!!!*/
{
FILE *fptr;
int i, len;
struct Node *head;
head = (struct Node *)malloc(sizeof(struct Node));
fptr = fopen("readstrtofile.tmp", "w");
if (fptr == NULL) {
printf("error - failed to open file\n");
exit(0);
return NULL;
}
len = strlen(path);
for (i = 0; i < len && fputc(*(path + i), fptr) != EOF; i++);
if (ferror(fptr))/*checking if the loop ended for the right reason*/
{
printf("error - failed to read into file\nthis is what we got so far\n");
}
fclose(fptr);
head = readFile("readstrtofile.tmp");
remove("readstrtofile.tmp");
return head;
}
/*a method that prints the recieved list depending on the list to have the equal length rows.
as specified in mmn 12 tab creating uneven rows is acceptable therefor when ever there is tab in the file
the rows will appear uneven as to tab takes a place of one char but prints to 8 blank spaces in ubuntu */
void printList(struct Node *head)
{
struct Node *curr;
curr = (struct Node *)malloc(sizeof(struct Node));
if (head == NULL) {
printf("empty list\n");
return;
}
if (curr==NULL) {
printf("memory allocation failed\n");
return;
}
printf("this is the list printed nicely\n");
curr = head;
printf("%s\n", curr->ptr);
while (curr->next != NULL) {
curr = curr->next;
printf("%s\n", curr->ptr);
}
printf("\n/********************/\n");
}
/* a method that creates a new file named path and prints a list to it */
void printListToFile(char *path,struct Node *head)/*!!!problem!!!*/
{
struct Node *curr;
char c;
int i;
FILE *fptr;
curr = (struct Node *)malloc(sizeof(struct Node));
if (curr == NULL) {
printf("memory allocation failed\n");
exit(0);
}
curr = head;
fptr = fopen(path, "w+");
if (fptr == NULL) {
printf("error - failed to open file\n");
exit(0);
}
if (head == NULL) {
printf("empty list\n");
exit(0);
}
printf("this is the file %s printed nicely\n",path);
curr = head;
while (curr->next != NULL) {
printf("new node -> ptr -> %s\n",curr->ptr);
/*if(sizeof(curr->ptr)/sizeof(char)<=NICE)
{*/
for(i=0;i<NICE && (c = fputc(curr->ptr[i],fptr)) != EOF;i++);
printf("puting %s to file %s\n",curr->ptr,path);
curr = curr->next;
printf("bolili\n");
/*}
else
{
printf("lilibo\n");
break;
}*/
}
printf("\n/********************/\n");
}
/* a method that recievs a string turns it into a list and inserts it into another list */
void insertToList(struct Node *node, char *str)
{
struct Node *tail, *head;
tail = (struct Node *)malloc(sizeof(struct Node));
head = (struct Node *)malloc(sizeof(struct Node));
if (tail == NULL || head == NULL) {
printf("memory allocation failed\n");
return;
}
head = readstl(str);/*reading the string to a node*/
printList(head);
printf("\n/***********in insert*********/\n");
tail = head;
while (tail->next) {
tail = tail->next;
}/*getting tto the last node to connect it*/
strcpy(tail->ptr, node->next->ptr);/*connecting the lists*/
tail->next = node->next->next;
strcpy(node->ptr, head->ptr);
node->next = head->next;
printf("inserted string successfully\n");
}
/* a method that returns the size of the list*/
unsigned int sizeOfList(struct Node *head)
{
struct Node *tmp;
int size;
if (!(head))
return 0;
size = 1;
tmp = (struct Node *)malloc(sizeof(struct Node));
tmp = head;
while ((tmp = tmp->next))
size++;
return size;
}
header file
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NICE 80
#define debug "\n/****************/\n"
/*the node structure of a the list which contains a string the size we choose is nice
to print by and a pointer to the next node in the list. */
struct Node {
char ptr[NICE];
struct Node *next;
};
/*makeNode - a method that returns a newely created node and sets all values to NULL values.*/
struct Node *makeNode();
/*makeFullNode - a method that return a newely created node with values set to params as listed below.
#param Next - tho ptr to the next node desired.
#param Ptr - the string that will go into the node ptr.*/
struct Node *makeFullNode(struct Node *Next, char *Ptr);
/*readFile - a method that reads a file into a linked list returning the head to that list.
it reads the file using fgets and a const to decide what size the node strings should be.
#param path - the name of the file to open.
#return the head of the list.*/
struct Node *readFile(char *path);
/*readstl - a method that reads a string into a linked list returning the head to that list.
it prints the list to a tmp file then reads the file using readFile.
#param path - the string to read.
#return the head of the list.*/
struct Node *readstl(char*);
/*printList - a method that prints the list to stdout.
it goes in loop on the nodes each time printing the node->ptr.
#param head - the head of the linked list.*/
void printList(struct Node *head);
/*insertToList - a method that inserts a string into list.
it creates a new list using readstl the connects the nodes using the basic method.
#param node - the node to override.
#param str - the string to insert.*/
void insertToList(struct Node *node, char *str);
/*a method that prints the list to stdout.
it goes in loop on the nodes each time printing the node->ptr.
#param head - the head of the linked list.*/
void printListToFile(char *path,struct Node *head);
/*sizeOfList - a method that returns how many node are in the list.
it goes in a while loop incresing counter by 1 each iteration.
#param head - the head of the list to measure.
#return the size of the list.*/
unsigned int sizeOfList(struct Node *head);
I think it is this line:
for(i=0;i<NICE && (c = fputc(curr->ptr[i],fptr)) != EOF;i++);
Why would fputc ever return EOF if everything goes right? It will try to write characters behind the ptr array. From the manpage of fputc:
fputc(), putc() and putchar() return the character written as an unsigned char cast to an int or EOF on error.
This means, your loop writes as long as fputc doesn't return an error code. But what you probably want, is writing either 80 (NICE is not a nice constant name) or strlen(curr->ptr) characters. Assuming based on your readFile function, you want both things as a limit. I would recommend rewriting this line as:
int len = strnlen(curr->ptr, 80);
if (fwrite(curr->ptr, 1, len, fptr) < 0) {
printf("error writing file");
}
or if the string is always null terminated:
if (fputs(curr->ptr, fptr) < 0) {
printf("error writing file");
}
Also ptr is not a good name for an array. It might confuse people or even you after some time, trying to understand the code. A better name would be value or text (even arr would be better, because it is not a pointer).
In readFile you have a loop in which you read a line and put it in curr->ptr and then create a new curr and link it to the previous curr.
This creates an extra empty curr at the end of the list which you don't need and so you free it later. Unfortunately, the next pointer of the previous node is still pointing at the empty node you just freed.
The easiest way to fix this without restructuring the loop a bit is to keep a record of the previous node, something like this:
struct Node* prev = NULL;
while (fgets(curr->ptr, NICE, fptr))/*if fgets returns NULL it means that we either reached EOF or error, both a reason to end the loop*/
{
curr->next = makeNode();
prev = curr;
curr = curr->next;
}
free(curr);
if (prev != NULL)
{
prev->next = NULL;
}
else
{
head = NULL; // For the empty file case. head == curr in this case
}
// The other clean up stuff

How to add a string to linked list in c?

I already get how to add an int to a linked list in C but I need to add a string and it simply doesn't work.
The main function gets the data from the user and prints it in the show function after adding it to the linked list.
list and main
struct nlista{
char dado[10];
struct nlista *prox;
}*Head;
int main(){
int op;
char data[10];
Head = NULL;
printf("type a value: ");
scanf("%s",&data);
inserir(data);
printf("the element is : ");
show();
}
inserir(): add the element in the end of list
void inserir(char data){
nlista *novoelemento;
novoelemento = (struct nlista *)malloc(sizeof(struct nlista));
nlista *check;
check = (struct nlista *)malloc(sizeof(struct nlista));
novoelemento->dado = data;
if(Head == NULL){
Head = novoelemento;
Head->prox = NULL;
}
else{
check = Head;
while(check->prox != NULL)
check = check->prox;
check->prox = novoelemento;
novoelemento->prox = NULL;
}
show(): display the linked list
void show()
{
nlista *check;
check = (struct nlista *)malloc(sizeof(struct nlista));
check = Head;
if (check == NULL){
return;
}
while(check != NULL) {
printf("%s", check->dado);
check=check->prox;
}
printf("\n");
}
What am I missing? The compiler message is: invalid conversion from char* to char. in the line of inserir(data);
Sorry, but I found many mistakes in your code. I have written a very simple solution for your question. Kindly refer and correct your mistakes.
Value is nothing but, the string i.e data(in the code) passed as an argument in function inserir in the main function. Remember each node of the linked list consists of a string element and the pointer to the next node. The string can be of various length. step 1 and step 2 will take care of that(see the code). Hope you are clear now.
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct nlista{
char *data;
struct nlista *prox;
}Node;
Node * inserir(Node *, char *);
'''inserir function should return your head node'''
void show(Node *);
'''show function takes head node'''
int main()
{
char data[10];
Node * Head = NULL;
printf("Type a value: ");
scanf("%s",data);
Head = inserir(Head,data);
printf("the element is : ");
show(Head);
}
Node* inserir(Node *Head, char *value)
{
Node *novoelemento;
novoelemento = (Node *)malloc(sizeof(Node));
//step 1. allocate memory to hold word
novoelemento->data = malloc(strlen(value)+1);
//step 2. copy the current word
strcpy(novoelemento->data,value);
Node *check;
check = (Node *)malloc(sizeof(Node));
if(Head == NULL){
Head = novoelemento;
Head->prox = NULL;
}
else{
check = Head;
while(check->prox != NULL)
check = check->prox;
check->prox = novoelemento;
novoelemento->prox = NULL;
}
return Head;
}
void show(Node *Head)
{
//check is of Node type using which you traverse the list and print the values
Node *check;
check = (Node *)malloc(sizeof(Node));
check = Head;
if (check == NULL){
return;
}
while(check != NULL) {
printf("%s", check->data);
check=check->prox;
}
printf("\n");
}
Hope this will help you.
We have char dado[10]; but novoelemento->dado = data; As you discovered, this does not compile.
You seem to want strncpy(novoelemento->dado, data, 10)[9] = 0; This copies the string within data over and ensures it's properly null terminated.
If you have strlcpy, you can do it better as strlcpy(novoelemento->dado, data, 10);

head updates on each insertion while converting text file to singly linked list in C

As the question specifies I want to convert a text file into linked list. When I read the string elements from an array it works fine but while doing the same from file creates the issue of updated head. The following is what I've tried...
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
//creating structure
typedef struct node {
char *word;
struct node *next;
}node;
//function for creating a node
node *createnode(char *wrd){
node *temp1;
temp1 = (node*)malloc(sizeof(node));
temp1->word = wrd;
temp1->next = NULL;
return temp1;
}
//function for creating and adding new node to linked list
node *creat(node *head, char *wrd){
node *temp, *p;
temp = createnode(wrd);
if(head == NULL){
head = temp;
}else{
p = head;
while(p->next != NULL){
p = p->next;
}
p->next = temp;
printf("p->word from creat method: %s ADDR: %p HEAD: %s \n", p->word,
p->next,head->word);
}
return head;
}
//traverse the list and display each node
node *show(node *head){
node *p;
p=head;
while(p != NULL){
printf("from show method: %s", p->word);
p = p->next;
printf("\n");
}
printf("\n");
}
int main()
{
node *head = NULL;
/* Character array to read the content of file */
char sWord[20];
/* Pointer to the file */
FILE *fp;
/* Opening a file in r mode*/
fp= fopen ("hw10data.txt", "r");
while( fscanf(fp, "%s", sWord) != EOF )
{
head = creat(head, sWord); //create list
}
fclose(fp);
show(head);
return 0;
}
I don't know why the head is updating on each insert. Any help will be appreciated.
It's not the head of the list which is changing; it's just that you read in the values into a local array sWord, which you then pass to the creat and createnode-functions. Therein, you simply assign a pointer, but you do not copy the content of sWord; Hence, all node contents will point to the same memory address, i.e. to sWord; and when you read in new values, all node contents will point to that new value. So it just seems as if the "head" has changed. Actually all nodes will show the same content...
To overcome this, write the following in createnode:
// temp1->word = wrd;
temp1->word = strdup(wrd);
Or, if strdup is not available:
temp1->word = malloc(strlen(wrd)+1);
strcpy(temp1->word,wrd);

How do you get a data section from a Linked list to compare?

I have just started learning linked list and was messing around with it but then I ran into a problem. I was not sure how to access the data member to actually compare it. In my code, I prompt the user to input grades and when they input -1 then it signals that they are finished. My first thought was to get the pointer pointing to the node to get the data like I did in scanf, however I can't compare pointers to integers. Is there a way to get data members from linked lists to compare? Also, pointing out other errors would be appreciated as well because I don't know linked lists too well. I have the following code:
int main() {
struct Node
{
int grade;
struct Node *next;
};
struct Node *head;
struct Node *first;
struct Node *temp = 0;
first = 0;
while (****** != -1) { //This is what I need the data from linked list for
head = (struct Node*)malloc(sizeof(struct Node));
printf("Enter the grade: \n ");
scanf("%d", &head -> grade);
if (first != 0) {
temp -> next = head;
temp = head;
}
else
{
first = temp = head;
}
}
}
There is a number of issue with your code:
1) Don't scan directly into the list - use a temp variable
2) Always check return values
3) Make sure to initialize variables, i.e. head
Try something like:
struct Node
{
int grade;
struct Node *next;
};
int main() {
struct Node *head = NULL;
struct Node *temp;
int data;
while (1)
{
printf("Enter the grade: \n ");
if (scanf("%d", &data) != 1)
{
// Illegal input
exit(1);
}
if (data == -1) break; // Stop the loop
temp = malloc(sizeof *temp); // Allocate new element
if (temp == NULL)
{
// Out of mem
exit(1);
}
temp -> next = head; // Insert new element in the front of list
temp -> grade = data;
head = temp; // Move the front (aka head) to the new element
}
// .... add code that uses the list
return 0;
}

program crashes while iterating through a linked list

I am supposed to create a linked list with the following properties:
struct node{
char *word;
int times;
struct node *next;
}head;
I have to read each word from a file, check if it exists in the list, and if it doesn't, i should add it. If it already exists i need to increase times by one. I use the following code to accomplish that:
void append(char *wrd, struct node *start){
struct node *current = start;
while(current->next != NULL){
current = current->next;
}
current->next = malloc(sizeof(struct node));
strcpy(current->word, wrd);
current->times = 1;
current->next->next = NULL;
}
int iterate(char *wrd, struct node *start){
struct node *current = start;
while(current != NULL){
if(strcmp(current->word, wrd)==0){
current->times++;
return 1;
}
current = current->next;
}
return 0;
}
void read_file(struct node *start){
FILE *fp;
char wrd[20];
puts("give file name and format(max 19 characters)");
gets(wrd);
fp = fopen((const char*)wrd, "r");
fscanf(fp, "%s", wrd);
start->word = malloc(strlen(wrd)+1);
strcpy(start->word, wrd);
while(fscanf(fp, "%s", wrd) != EOF){
if(!iterate(wrd, start)){
append(wrd, start);
}
}
}
void print_data(struct node *start){
struct node *current = start;
while(current->next != NULL){
printf("word: %s , times: %d", current->word, current->times);
}
}
int main(int argc, char *argv[]) {
struct node *start = &head;
read_file(start);
return 0;
}
append takes a word, creates a new node containing it, and adds the node to the list.
iterate takes a word and searches the list for a match. If the word already exists within the list, then times is increased by one. 0 is returned if no match was found and 1 in the opposite case.
read_file initializes the head node, reads the file and calls the above functions for each word it reads.
Let's say i have a text file containing the following words:
hello hey world hello
world this is supposed to work
but it does not
The program successfuly runs for the first 3 words and creates the nodes. When the match hello is found the program crashes. I've determined that the error lies in iterate, but i can't figure out what's causing it. Any help is greatly appreciated.
First things first, I don't understand why you can confidently say that your program has an error in the iterate function.
You haven't allocated any memory to the word pointer before strcpy().
I would suggest doing this in your append() function:
void append(char *wrd, struct node *start){
struct node *current = start;
if(current == NULL){
start = (struct node*)malloc(sizeof(struct node));
start->word = (char *)malloc((strlen(wrd) + 1)*sizeof(char));
strcpy(start->word, wrd);
start->times = 1;
start->next = NULL;
return;
}
while(current->next != NULL){
current = current->next;
}
current->next = (struct node*)malloc(sizeof(struct node));
current->next->word = (char*)malloc((strlen(wrd) + 1)*sizeof(char)); //add this line
strcpy(current->next->word, wrd); //not current->word
current->next->times = 1; //not current->times
current->next->next = NULL;
}
Notice here that in the append function, you did not check if the list is already empty or not. The if block is to do the same. Also notice the mistake you made while using strcpy(). You wanted to copy the new word in the new pointer, but were doing it in the pointer which is the parent of the new node.
Now, you read_file() function will look a lot simpler!
void read_file(struct node *start){
FILE *fp;
char wrd[20];
puts("give file name and format(max 19 characters)");
gets(wrd);
fp = fopen((const char*)wrd, "r");
while(fscanf(fp, "%s", wrd) != EOF){
if(!iterate(wrd, start)){
append(wrd, start);
}
}
}
I don't think your iterate function needs an update, but print_data() surely does:
void print_data(struct node *start){
struct node *current = start;
while(current != NULL){
printf("word: %s , times: %d", current->word, current->times);
current = current->next;
}
}
Seems like the only function not having any error was iterate(). Happens when you play with pointers! :P

Resources