Trying to make linked list, getting seg fault - c

New to C, but I'm trying to write this Linked List program, and I keep getting Segmentation fault: 11. I think I've narrowed it down to the problem being just in the linked list creation -- I marked it as the problem area. When I comment this section out, the seg fault doesn't happen.
I keep going over what is happening on paper and I can't understand why it won't work. Perhaps I just misunderstand the use of pointers or malloc since I'm inexperienced.
example text file that this program should work with:
>984932:39284 mus musculus okodvcxvmkw2e2p \n
ATCTCAATCGCACTATCTAGCATGTCGTATGCTTGCATGTCGTAGTCGT\n
ATGCTATGCTTACTCTATTTACGGCGCATCGTGATCGTAGGAGCGAGCT\n
>984932:39284 mus huumoros okodvcxvmkw2e2p \n
ATCTCAATCGCACTATCTAGCATGTCGTATGCTTGCATGTCGTAGTCGT\n
ATGCTATGCTTACTCTATTTACGGCGCATCGTGATCGTAGGAGCGAGCT\n
>984932:39284 mus pisces okodvcxvmkw2e2p \n
ATCTCAATCGCACTATCTAGCATGTCGTATGCTTGCATGTCGTAGTCGT\n
ATGCTATGCTTACTCTATTTACGGCGCATCGTGATCGTAGGAGCGAGCT\n
What I'm trying to do:
Create a linked list, where each node is one block of the text above. That is, each node contains the header which starts with '>', and the sequence data that is all of the ACTG. In the above example text file, there would be 3 nodes in addition to the head/tail nodes in the list.
How I'm trying to do it (the problem section):
Char is scanned. If char is '>', then we know we're at the header, and we read all following chars into the new node's header field until we reach the newline char. At this point, we know we're going to read in sequence data. Continue to do so until we reach another '>', and when we do, repeat.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int list_header_size = 200;
int list_data_size = 2000;
struct list{
char *header;
char *data;
struct list *next;
struct list *prev;
};
//append char onto a string
void append(char *s, char c){
int len = strlen(s);
s[len] = c;
s[len + 1] = '\0';
}
int create_list(char *filename){
FILE *fp = fopen(filename, "r");
if(fp == NULL){
printf("File could not be opened. Exiting..");
exit(1);
}
//setup head - doesn't hold a char
struct list *head = malloc(sizeof(struct list));
head->next = NULL;
head->header = NULL;
head->data = NULL;
head->prev = NULL;
//setup tail - doesn't hold a char
struct list *tail = malloc(sizeof(struct list));
tail->next = NULL;
tail->header = NULL;
tail->data = NULL;
tail->prev = NULL;
/***scan the .fasta file, populate list***/
//char holder
char c;
int list_size = 0;
int i = 1;
//pull single char from file until end of file is reached
do{
c = getc(fp);
//******PROBLEM IS IN THIS SECTION********//
//if header text is found
if(c == '>'){
//create a node
struct list *temp = malloc(sizeof(struct list));
//first case to setup head
if(i == 1){
head->next = temp;
temp->prev = head;
i = 0;
}
tail->next = temp;
tail->prev = temp;
//create space for header/sequence data in the new node
temp->header = (char*) malloc(sizeof(list_header_size));
temp->data = (char*) malloc(sizeof(list_sequence_size));
//add current char to header
append(temp->header, c);
c = getc(fp);
//put file's header data into node's header data
while(c != '\n'){
append(temp->header, c);
c = getc(fp);
}
//put file's sequence data into node's sequence data
while(c != '>' && c != EOF){
append(temp->data, c);
}
}
//*******END OF PROBLEM SECTION********//
}while(c != EOF);
/***end of scanning .fasta file and creating linked list***/
return 1;
}
int main(int argc, char * argv[]){
char *filename = (char*) malloc(80);
//check options
int i;
for(i = 1; i < argc; i++){
if(argv[i][0] == '-'){
switch(argv[i][1]){
default:;
}
}else{
//arg is filename
filename = argv[i];
}
}
create_list(filename);
return 1;
}

