C - Read file to Doubly Linked List got segmentation fault - c

I am reading from txt file into a doubly linked list. The codes can do storing data into Nodes, but when I let it go through the linked list, it got a segmentation fault.
Could you guys please tell what has been wrong with the code, thank you!
This is the data structure:
typedef struct telephoneBookNode {
int id;
char name[NAME_LENGTH];
char telephone[TELEPHONE_LENGTH];
struct telephoneBookNode * previousNode;
struct telephoneBookNode * nextNode;
} TelephoneBookNode;
typedef struct telephoneBookList {
TelephoneBookNode * head;
TelephoneBookNode * tail;
TelephoneBookNode * current;
unsigned size;
} TelephoneBookList;
This is the code to create linked list:
TelephoneBookList * createTelephoneBookList(char entry[]) {
TelephoneBookList* aList = NULL;
TelephoneBookNode* aNode = NULL;
char *tokens;
TelephoneBookNode *(*create)() = createTelephoneBookNode;
aNode = (*create)();
tokens = strtok(entry, ", ");
aNode->id = atoi(tokens);
tokens = strtok(NULL, ", ");
strcpy(aNode->name, tokens);
tokens = strtok(NULL, ", ");
strcpy(aNode->telephone, tokens); //Fine until here
//Do I need this line?
//aList = (TelephoneBookList*) malloc(aList->size + 1) * sizeof aList);
if (aList->head == NULL) {
aNode->nextNode = NULL;
aNode->previousNode = NULL;
aList->current = aNode;
aList->head = aNode;
aList->tail = aNode;
} else {
aList->tail->nextNode = aNode;
aNode->previousNode = aList->tail;
}
return aList;
}
TelephoneBookNode * createTelephoneBookNode() {
TelephoneBookNode* aNode;
aNode = (TelephoneBookNode*) malloc(sizeof *aNode);
return aNode;
}

