Program execution interrupted when certain String is read from File - c

I have a small problem with my code and hope you can help me.
This program below reads names that are written in a txt-file and stores them in a linked list and prints them back out on the command line.
The list consists of the following names:
Gustav Mahler
Frederic Chopin
Ludwig van Beethoven
Johann-Wolfgang Von-Goethe
But when I run the program, the execution of the program is interrupted, either before printing the list or after.
If I remove the last line it works perfectly, but when I add it back in to the list or replace it with a random combination like "jlajfi3jrpiök+kvöaj3jiijm. --aerjj" it stops again.
Can somebody please explain to me why the program execution gets interrupted?
Thank you in advance ! :)
Here's the Program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct list {
char* name;
struct list *next;
}NODE;
char * getString(char *source);
int main() {
FILE *fpointer = NULL;
char filename[100];
puts("\nEnter the name of the file:\n");
gets(filename);
if((fpointer = fopen(filename, "r")) == NULL ) {
printf("\nThe file you have chosen is not valid.\n");
return 1;
}
char buffer[200];
NODE *head = NULL;
NODE *current = NULL;
while(fgets(buffer, 200, fpointer) != NULL) {
NODE *node = (NODE *) malloc(sizeof(NODE));
node -> next = NULL;
node -> name = getString(buffer);
if(head == NULL) {
head = node;
} else {
current -> next = node;
}
current = node;
}
current = head;
while(current) {
printf("%s", current -> name);
current = current -> next;
}
return 0;
}
char * getString(char* source) {
char* target = (char*) malloc(sizeof(char));
strcpy(target, source);
return target;
}

