Segmentation fault at free() - c

I'm getting a segmentation fault when I do free() in the delete function of the following linked list implementation. Please take a look and tell me where I am going wrong. When I run this program with valgrind, there is no seg. fault, it runs fine. So I am not able to figure out the problem.
typedef struct node {
char name[100];
int id;
struct node* next;
} Node;
void insert(Node** p, char* _name, int _id)
{
Node *temp, *prev;
temp = malloc(sizeof(struct node));
temp->next = NULL;
strcpy(temp->name,_name);
temp->id = _id;
if(*p == NULL) {
*p = temp;
}
else {
for(prev = *p; prev->next!=NULL; prev=prev->next);
prev->next=temp;
}
}
/* Delete entry
#params p first element
_id ID to delete
*/
void delete_by_id(Node** p, int _id) {
Node *temp, *prev;
prev = NULL;
for(temp = *p; temp!= NULL; prev = temp, temp=temp->next) {
if(temp->id == _id) {
printf("Deleting entry with id: %d\n", temp->id);
if(prev == NULL)
*p = temp->next;
else
prev->next= temp->next;
free(temp);
return;
}
}
}
Here is part of the code from the main program:
Node* p;
int main() {
...
...
buf[rval]=0;
char* tokens = strtok(buf, "+");
char* strArray[5]; /* up-to 5 words can be stored */
int n = 0;
while (tokens)
{
strArray[n] = malloc(strlen(tokens) + 1);
strcpy(strArray[n++], tokens);
tokens = strtok(NULL, "+");
}
int type = 0;
if(strcmp(strArray[0], "1") == 0)
type = 1;
else
type = 2;
char* name = "";
if(type == 1) {
name = strArray[1];
insert(&p, name, clients[i]);
display(&p);
} else {
name = strArray[1];
rval = search(&p, name);
if(rval) {
delete_by_id(&p, rval);
display(&p);
}
}
for (i = 0; i < 5; i++)
{
if (strArray[i]) // check for null data
free(strArray[i]);
}
...
...
}
int search(Node** p, char* _name) {
Node *temp;
for (temp = *p; temp!= NULL; temp = temp->next) {
if (strcmp((char *)temp->name, _name)==0) {
printf("Name matched: %s\n", temp->name);
return temp->id;
}
}
return 0;
}
Valgrind is complaining about the malloc and free used for strArray but not for the linked list.

Print out the addresses returned by malloc(), and also print out the value of temp immediately before the call to free(). Make sure that what's being passed to free() matches what you expect. If somehow you are passing a pointer to free() that didn't come from malloc(), you can encounter problems like you are seeing.
There's also a possibility that the function delete_by_id() is using an invalid pointer. The p parameter is dereferenced before it's checked for NULL. I recommend walking through the function in your debugger and making sure that all of the pointers look as you expect them to look.

Let your program dump core and analyze the core in GDB:
gdb -c yourprog.core yourprog
then do a full backtrace:
(gdb) bt full
This will show you where exactly the reason for your segfault is and what values were passed to the function.
(edit) Oh, and compile your program with the GCC -g switch to have debugging information.

Run your program through valgrind. Segfaults on free are usually due to writes outside of the allocated memory (which overwrites/corrupts the wrappers that the system places before/after allocated memory). Valgrind is usually the easiest way to find out when the writes in question happens.

Related

Can you tell me why my function to select a random string from a linked list isn't working?