//Do I need this line?
//aList = (TelephoneBookList*) malloc(aList->size + 1) * sizeof aList);
Yes. Yes you do need that line. Otherwise the next line
if (aList->head == NULL) {
will dereference a null pointer.
Though you already do that in the commented out malloc call, dereference a null pointer, with aList->size + 1.
The correct line should be
aList = malloc(sizeof *aList);
And since you create the list from scratch in the function, there is no need to check if it is empty or not, it will always be empty. More importantly, the malloc call will not initialize the memory it allocates, so using that memory (for example in an expression like aList->head == NULL) will lead to undefined behavior.
Allocate the list structure. And then initialize it as if it was empty. And don't forget to initialize the size member as well.

Your createTelephoneBookNode function does not initialize the node that it created. malloc() assigns it a memory block that's probably not been initialized with zeros, and as a result, the nextNode and previousNode pointers contain garbage. Either set them both to NULL, or allocate your memory with calloc().

Related

Unexpect behaviour with pointer array

im currently implementing a basic linked list structure on C.
Basically im parsing a txt file, and I buffer each line into a Node which contains a pointer to an array of integers. The problem is, that my data (the array of integers) doesn't save correctly / i don't know how to iterate through it correctly.
These are the structures that I use:
typedef struct Node
{
struct Node* next;
struct Node* prev;
int* data;
int len;
} Node;
typedef struct LinkedList
{
Node* head;
Node* tail;
} LinkedList;
and I use this method to create a new node from a buffered string:
int nodeManager(FILE* filePointer, char* buffer, char* token, LinkedList* linkedList)
{
token = strtok(buffer, DELIMITER);
int* data = (int*)malloc(sizeof(int));
int dataIndex = 0;
if (data == NULL)
{
fprintf(stderr, DATA_ALLOCATION_ERROR);
freeLinkedList(linkedList);
fclose(filePointer);
return EXIT_FAILURE;
}
const char* insertPosition = token;
while ((token = strtok(NULL, DELIMITER)))
{
data = realloc(data, dataIndex + 1);
if (data == NULL) {
fprintf(stderr, DATA_ALLOCATION_ERROR);
freeLinkedList(linkedList);
fclose(filePointer);
return EXIT_FAILURE;
}
char *res;
int num = (int) strtol(token, &res, 10);
data[dataIndex] = num;
dataIndex++;
}
Node* newNode = (Node*)malloc(sizeof(Node));
if (newNode == NULL)
{
freeLinkedList(linkedList);
free(data);
fclose(filePointer);
return EXIT_FAILURE;
}
newNode -> prev = NULL; newNode -> next = NULL;
newNode -> len = dataIndex; newNode -> data = data;
if(strcmp(insertPosition, INSERT_TO_START) == 0)
{
addToStartLinkedList(linkedList, newNode);
}
else
{
addToEndLinkedList(linkedList, newNode);
}
return EXIT_SUCCESS; // TODO - Change
}
A line of input looks like this:
start,1,2,3,4,5,6,7,10,22,44,55,66,66,77
for some reason, node -> data doesn't get all the values that I assign in this method and I can't really tell why.
I tried to print the values like this:
for (int i = 0; i < newNode -> len; i++)
{
printf("%d,", (newNode -> data)[i]);
}
However, as I said, something quite doesn't work with my assigment, or I just don't know how to access the values correctly.
Would love to get some insight - thanks.
This part is wrong:
data = realloc(data, dataIndex + 1);
You have forgotten to multiply with sizeof(int) or better sizeof *p
BTW: Be careful about doing realloc directly into data. On failure realloc may return NULL and then you have a memory leak. You should use a temporary pointer like:
int * temp = realloc(data, SOME_SIZE);
if (temp == NULL)
{
// oh dear, add error handling here - maybe a return or whatever fits
}
else
{
// All good
data = temp;
}
OT: Passing the file pointer to the function in order to be able to close the file is (IMO) a rather strange design. Instead, the caller should check the return value and close the file (if desired).

Array pointer always points to NULL

Im trying create a linked list in an array of nodes. When I try to update the pointer for arrTab->h_table[index] to the address of newNode, The address points to newNodes address. But when I try to add to a list that exists in the array, the pointer always points to NULL instead of the previous value in memory. Basically the arrTab->h_table[index] head of the linked list does not update to the address of newNode.
typedef struct node {
struct node* next;
int hash;
s_type symbol;
} node_t;
struct array {
int cap;
int size;
n_type** h_table;
};
int add_to_array (array* arrTab, const char* name, int address) {
if(s_search(arrTab, name, NULL, NULL) == NULL){
s_type *symbol = (s_type*) calloc(1, sizeof(s_type));
symbol->name = strdup(name);
symbol->addr = addr;
n_type *newNode = (n_type*) calloc(1, sizeof(n_type));
newNode->next = NULL;
newNode->hash = nameHash(name);
newNode->symbol = *symbol;
int index = newNode->hash % arrTab->cap;
if(arrTab->h_table[index] == NULL){
arrTab->h_table[index] = newNode;
} else {
newNode->next = arrTab->h_table[index];
arrTab->h_table[index] = newNode;
}
//
arrTab->size++;
return 1;
}
return 0;
}
struct node* s_search (array* arrTab, const char* name, int* hash, int* index) {
int hashVal = nameHash(name);
hash = &hashVal;
int indexVal = *hash % arrTab->cap;
index = &indexVal;
s_type *symCopy = arrTab;
while (symCopy->h_table[*index] != NULL){
if(*hash == symCopy->h_table[*index]->hash){
return symCopy->h_table[*index];
}
symCopy->h_table[*index] = symCopy->h_table[*index]->next;
}
return NULL;
}
I cannot say for sure why the pointer always points to NULL; there is not enough code. Consider posting an MCVE.
The posted code however presents few problems to address.
First, it leaks memory like there is no tomorrow:
symbol_t *symbol = (symbol_t*) calloc(1, sizeof(symbol_t));
allocates some memory, and
newNode->symbol = *symbol;
copies the contents of that memory to the new location. The memory allocated still exists, and continues to exist after the function returns - but there's no way to get to it. I strongly recommend to not allocate symbol, and work directly with newNode->symbol:
newNode->symbol.name = strdup(name);
newNode->symbol.addr = addr;
The hash and index parameters to symbol_search seem to be planned as an out parameters. In that case, notice that the results of hash = &hashVal; and index = &indexVal; are invisible to the caller. You likely meant *hash = hashVal and *index = indexVal.
The biggest problem comes with sym_table_t *symCopy = symTab;.
symTab is a pointer. It points to an actual symbol table, a big piece of memory. After the assignment, symCopy points to the same piece of memory. Which means that
symCopy->hash_table[*index] = symCopy->hash_table[*index]->next;
modifies that piece of memory. Once the search is completed, the hash_table[index] is not the same as it was before the search. This could be a root of your problem. In any case, consider
node_t * cursor = symTab->hash_table[*index];
and work with this cursor instead.
As a side note, a search condition *hash == symCopy->hash_table[*index]->hash is strange. Every node in a given linked list has the same hash (check how you add them). The very first node would produce a match, even if the names are different.

Realloc behaviour using a pointer-to-pointer

I don't understand why when I run this code, the printf statements aren't working.
Here is the code:
typedef struct list {
int n;
struct list *next;
}List;
List **head;
List *tmp=malloc(sizeof(List));
tmp->n=34;
tmp->next=NULL;
List *tmp2=malloc(sizeof(List));
tmp2->n=45;
tmp2->next=NULL;
List *tmp3=malloc(sizeof(List));
tmp3->n=26;
tmp3->next=NULL;
head=malloc(sizeof(head));
head[0]=tmp;
head[1]=tmp2;
head=realloc(head,sizeof(head));
head[2]=tmp3;
printf("n of tmp:%d \n",head[0][0].n);
printf("n of tmp2:%d \n",head[1][0].n);
printf("n of tmp3:%d \n",head[2][0].n);
I think that the reason for that is probably realloc, but why ? I'm using it properly, no ? I have followed this tutorial http://www.tutorialspoint.com/c_standard_library/c_function_realloc.htm
Not only realloc, here
head = malloc(sizeof(head));
You allocate space for just one pointer, and then
head[0]=tmp;
head[1]=tmp2;
you try to store 2.
If you need space for 2 pointers, then the correct way is
head = malloc(2 * sizeof(*head));
/* ^ always dereference when using sizeof */
/* in this case it's not a problem, but in other cases it will be */
then you can fill the two elements, after checking the return value of malloc() so
head = malloc(2 * sizeof(*head));
if (head == NULL)
doSomething_But_DontDereference_head_mayBe_exit();
head[0] = tmp;
head[0] = tmp2;
Now, realloc(), what if realloc() returns NULL, and you alread overwrite the head pointer, now you can't do anything else with it, so
void *pointer;
pointer = realloc(head, 3 * sizeof(*head));
if (pointer == NULL)
doSomethingAndProbablyFree_head_and_abort();
head = pointer;
is much safer.
And also, note that you need to multiply the size of the pointer sizeof(*head) by the number of pointers you want to store.
ALWAYS CHECK THE RESULT OF malloc()
Your code is relatively broken. Here's a fairly sane way of going about this:
typedef struct list {
int n;
struct list *next;
} List;
int main() {
List *tmp1 = malloc(sizeof(List));
tmp1->n = 34;
tmp1->next = NULL;
List *tmp2 = malloc(sizeof(List));
tmp2->n = 45;
tmp2->next = NULL;
List *tmp3 = malloc(sizeof(List));
tmp3->n = 26;
tmp3->next = NULL;
List **head = malloc(2 * sizeof(List *));
head[0] = tmp1;
head[1] = tmp2;
head = realloc(head, 3 * sizeof(List *));
head[2] = tmp3;
printf("n of tmp1: %d\n", head[0]->n);
printf("n of tmp2: %d\n", head[1]->n);
printf("n of tmp3: %d\n", head[2]->n);
}
I haven't included this, but you should also verify that malloc() and realloc() return a non-null pointer.

invalid write size of 1 in C

I trying to write a queue(String Version) program in C by using linked lists.
Here is the structure:
struct strqueue;
typedef struct strqueue *StrQueue;
struct node {
char *item;
struct node *next;
};
struct strqueue {
struct node *front;//first element
struct node *back;//last element in the list
int length;
};
I creates a new StrQueue first
StrQueue create_StrQueue(void) {
StrQueue q = malloc(sizeof (struct strqueue));
q->front = NULL;
q->back = NULL;
q->length = 0;
return q;
}
makes a copy of str and places it at the end of the queue
void push(StrQueue sq, const char *str) {
struct node *new = malloc(sizeof(struct node));
new->item = NULL;
strcpy(new->item,str);//invalid write size of 1 ?
new->next = NULL;
if (sq->length == 0) {
sq->front = new;
sq->back = new;
} else {
sq->back->next = new;
sq->back = new;
}
sq->length++;
}
frees the node at the front of the sq and returns the string that was first in the queue
char *pop(StrQueue sq) {
if (sq->length == 0) {
return NULL;
}
struct node *i = sq->front;
char *new = sq->front->item;
sq->front = i->next;
sq->length --;
free(sq->front);
return new;
}
I got invalid write size of 1 at strcpy(new->item,str); I dont understand why I got this error.
Can anyone tell me why and tell me how should I fix it? Thanks in advance.
Okay, first things first, in the answer below I am NOT fixing your doubly linked list concepts, I am just showing you how you should fix the code above within the scope of your question. You may want to look into how doubly linked lists are done.
In:
void push(StrQueue sq, const char *str) {
struct node *new = malloc(sizeof(struct node));
new->item = NULL;
The next statement is wrong:
strcpy(new->item,str);
There are two ways you can solve it:
Make sure that *str is a valid pointer outside of the list management context while the list is being used.
Let the list manage the string allocation (and possibly deallocation).
is the quick and dirty method, it's easier to debug later but larger codebase makes it cumbersome.
cleaner looking code, but requires initial setup discipline, you should create object (string) management routines in addition to list management routines. can be cumbersome in its own right.
CASE 1: const char *str is guaranteed to be valid for life of StrQueue (this is what you are looking for really)
It should be:
new->item = str;
Here we assume str was a dynamic string allocated elsewhere
Now, in pop when you pop off the string you are okay. because the pointer you are returning is still valid (you are guaranteeing it elsewhere)
CASE 2: const char *str is not guaranteed to be valid for life of StrQueue
Then use:
new->item = strdup(str);
Now, in pop when you pop off the string you can either
de-allocate the strdup and not return anything, (not quite the same things as you did)
pass a container pointer to pop where contents of item are copied (clean)
return the popped off pointer, but you must deallocate it separately when you are done with it (ugly)
Which would make your pop function one of the following:
Case 2.1:
void pop(StrQueue sq) {
if (sq->length == 0) {
return NULL;
}
struct node *node = sq->front;
sq->front = node->next;
sq->length--;
free(node->item);
free(node);
}
Case 2.2:
char *pop(StrQueue sq, char *here) {
if (sq->length == 0) {
return NULL;
}
struct node *node = sq->front;
sq->front = node->next;
sq->length--;
strcpy(here, node->item);
free(node->item);
free(node);
}
Case 2.3:
char *pop(StrQueue sq) {
char *dangling_item = NULL;
if (sq->length == 0) {
return NULL;
}
struct node *node = sq->front;
sq->front = node->next;
sq->length--;
dangling_item = node->item;
free(node);
return dangling_item;
}
I got invalid write size of 1 at strcpy(new->item,str); I dont understand why I got this error. Can anyone tell me why and tell me how should I fix it?
Why:
This code:
new->item = NULL;
strcpy(new->item,str);//invalid write size of 1 ?
You're not suppose to pass a null pointer to the first argument, it should be a pointer to allocated memory. The reason why you're getting this error message, I can imagine, is because the implementation of strcpy probably looks like this:
for (int i = 0; str2[i]; i++) str1[i] = str2[i];
And in the first iteration of the for loop, it writes to address 0 (a read-only section of memory) - this gives you the invalid write of size 1. I'm not sure, however, why you are only getting a size of 1, though (I would imagine it would be the entire size of the string). This could be because either a) str is only of size 1 or b) because the signal, SIGSEGV stops the program.
How to fix:
Allocate space for new->item before calling strcpy, like this:
new->item = malloc (strlen (str) + 1); // + 1 for null-terminating character
But you could probably include some error checking, like this:
int len = strlen (str) + 1;
if (len){
new->item = malloc (len);
if (!new->item){
return;
}
}

Using fgets to read a .CSV file

I have already googled a lot about this, but I want to know one thing. I have a .csv file that I need to read, pass to a struct with linked list. The lines of file doesn't have the same size.
I'm thinking use fgets() to read each line, and then use strtok to get info through "," and pass to struct.
I'M USING LINUX.
typedef struct nodo
{
int row1;
char row2;
int row3;
struct nodo *next;
struct nodo *nant;
}nodo;
nodo* insert_last(nodo* base1, nodo* nv)
{
if(base1 == NULL)
base1 =nv;
base1->next = NULL;
while(base1->next != NULL)
base1 = base1->next;
base1->next = nv;
nv->nant = base1;
nv->next = NULL;
}
nodo* put2memory(nodo *base1)
{
nodo *nv;
FILE *fp1=fopen(xxx,"r");
char *tok;
while(fgets((buffer, sizeof(buffer),fp1) != NULL))
{
nv = (nodo*) malloc (sizeof(nodo));
nv->next=NULL;
tok = strtok(buffer,",");
nv->row1=tok;
tok = strtok(NULL,",");
nv->row2=tok;
tok = strtok(NULL,",");
nv->row3=tok;
insert_last(base1,nv);
}
free(nv);
}
int main()
{
nodo *base1;
put2memory(base1);
return 0;
}
I'm thinking doing like that but i'm returning "my friend" segmentation fault!!
SYNTAX FILE :
123,abc,23
23,d,444
.
.
.
insert_last doesn't look good to me for the case where base1 is null.
nodo* insert_last(nodo* base1, nodo* nv)
{
if(base1 == NULL)
base1 =nv;
At minimum I would put return nv here. Without that, what your code does is set nv->next to nv. (Or rather try to insert nv after base1 which will be set after `nv.)
As a broader point, note that your insert_last is O(n) since it must find the end of the list before inserting. This means inserting N elements is O(N2). A decent linked list implementation will track the tail element in memory and insert in constant time.
Update: read the rest of the code. This is also invalid:
nodo *base1;
put2memory(base1);
base1 has not been initialized and is a garbage value at this point. You're trying to use it as pointer.
Here's one suggestion for how to fix it:
Add return statements to insert_last. I suggest returning the head of the list. Even better would be to store both head and tail and avoid O(N) inserts.
Change your call to insert_last to do something like:
list_head = insert_last(base1,nv);
In main, you can do something like:
list_head = put2memory(NULL);
Update again: To illustrate O(1) insertion, here's an adjustment of your put2memory. Note that you'd eventually have to call free() on every list node.
nodo* put2memory()
{
nodo *head = NULL, *prev = NULL, *nv;
FILE *fp1=fopen(xxx,"r");
char *tok;
while(fgets((buffer, sizeof(buffer),fp1) != NULL))
{
nv = (nodo*) malloc (sizeof(nodo));
nv->next=NULL;
tok = strtok(buffer,",");
nv->row1=tok;
tok = strtok(NULL,",");
nv->row2=tok;
tok = strtok(NULL,",");
nv->row3=tok;
if (prev)
prev = prev->next = nv;
else
head = prev = nv;
}
return head;
}

Resources