In getString, you're not allocating enough space for the string you want to copy:
char* target = (char*) malloc(sizeof(char));
This is only allocating space for a single character. You need enough for the length of the string, plus 1 more for the null terminating byte:
char* target = malloc(sizeof(strlen(source) + 1);
You could actually replace the entire function with a call to strdup, which does the same thing.
Also, don't cast the return value of malloc, and never use gets.

Related

inserting strings into linked list is not working correctly

I have a program that is supposed to take an input file and extract the strings from it and add it to a linked list. I do not think I am adding the strings to the linked list correctly and i cannot seem to find the right way to. When the program executes it goes into an infinite loop for some reason.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct list {
char *string;
struct list *next;
};
typedef struct list LIST;
int main() {
FILE *fp;
char line[128];
char file_name[20];
LIST *current, *head;
char *p, *s;
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))
{
p = s = line;
while(*p!=0)
{
if (*p==' ')
{
LIST *node = malloc(sizeof(LIST));
*p = 0;
node->string = strdup(s);
node->next =NULL;
if(head == NULL){
current = head = node;
} else {
current = current->next = node;
}
s = p+1;
}
p++;
}
}
fclose(fp);
//test print
for(current = head; current ; current=current->next){
printf(" %s", current->string);
}
return 0;
}
Several things:
You are using the same node for all words in a line, thereby creating a loop where node->next equals node. You should create a new node when you insert a new word, not when you read a new line.
You don't catch the last word of a line. You can make use of the fact that fgets retains the trailing new-line character and check for that in addition to checking for a space. You could also consider using isspace from <ctype.h>.
Alternatively, and maybe better, is to defer the check for the null terminator until after the loop. You must then add a new word when you read a space or a null character.
You insert empty words when the input file contains consecutive spaces or space characters. Your program should check whether p > s to add only valid words. (Or your program shoul only add valid words when the previously read character wasn't a space.)
You allocate memory for the nodes and the strings. You should free this memory before exiting the program.
Here's your main loop with the fixes described above:
while(fgets(line, sizeof(line), fp))
{
char *p = line;
char *s = line;
do {
if (*p== ' ' || *p == '\n' || *p == '\t' || *p == '\0') {
if (p > s) {
LIST *node = malloc(sizeof(LIST));
*p = 0;
node->string = strdup(s);
node->next = NULL;
if(head == NULL){
head = node;
} else {
current->next = node;
}
current = node;
}
s = p + 1;
}
p++;
}
while (*p != 0);
}

Singly linked list C, printing

I'm a beginner in developing, so my sensei gave me a task to complete in which I need to enter a couple of strings in linked lists and after I enter print, they need to be printed in the correct order, from the first to last.
Here is what I got:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Node {
char data;
struct Node *next;
}node;
char createlist(node *pointer, char data[100]) {
while (pointer->next != NULL) {
pointer = pointer->next;
}
pointer->next = (node*) malloc(sizeof(node));
pointer = pointer-> next;
pointer->data = *data;
pointer->next = NULL;
}
int main() {
node *first, *temp;
first = (node*) malloc(sizeof(node));
temp = first;
temp->next = NULL;
printf("Enter the lines\n");
while (1) {
char data[100];
gets(data);
createlist(first, data);
if (strcmp(data, "print") == 0)
printf("%s\n", first->data);
else if (strcmp(data, "quit") == 0)
return (0);
};
}
When I run it I get:
Enter the lines:
asdfasdf
print
(null)
Any help would be appreciated since this is my first time using linked lists.
You should format your code properly.
first->data is allocated via malloc() and isn't initialized, so using its value invokes undefined behavior.
In order not to deal the first element specially, you should use pointer to pointer to have createlist() modify first.
Since createlist() won't return anything, type of its return value should be void.
I guess you wanted to copy the strings instead of assigning the first character of each strings.
To print all of what you entered, code to do so have to be written.
You shouldn't use gets(), which has unavoidable risk of buffer overrun.
You should free() whatever you allocated via malloc().
improved code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Node
{
char *data;
struct Node *next;
} node;
void createlist(node **pointer, char data[100])
{
while (*pointer != NULL)
{
pointer = &(*pointer)->next;
}
*pointer = malloc(sizeof(node));
if (*pointer == NULL)
{
perror("malloc 1");
exit(1);
}
(*pointer)->data = malloc(strlen(data) + 1);
if ((*pointer)->data == NULL)
{
perror("malloc 2");
exit(1);
}
strcpy((*pointer)->data, data);
(*pointer)->next = NULL;
}
int main(void)
{
node *first = NULL;
printf("Enter the lines\n");
while (1)
{
char data[100], *lf;
if (fgets(data, sizeof(data), stdin) == NULL) strcpy(data, "quit");
if ((lf = strchr(data, '\n')) != NULL) *lf = '\0'; /* remove newline character */
createlist(&first, data);
if (strcmp(data, "print") == 0)
{
node *elem = first;
while (elem != NULL)
{
printf("%s\n", elem -> data);
elem = elem->next;
}
}
else if (strcmp(data, "quit") == 0)
{
while (first != NULL)
{
node *next = first->next;
free(first->data);
free(first);
first = next;
}
return(0);
}
}
}
Inside createlist(), you are iterating to the end of the list. There, you are adding a new node and setting a new text entered. By doing so, you are missing that you have already a first node. Because you are iterating to the end in every call of createlist(), you are jumping over your first node every time, so it remains without text and delivers NULL.
In order not to jump over the first initial node, you could alter createlist() like this:
char createlist(node *pointer, char data[100])
{
while (pointer->data != NULL && pointer->next != NULL)
{
pointer = pointer->next;
}
...
...
}
Or you could create the first node not initially, but only after the first line of text was entered.
edit: Here are two additional style hints:
What happens if somebody enters 120 characters? The text will outrun your char[100] array and will fill RAM that is used otherwise. This is a buffer overflow. You could try to grab only the first 100 chars, get the substring. Alternatively, use the length argument of fgets()
Create a constant for 100, like #define MAX_BUFFER_LENGTH 100, and use it every time.

Why is my linked list only printing last entry?

I'm trying to read specific lines from a file and add it to a linked list and then print it out.
Code below:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct list {
int uid;
char* uname;
struct list* next;
}node;
void push(node ** head, int uid ,char* uname) {
node * new_node;
new_node = malloc(sizeof(node));
new_node->uid = uid ;
new_node->uname=uname;;
new_node->next = *head;
*head = new_node;
}
void print_list(node *head) {
node * current = head;
while (current != NULL) {
printf("%u:%s\n", current->uid,current->uname);
current = current->next;
}
}
int main(int argc, char **argv){
node *current=NULL;
FILE *fp=fopen(argv[1],"r" );
if (fp==NULL){
perror("Failed to open file");
exit(EXIT_FAILURE);
}
char s[1024];
const char token[2]=":";
char *stoken;
while(!feof(fp)){
int count=0;
int tempint;
char* tempchar=malloc(sizeof(char));
fgets(s, 1024, fp);
stoken = strtok(s,token);
current=malloc(sizeof(node));
while(stoken != NULL){
if (count==0){
tempchar=stoken;
}
if (count==2){
sscanf(stoken,"%d",&tempint);
}
count++;
stoken=strtok(NULL,token);
}
push(&current,tempint,tempchar);
}
fclose(fp);
print_list(current);
}
My problem is when print_list is ran the only thing who gets printed is the last entry.
For this input :
hello:asd:123:foo:ar
hi:proto:124:oo:br
hey:qwe:321:fo:bar
the only thing which gets printed is
321:hey
is it my push which is wrong or my print_list?
The problem is the way you are treating the result of strtok: you are setting its value right into the node, instead of copying it.
Make a copy of name when adding a node:
void push(node ** head, int uid ,char* uname) {
node * new_node;
new_node = malloc(sizeof(node));
new_node->uid = uid;
new_node->uname=malloc(strlen(uname)+1);
strcpy(new_node->uname, uname);
new_node->next = *head;
*head = new_node;
}
You should also look at the way that you are using tempchar in the main function. You allocate a space for a single character to it, which gets written over with the result of strtok, leaking the malloc-ed memory.
It's because you always overwrite head in the push() function, you should make it NULL initially and then check if it's NULL the first time and assign to it the first node, and then don't reassing anything to it, your program has a memory leak because of this too.
Also you are malloc()ing the node outside the function and then inside the function again,which causes another memory leak.
You should also check if malloc() returns NULL which indicates an error like when the system runs out of memory, dereferencing a NULL pointer is undefined behavior.
And a final note, you must check the return value of scanf() before accessing the target variables, or that would again cause undefined behavior.
change like as follows
char* tempchar;//=malloc(sizeof(char));
fgets(s, 1024, fp);
stoken = strtok(s,token);
//current=malloc(sizeof(node));//don't update like this
while(stoken != NULL){
if (count==0){
tempchar=strdup(stoken);//malloc and strcpy

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
}
}

How to read file content into a struct line by line in C

Here, I am trying to read the contents of a file line by line and create a struct for each line. The problem is when I print the list of words, every single one of them is the last word of the file (which is } in this sample). I believe since line changes frequently and I pass a pointer to a char, value of every struct changes as well. I've been trying to fix this problem for nearly a day without any luck. What's a good way to read every word into a struct and link each struct to the linked list?
Note that there are some helper methods used below. I've tested them multiple times and they are working.
Token struct
typedef struct token
{
char* value;
struct token* next;
}TOKEN;
File content
target1:
dependency1
{
command1,
command2
}
Main
TOKEN *head = NULL;
// represents each formatted line from the script file
char* line = malloc(161*sizeof(char));
FILE* fileRead = openFile("RawRules.txt", "r");
while((line = readLine(line, fileRead)) != NULL)
{
head = add(head, line);
}
displaylist(head);
freeNodes(head);
fclose(fileRead);
Add function Modified from http://cprogramminglanguage.net/singly-linked-list-c-source-code.aspx
TOKEN* add(TOKEN *head, char* value){
TOKEN *tmp;
if(head == NULL){
head=(TOKEN *)malloc(sizeof(TOKEN));
if(head == NULL){
printf("Error! memory is not available\n");
exit(0);
}
head-> value = value;
head-> next = head;
}else{
tmp = head;
while (tmp-> next != head)
tmp = tmp-> next;
tmp-> next = (TOKEN *)malloc(sizeof(TOKEN));
if(tmp -> next == NULL)
{
printf("Error! memory is not available\n");
exit(0);
}
tmp = tmp-> next;
tmp-> value = value;
tmp-> next = head;
}
return head;
}
readline function
// reads a line of a file into buffer
char* readLine(char* buffer, FILE* file) {
buffer = fgets(buffer, 161, file);
return buffer;
}
This did not fix the problem either
while(true)
{
char* ll = malloc(161*sizeof(char));
ll = readLine(ll, fileRead);
f(ll != NULL)
head = add(head, ll);
else
break;
}
Sorry, I progammed in C like billion years ago, so call me a noob!
In the add() function, you're simply assigning a char *, rather than allocating any new memory (and then copying) for each string. So each TOKEN ends up pointing at the original buffer. As you're using a single buffer at the top-level, you're overwriting it over and over again.
In short: You need a separate buffer for each line. One way (not necessarily the best way) is to do the following inside add():
int len = strlen(value);
...
tmp->value = malloc(len+1); /* +1 for null terminator */
strncpy(tmp->value, value, len+1);
Remember that at some point, you'll need to free() all of these extra buffers.

Resources