The most immediate thing is this:
//create space for header/sequence data in the new node
temp->header = (char*) malloc(sizeof(list_header_size));
temp->data = (char*) malloc(sizeof(list_sequence_size));
Which I believe should be this:
//create space for header/sequence data in the new node
temp->header = malloc(list_header_size);
temp->data = malloc(list_sequence_size);
if you're super - new to C there are probably other things here too, but mallocs and their sizes are always the first things I check, and this one isn't right.
EDIT Another Problem:
Your buffers are now allocated, but your append() function expects them to be zero-terminated from inception. They are not. Add this:
temp->header = malloc(list_header_size);
temp->data = malloc(list_sequence_size);
temp->header[0] = temp->data[0] = 0; // <=== this
To be honest, since these sizes are fixed I would have rather you just declare the actual node structure like this:
struct list{
char header[200];
char data[2000];
struct list *next;
struct list *prev;
};
and avoid all the extra allocations entirely, just allocating nodes and not their fields. If the field sizes ever become dynamic, this would need to change, but until then, keep it simple.

I would have a look at your append(...) function, and the data you feed into it.
Your first call to the function is
append(temp->header, c);
and temp->header is not guaranteed to be zeroed. It could point to anything, though most compilers will zero it (or attempt to do so). Use calloc instead of malloc.

Related

CS50 - LOAD - Get random character from no where when trying to execute load