I am building a program for a project. One of the requirements for the project is a function that selects a random node from my linked list of 3000 words.
I tried to do this by creating a function that generates a random number from 0 to 2999. After this, I created another function that follows a for loop starting from the head and moving to the next node (random number) times.
My random number generator is working fine, but my chooseRand() function is not.
Please help, the random number generator and the chooseRand() function are the last two functions above main. Also, my code is a bit messy, sorry.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
int nodeNum;
int chances;
char* secret;
/*Node of linked list*/
typedef struct node {
char *data;
struct node *next;
} node;
node *start = NULL;
node *current;
/*Void function to print list*/
void printList(struct node *node)
{
while (node != NULL) {
printf("%s ", node->data);
node = node->next;
}
}
/*Appending nodes to linked list*/
void add(char *line) {
node *temp = malloc(sizeof(node));
temp->data = strdup(line);
temp->next = NULL;
current = start;
if(start == NULL) {
start = temp;
} else {
while(current->next != NULL) {
current = current->next;
}
current->next = temp;
}
}
void readfile(char *filename) {
FILE *file = fopen(filename, "r");
if(file == NULL) {
exit(1);
}
char buffer[512];
while(fgets(buffer, sizeof(buffer), file) != NULL) {
add(buffer);
}
fclose(file);
}
node *listSearch(node* start, char *nodeSearched){
node *p;
for (p = start; p != NULL; p = p->next)
if (strcmp(p->data, nodeSearched) == 0)
printf("%s", p->data);
return NULL;
}
node *letterSearch(node* start, int i){
node *p;
for (p = start; p != NULL; p = p->next)
if (strlen(p->data) == i)
{
printf("\n %s", p->data);
free(p);
p = NULL;
}
return NULL;
}
void chooseRand(struct node* start)
{
node* p;
int n;
p = start;
for(n = 0; n != nodeNum; n++)
{
p = p->next;
}
printf("%s", p->data);
}
void randNum(int lower, int upper)
{
srand(time(0));
nodeNum = (rand() % (upper - lower + 1)) + lower;
}
int main(){
randNum(0, 2999);
chooseRand(start);
return 0;
}
As others has said, the problem is that you don't have initialized the linked list yet, because of what your are getting a segmentation fault. So, in addition to initializing the list first, you must also introduce checks in the implementation of the chooseRand function, to check that if you reach the end of the list, without reaching the desired index, you stop executing the foor loop, otherwise you will be potentially exposed to segmentation faults.
Improve chooseRand implementation, to prevent segmentation fault either, when the linked list is empty, or when the randomly generated nodeNum is grater than the the index of the list's last item:
void chooseRand(struct node* start)
{
node* p;
int n;
p = start;
if(p == NULL){
printf("The list is empty!");
return;
}
// Also, we must stop the iteration, if we are going to pass the end of the list, you don't want a segmentation fault because trying to access a NULL pointer:
for(n = 0; n != nodeNum && p->next != NULL; n++)
{
p = p->next;
}
// If p == NULL, the list was not big enough to grab an item in the `nodeNum` index:
printf("%s", (n != nodeNum) ? "Not found!" : p->data);
}
Initialize the linked list, with the content of some file on disk:
int main(){
randNum(0, 2999);
// Fill the linked list with the content of a file in disk, calling your method:
char fileName[] = "PutYourFileNameHere.txt";
readfile(fileName);
chooseRand(start);
return 0;
}
There is another fix that you must do, and it is free the memory being hold by the pointer field data of your structure, in the implementation of your method letterSearch. Inside the if statement, you're de-allocating the memory hold by the p pointer, but you aren't de-allocating the memory assigned to the pointer p->data, this will cause a memory leak. When you in the function add, initialized p->data with the result of the call to the function strdup(line), what this function does is allocate enough memory in the heap, copies to it the buffer pointed by the line argument, and give to you back a pointer to the new allocated memory, that you're storing in the p.data field; a pointer that you should free when you're done with it, otherwise your program will have potential memory leaks. So I will modify your function letterSearch as folollows:
node *letterSearch(node* start, int i){
node *p;
for (p = start; p != NULL; p = p->next)
if (strlen(p->data) == i)
{
printf("\n %s", p->data);
// Free p->data before free p:
free(p->data);
free(p);
p = NULL;
}
return NULL;
}
References:
strdup

print from users input linked list of struct