I am new to C programming. I am trying to do the pset5 in CS50 while trying to understand the concepts of memory, linked list and hashtable. I wrote the code and it compiled but there seems to be something wrong because every time I tried to execute the code it returns some garbage value. Could anyone please help me with that? Many thanks.
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<string.h>
#include "dictionary.h"
#define DICTIONARY "dictionaries/small"
typedef struct node
{
char WORD[LENGTH + 1];
struct node *next;
}
node;
int hash(char *word);
int main(void)
{
node **HASHTABLE = malloc(sizeof(node) * 26);
//open the dictionary
FILE *dic = fopen(DICTIONARY, "r");
if (dic == NULL)
{
fprintf(stderr, "Could not open the library\n");
return 1;
}
int index = 0;
char word[LENGTH + 1];
for (int c = fgetc(dic); c != EOF; c = fgetc(dic))
{
word[index] = c;
index++;
if (c == '\n')
{
int table = hash(word);
printf("%d\n", table);
//create a newnode
node *newnode = malloc(sizeof(node));
strcpy(newnode->WORD, word);
newnode->next = NULL;
printf("Node: %s\n", newnode->WORD);
index = 0;
//add new node to hash table
if (HASHTABLE[table] == NULL)
{
HASHTABLE[table] = newnode;
}
else
{
HASHTABLE[table]->next = newnode;
}
}
}
for(int i = 0; i < 26; i++)
{
node *p = HASHTABLE[i];
while (p != NULL)
{
printf("%s", p->WORD);
p = p->next;
}
}
//free memory
for(int i = 0; i < 26; i++)
{
node *p = HASHTABLE[i];
while (p != NULL)
{
node *temp = p->next;
free(p);
p = temp;
}
}
free(HASHTABLE);
}
int hash(char *word)
{
int i = 0;
if (islower(word[0]))
return i = word[0] - 'a';
if (isupper(word[0]))
return i = word[0] - 'A';
return 0;
}
Your code has serious problems that result in undefined behavior.
Two of them are the result of this line:
node **HASHTABLE = malloc(sizeof(node) * 26);
That allocates 26 node structures, but the HASHTABLE variable expects the address of a pointer to an array of node * pointers (that's the ** in the node **HASHTABLE declaration).
So, you should replace it with something like:
node **HASHTABLE = malloc( 26 * sizeof( *HASHTABLE ) );
Note that I used the dereferenced value of the variable being assigned to - HASHTABLE. This means in this case a node (one less * than in the declaration). So if the type of HASHTABLE changes, you don't need to make any other changes to the malloc() statement.
That problem, while technically undefined behavior, likely wouldn't cause any problems.
However, there's still a problem with
node **HASHTABLE = malloc( 26 * sizeof( *HASHTABLE ) );
that will cause problems - and serious ones.
That array of 26 pointers isn't initialized - you don't know what's in them. They can point anywhere. So this won't work well, if at all:
if (HASHTABLE[table] == NULL)
Meaning this points off to somewhere unknown:
HASHTABLE[table]->next = newnode;
And that will cause all kinds of problems.
The simplest fix? Initialize the values all to zero by using calloc() instead of malloc():
node **HASHTABLE = calloc( 26, sizeof( *HASHTABLE ) );
Until that's fixed, any results from your entire program are questionable, at best.
The reason for the garbage is that you didn't null-terminate the string:
strcpy(newnode->WORD, word);
strcpy expects the src to point to a null-terminated string. Simply adding 0 at the end. Simply terminate it with
word[index] = 0;
before the strcpy.
Other than that, the ones in Andrew Henle's answer should be addressed too, but I am not going to repeat them here.
BTW, next you will notice that
HASHTABLE[table]->next = newnode;
wouldn't work properly - that code always inserts the node as the 2nd one. But you want to always insert the new node unconditionally as the head, with
newnode->next = HASHTABLE[table];
HASHTABLE[table] = newnode;
There need not be any special condition for inserting the first node to a bucket.

Program execution interrupted when certain String is read from File

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.

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

C Segmentation fault even when using EOF [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
I'm loading a file into memory and I am doing so with the following statement:
if ((ch = fread(&temp[i],1,1,loadDict)) == EOF)
break;
But I receive a segmentation fault. Upon inspection using gdb I verified that the fault is happening at this line (the if statement, before the break). Why does it not see that it will fault (the whole point of using EOF)?
I thought it might be that I'm using the EOF in an if statement rather than within a while() statement. Is it possible to use EOF in an if statement?
Update: More Code
bool load(const char* dictionary)
{
FILE* loadDict = fopen(dictionary, "r");
char* new = malloc(sizeof(char)); // for storing the "new-line" character
*new = 0x0A;
// defines a node, which containes one word and points to the next word
typedef struct node
{
char* word;
struct node* next;
}
node;
node* head = malloc(sizeof(node));
node* temp = malloc(sizeof(node));
head->next=temp;
// copies a word from the dictionary file into a node
int* numStore = malloc(sizeof(int)); //count for number of words in dictionary
int num = 0;
int ch = 0; // to hold for EOF
int flag = 0; // for breaking out of while loop
while(true)
{
node* newNode = malloc(sizeof(node));
temp->next=newNode;
temp->word=malloc(46);
int i = -1;
do
{
i++;
if (!feof(loadDict) || !ferror(loadDict))
{
flag = 1;
break;
}
fread(&temp[i],1,1,loadDict);
if (memcmp (new, &temp[i], 1) == 0)
num += 1;
}
while(memcmp (new, &temp[i], 1) != 0);
temp=newNode;
if (flag == 1)
break;
}
numStore = &num;
return true;
}
typedef struct node
{
char* word;
struct node* next;
}
The structure that you defined can crash, at least the implementations I have seen has. The char* inside the node has no fixed value. So when you do :
node* head = malloc(sizeof(node));
The malloc() will allocate a memory of (taking 1 byte for char pointer, and an int size pointer for node, defaulting to 4 bytes on a 32-bit machine) 5 bytes. What happens when you read more than 5 bytes?
Also, you are needlessly complicating this:
int* numStore = malloc(sizeof(int));
If you want to store the number of words in the dictonary, straight away use an int numstore, less headache :)
while(true)
{
node* newNode = malloc(sizeof(node));
temp->next=newNode;
temp->word=malloc(46);
...
}
Now, this here is an interesting concept. If you want to read till the end of file, you have got two options:
1) use feof()
2) at the end of the loop, try this:
while(true)
{
....
if(fgetc(loadDict)==EOF) break; else fseek(loadDict,-1,SEEK_CUR);
}
Also, this line: temp->word=malloc(46);
Why are you manually allocating 46 bytes?
Armin is correct, &temp[i], while i does get allocated to 0, the do{...}while(); is completely unnecessary.
Also from man fread : http://www.manpagez.com/man/3/fread/
You are reading what looks to me like 1 character.
In my opinion, try something like this:
set a max value for a word length (like 50, way more for practical purposes)
read into it with fscanf
get its length with fscanf
allocate the memory
Also, you do not need to allocate memory to *head; It can be kept as an iterator symbol
I almost forgot, how are you going to use the returned list, if you are returning bool, and the *head is lost, thus creating a memory leak, since you can't deallocate the rest? And unless you are using c99, c doesn't support bool
/*Global declaration*/
typedef struct node
{
char* word;
struct node* next;
}node;
node *head, *tmp;
/* for the bool if you really want it*/
typedef enum { false, true } bool;
node* load(const char* dictionary)
{
FILE* loadDict = fopen(dictionary, "r");
char word[50];
int num = 0;
int len;
node *old;
while(true)
{
/*node* newNode = malloc(sizeof(node));
temp->next=newNode;
temp->word=malloc(46);*/
fscanf(loadDict,"%s ",word);
len = strlen(word);
tmp = malloc(len + sizeof(node));
strcpy(tmp->word,word);
tmp->next = NULL;
if(head==NULL)
{
head = tmp;
old = head;
}
else
old->next = tmp;
old = tmp;
num++;
if(fgetc(loadDict)==EOF) break; else fseek(loadDict,-1,SEEK_CUR);
}
printf("number of counted words::\t%d\n",num);
fclose(loadDict);
return head;
}
Also, please remember that i have only accounted for the act that words are separated by one space per, so please load the file t=like that, or change the algo :) Also, be sure to free the memory after using the program !
void freeDict()
{
node *i;
while(head!=NULL)
{
i = head;
head = head->next;
free(i);
}
}
Hope this helps :)
This compiles...I've now run it too. The error handling on failure to allocate is reprehensible; it should at minimum give an error message and should probably free all the allocated nodes and return 0 (NULL) from the function (and close the file).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Node
{
char *word;
struct Node *next;
} Node;
Node *dict_load(const char *dictionary)
{
FILE *loadDict = fopen(dictionary, "r");
if (loadDict == 0)
return 0;
Node *head = 0;
char line[4096];
while (fgets(line, sizeof(line), loadDict) != 0)
{
size_t len = strlen(line); // Includes the newline
Node *node = malloc(sizeof(*node));
if (node == 0)
exit(1); // Reprehensible
node->word = malloc(len);
if (node->word == 0)
exit(1); // Reprehensible
memmove(node->word, line, len - 1); // Don't copy the newline
node->word[len-1] = '\0'; // Null terminate the string - tweaked!
node->next = head;
head = node;
}
fclose(loadDict);
return head;
}
If you've got to return a bool from the function, then you probably need:
static bool dict_load(const char *dictionary, Node **head)
If the argument list is fixed at just the file name, then you're forced to use a global variable, which is nasty on the part of the people setting the exercise. It's 'doable' but 'ugly as sin'.
The code above does work (note the tweaked line); adding functions dict_free() and dict_print() to release a dictionary and print a dictionary plus proper error handling in dict_load() and a simple main() allows me to test it on its own source code, and it works (printing the source backwards). It gets a clean bill of health from valgrind too.
You're use of temp[i] raises suspicion that you might be accessing outside memory.
To quote from K&R:
If pa points to a particular element of an array, then by definition pa+1 points
to the next element, pa+i points i elements after pa, and pa-i points i elements
before.
These remarks are true regardless of the type or size of the variables in
the array a. The meaning of ``adding 1 to a pointer,'' and by extension,
all pointer arithmetic, is that pa+1 points to the next object, and pa+i
points to the i-th object beyond pa.

cstring trouble for a beginner

I'm trying to make a program that read a file line by line and then put the readed line into a a linked list, my problem is to add the string to list. Look at the code, in the else test you can see my problem.
#include<stdlib.h>
#include<stdio.h>
struct list_el {
char *ord;
struct list_el * next;
};
typedef struct list_el item;
int main(int argc, char *argv[]) {
int c;
item *curr, *head;
head = NULL;
FILE *fileHandle = fopen("tresmaa.txt", "r");
while((c = fgetc(fileHandle)) != '\n' || c != EOF)
if(c == EOF) {
printf("\n");
break;
} else {
curr = (item*)malloc(sizeof(item));
curr->ord = "I cant point curr -< ord = c, how can i point the readed sentences to the value Ord?";
curr->next = head;
head = curr;
putchar(c);
}
curr = head;
while(curr) {
printf("%s\n", curr->ord);
curr = curr->next ;
}
}
curr->ord = "some string" is wrong
instead you need to allocate a buffer and place the string in it
e.g.
curr->ord = malloc( strlen(yourstring) + 1 );
strcpy(curr->ord, yourstring);
because
curr = (item*)malloc(sizeof(item));
only allocates the struct including the 'ord' pointer, but not what it points to.
another thing that looks a bit suspicious is
curr->next = head;
head = curr;
looks more like the name should have been 'prev' and not 'next' the way you do it (LIFO)
otherwise if you want a "normal" FIFO linked list just have a head ptr and an end ptr, then use the end ptr to append elements while keeping the head pointing to the first list element.
I see your problem in the else. :)
Your malloc of the struct is not sufficient. This malloc only creates the memory of the struct memory (two pointers) not the memory inside. You'll have to malloc your char memory (ord) with the proper size of the string as well. Use strlen and add one for null to determine size of this string.
curr->ord = "some string"
is right!

Resources