I am required to have a list of structs of sentence nodes that point to a struct of word nodes. I am trying to print the user's input.
I have a program that runs properly when I manually give it the input (see test section of the code). It does not, however, work when I use my input1() function.
I've tried debugging it, but I can't seem to find the problem.
I removed all printf lines that I used to debug. I also removed all the irrelevant code.
I am looking to know how to fix it and what is wrong so I can run it with no problems.
What I learned from debugging it is that (only when using input1() and not in the test) the head is overwritten every time and all the nodes as well.
I also tried using a double pointer instead of returning para but that didn't help.
any help will be appreciated,
thanks in advance
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
typedef struct word
{
char * ch;//poiter to char
}
W;
typedef struct sentence
{
W * currentWord;//pointer to a word
int lineNumber;// holds the line number
int numbersOfWords;//holds the number of words
struct sentence* link;
}
sent;
typedef struct list
{
sent* head;
int count;
}
LISTS;
LISTS* createList()
{
LISTS* list;
list= (LISTS*) malloc (sizeof (LISTS));
if (list)
{
list-> head = NULL;
list-> count = 0;
}
return list;
} // createList
void printList(LISTS* list)
{
sent *temp = list -> head;
//iterate the entire linked list and print the data
while(temp != NULL)
{
printf("%s\n", temp->currentWord->ch);
temp = temp->link;
}
// printf("NULL\n");
}
void insertSentList (LISTS* list, W* itemPtr)
{
sent* newPtr; //new node
if (!(newPtr = (sent * ) malloc(sizeof(sent)))){
printf(" Memory can not be allocated.");
return;
}
newPtr->currentWord = itemPtr;
newPtr->link = NULL;
if(list->head == NULL)
{
list->head = newPtr;
}else{
sent* current = list->head;
while(current->link != NULL){
current = current->link;
}
current -> link = newPtr;
}
(list->count)++;
return;
} // insertList
LISTS * input1(LISTS *para)
{
char * line;
line = (char * ) malloc(1000 * sizeof(char));
line[0] = '\0';
while (line[0] != '\n')
{
W word;
word.ch = (char * ) malloc(100);
printf(" Please input a line : ");
fgets(line, 1000, stdin);
if(line[0] != '\n'){
strcpy(word.ch, line);
insertSentList(para,&word);
}
}
free(line);
return para;
}
int main()
{
///////////////////test////////////////
LISTS* list = createList();
W word;
word.ch= "word0 ";
W word1;
word1.ch= "word1 ";
W word2;
word2.ch= "word2";
insertSentList(list,&word);
insertSentList(list,&word1);
insertSentList(list,&word2);
insertSentList(list,&word);
insertSentList(list,&word1);
insertSentList(list,&word2);
printList(list);
///////////////////test////////////////
LISTS *para = createList();
para= input1(para);
printList(para);
return 0;
}
Main problem with the posted code is that "ownership" of the sent and W objects in a list is not well defined. For example word.ch= "word0 "; in main sets the ch pointer pointing to a string literal (which it does not own), but word.ch = malloc(100); in input1 points it to dynamically allocated memory (which it should own, and remember to free later). Because of this, memory allocations cannot be tracked reliably and, even in the cases where things appear to "work", there are multiple memory leaks. It also breaks when the inserted objects are local variables that do not live for the entire lifetime of the list object.
The simplest (if not necessarily the best or most efficient) solution would be to dynamically allocate all objects that go into the list, make the list own them all, and add a function to cleanup once done. To that end insertSentList could be modified as follows.
void insertSentList (LISTS* list, W* itemPtr)
{
sent* newPtr; //new node
if (!(newPtr = malloc(sizeof(sent)))){
printf(" Memory can not be allocated.\n");
return;
}
W *newItem = malloc(sizeof(W)); // <-- make a deep copy of the `itemPtr` argument
newItem->ch = strdup(itemPtr->ch); // including a copy of the string itself
newPtr->currentWord = newItem; // <-- save the copy in the list, not the argument
newPtr->link = NULL;
if(list->head == NULL)
{
list->head = newPtr;
}else{
sent* current = list->head;
while(current->link != NULL){
current = current->link;
}
current->link = newPtr;
}
list->count++;
} // insertList
For proper cleanup and to avoid memory leaks, the following freeList should be called for each list pointer returned by createList and filled by insertSentList.
void freeList(LISTS *list)
{
sent *temp = list->head;
while(temp != NULL)
{
sent *next = temp->link;
free(temp->currentWord->ch);
free(temp->currentWord);
free(temp);
temp = next;
}
free(list);
}

Linked List value changes in gdb

I have a C linked list that looks like this:
typedef struct Node {
struct Node *child;
void *value;
} Node;
typedef struct LinkedList {
Node *head;
} LinkedList;
To test that everything is working properly, I have a main program that reads from a file, line by line, and stores each line in the following Node. Then, once the file reaches its end, I run through the linked list and print all of the lines.
However, when I test it, it only prints blank lines, except for the last line in the file, which gets printed normally. In addition, despite the fact that all the strings are malloc'd before they are stored in the nodes, I get a "pointer being free was not allocated error." I've gone through this pretty extensively in gdb and can't seem to figure out what I'm doing wrong. Perhaps somebody else can help me out here? Here's the rest of my code:
int main(int argc, char **argv) {
if (argc>1) {
FILE *mfile = fopen(argv[1], "r");
if (mfile!=NULL) {
char c;
char *s = (char*) malloc(1);
s[0] = '\0';
LinkedList *lines = (LinkedList*) malloc(sizeof(LinkedList));
while ((c=fgetc(mfile))!=EOF) {
if (c=='\n') {
setNextLine(lines, s);
free(s);
s = (char*) malloc(1);
s[0] = '\0';
}
else s = append(s, c);
}
if (strlen(s)>0) {
setNextLine(lines, s);
free(s);
}
fclose(mfile);
printList(lines);
LLfree(lines);
} else perror("Invalid filepath specified");
} else perror("No input file specified");
return 0;
}
void setNextLine(LinkedList *lines, char *line) {
struct Node **root = &(lines->head);
while (*root!=NULL) root = &((*root)->child);
*root = (Node*) malloc(sizeof(Node));
(*root)->child = NULL;
(*root)->value = line;
}
char *append(char *s, char c) {
int nl = strlen(s)+2;
char *retval = (char*) malloc(nl);
strcpy(retval, s);
retval[nl-2] = c;
retval[nl-1] = '\0';
free(s);
return retval;
}
void printList(LinkedList *lines) {
Node *root = lines->head;
while (root!=NULL) {
char *s = (char*) root->value;
printf("%s \n", s);
root = root->child;
}
}
void LLfree(LinkedList *list) {
if (list->head!=NULL) NodeFree(list->head);
free(list);
return;
}
void NodeFree(Node *head) {
if (head->child!=NULL) NodeFree(head->child);
free(head->value);
free(head);
return;
}
It appears that there are several things that could be changed in the code.
Perhaps the one that is most likely to help would be that memory improperly freed.
Change:
setNextLine(lines, s);
free(s);
s = (char*) malloc(1);
to:
setNextLine(lines, s);
// free(s);
s = (char*) malloc(1);
The pointer 's' is still pointing to what was just assigned to the previous node's 'value'. Hence, calling 'free(s)' is actually freeing the node's 'value'.
Try doing this
void NodeFree(Node *head)
if (head->child!=NULL)
NodeFree(head->child);
free(head->value);
free(head->child);
free(head);
head->value = NULL;
head->child = NULL;
head = NULL;
return;
}
The setNextLine() function is appending the 's' poitner to the node value, and then that same pointer is getting freed after that call in the while loop.
That's why you'll get a double free fault when NodeFree() tries to free head->value.
And the fact that you get the last line could be just because the address pointed by 's' for the last line (which got freed like all the previous lines) is still unused although its not allocated to your pointer anymore.
You should make a copy of the line pointed by 's' in setNextLine() so you can work with the 's' pointer for the rest of lines.

Reverse a sentence using stack in C

i want to reverse a sentence using stack in c.
eg. how are you => you are how.
i have written the following program
#include<stdio.h>
#include<conio.h>
struct rev
{
char *var;
struct rev *next;
};
struct rev *top=NULL;
struct rev *temp,*test;
main()
{
int start, j = 0;
char *p="Hi, How are you? Hope everything is fine";
char *s;
char *t;
*t = '\0';
s = p;
while(1) {
if(*p == ' '|| *p == '\0') {
printf("Inside if \n");
*(t + j) = '\0';
printf("This is t %s\n",t);
if(top == NULL) {
temp = (struct rev *)malloc(sizeof(struct rev));
temp->next = NULL;
temp->var=t;
top = temp;
} else {
temp = (struct rev *)malloc(sizeof(struct rev));
printf("This is going in stack %s\n", t);
temp->var = t;
temp->next = top;
top = temp;
printf("This is top %s\n", top->var);
}
j = 0;
} else {
*(t+j) = *p;
printf("%c\n", *p);
j++;
}
if(*p == '\0') {
break;
}
//printf("%c",*p);
p++;
}
struct rev *show;
show = top;
while(show != NULL) {
printf("%s\n", show->var);
show = show->next;
}
getch();
}
It is storing correctly but on traverse it is giving only the final element.
i am not be able to figure it out what is the problem.
Here is my output window:-
Read complete line. Tokenize string on whitespace, pushing each word to the stack. Pop the stack while printing.
Useful functions:
fgets
strtok
Complete solution can be done in less than 20 lines (including structure definitions, header files, etc.)
You also have a problem with undefined behavior in your code. You have a pointer p which points to a constant array of characters (all string literals are constant arrays of characters). Then you try to modify that constant array.
You might want something like this instead:
char arr[] = "Some string here";
char *p = arr;
And you have another case of undefined behavior as well: You have the pointer t which is not initialized. You then continue to dereference it. I would say that you are lucky to not get a crash.
You also don't update t in the loop, which you probably should.
First of all your char *t is just a pointer, make it point to malloced memory and then go ahead... I dont understand how the code is even running ... You are doing *(t + j) when t is actually pointing to junk.
On first look You are overwriting t... after parsing a string. i.e you set j = 0 and overwrite previously stored string and your struct rev hold a pointer to this t hence
you are getting you? you? you? as output. instead of having char *var in struct rev point to t .. your char *var point to a malloced memory and do strcpy or strtok
I just did a rough modification of your code and it worked for me on linux + gcc ... Here's the code:
#include<stdio.h>
#include <stdlib.h>
struct rev
{
char *var;
struct rev *next;
};
struct rev *top=NULL;
struct rev *temp,*test;
main()
{
int start, j = 0;
char *p="How are you?";
char *s;
char *t;
t = malloc(1000);
if (t == NULL) {
//OUT OF MEMORY
exit(1);
}
s = p;
while(1) {
if(*p == ' '|| *p == '\0') {
printf("Inside if \n");
*(t + j) = '\0';
printf("This is t %s\n",t);
if(top == NULL) {
temp = (struct rev *)malloc(sizeof(struct rev));
temp->next = NULL;
temp->var = malloc(100);
if (temp->var == NULL) {
//OUT OF MEMORY
exit(1);
}
strcpy(temp->var, t);
top = temp;
} else {
temp = (struct rev *)malloc(sizeof(struct rev));
printf("This is going in stack %s\n", t);
temp->var = malloc(100);
if (temp->var == NULL) {
//OUT OF MEMORY
exit(1);
}
strcpy(temp->var, t);
temp->next = top;
top = temp;
printf("This is top %s\n", top->var);
}
j = 0;
} else {
*(t+j) = *p;
printf("%c\n", *p);
j++;
}
if(*p == '\0') {
break;
}
//printf("%c",*p);
p++;
}
struct rev *show;
show = top;
while(show != NULL) {
printf("%s\n", show->var);
show = show->next;
}
//getch();
}
Here's the output:
H
o
w
Inside if
This is t How
a
r
e
Inside if
This is t are
This is going in stack are
This is top are
y
o
u
?
Inside if
This is t you?
This is going in stack you?
This is top you?
you?
are
How
PS: I dont undertand in which part of the code you are implementing push|pop ... You are using list and telling you want a stack. Stack and List are 2 different data-structures.
You can start by initializing variable t to point to a valid memory address.
It seems that the logic of "show" is written incorrectly-
show = top;
while(show != NULL) {
printf("%s\n", show->var);
show = show->next;
}
pointing show to top and printing "show->next" is incorrect way of popping out from stack.
Here is an example of pop function-
int pop(STACK **head) {
if (empty(*head)) {
fputs("Error: stack underflow\n", stderr);
abort();
} else {
STACK *top = *head;
int value = top->data;
*head = top->next;
free(top);
return value;}}

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

Resources