I am writing a generic linked list in C (following Kyle Loudon's book),
but when it comes to free it, I got a segfault.
Data types used for the list definition:
typedef struct list_elem_
{
void *data;
struct list_elem_ *next;
} list_elem;
typedef struct link_list_
{
int size;
int (*match)(const void *key1, const void *key2);
void (*destroy)(void *data);
list_elem *head;
list_elem *tail;
} link_list;
Function that is used to destroy caller's data:
void destroy_data(void *data)
{
if(data)
free(data);
return;
}
Destroy passed by a function pointer:
void list_init(link_list *list, void (*destroy)(void *data))
{
list->size = 0;
list->destroy = destroy;
list->head = NULL;
list->tail = NULL;
return;
}
Free the list:
void list_destroy(link_list *list)
{
void* data;
while(list_size(list) > 0)
if(list_rem_next(list, NULL, (void**)&data) == 0 && list->destroy != NULL)
list->destroy(data);
memset(list,0,sizeof(link_list));
return;
}
The segfault is triggered by the free in the destroy_data.
============== EDIT ====================
Remove a list element
int list_rem_next(link_list *list, list_elem *element, void **data)
{
list_elem *OldElement;
if(list_size(list) ==0)
return -1;
/* Remove the head */
if(element == NULL)
{
*data = list->head->data;
OldElement = list->head;
list->head = list->head->next;
if(list_size(list) == 1)
list->tail = NULL;
/* Remove other than head */
} else {
if(element->next == NULL)
return -1;
*data = element->data;
OldElement = element->next;
element->next = element->next->next;
if(element->next == NULL)
list->tail = element;
}
free(OldElement);
list->size--;
return 0;
}
=================== EDIT 2 ==========================
Inside main
link_list myList;
int i;
int *iptr;
char *chrPtr;
list_init(&myList, destroy_data);
for(i = 0; i < 4; i++)
{
iptr = malloc(sizeof(int));
*iptr = i;
list_ins_next(&myList, NULL, iptr);
}
chrPtr = malloc(sizeof("uno\0"));
chrPtr = "uno\0";
list_ins_next(&myList,NULL,chrPtr);
chrPtr = malloc(sizeof("stringa numero due\0"));
chrPtr = "stringa numero due\0";
list_ins_next(&myList,NULL,chrPtr);
chrPtr = NULL;
iptr = NULL;
getchar();
list_destroy(&myList);
In your code from main() you have:
chrPtr = malloc(sizeof("uno\0"));
chrPtr = "uno\0";
Why the explicit \0 when C adds one after it automatically?
Can you say 'memory leak'? You allocate memory; you immediately overwrite the only pointer to that allocated memory by assigning the address of the string literal to the same pointer.
What happened to strcpy()?
As a result of this abuse, you are passing unallocated memory pointers to free(); in fact, you're passing pointers to string constants to free(). That's undefined behaviour and can very easily lead to crashes!
The problem wasn't in the code you showed at first; it was in the other code. That's also why the MCVE (Minimal, Complete, Verifiable Example) — aka SSCCE (Short, Self-Contained, Correct Example) mentioned by Greg Hewgill — is so important. There's no way for us to debug code you don't show — and it is unnecessarily hard work establishing that the problem isn't in the code you do show.
You could probably use:
chrPtr = strdup("uno"));
list_ins_next(&myList, NULL, chrPtr);
chrPtr = strdup("stringa numero due");
list_ins_next(&myList,NULL,chrPtr);
to avoid the trouble. Failing that, you could use:
chrPtr = malloc(sizeof("uno"));
strcpy(chrPtr, "uno");
list_ins_next(&myList, NULL, chrPtr);
chrPtr = malloc(sizeof("stringa numero due"));
strcpy(chrPtr, "stringa numero due");
list_ins_next(&myList,NULL,chrPtr);
Neither of these checks that the memory allocation succeeded; that too should be done in production code, and arguably in school assignments.
Note that sizeof("string literal") counts the null byte, so the length is correct. Note equally that strlen("string literal") does not count the null byte — be careful!
There could still be other problems in the code; I've not verified that everything is clean. But this part will be cleaner and more likely to work correctly.
The functions list_size() and list_ins_next() are not shown. The size can be guessed; the list_ins_next() is not so easy.
I also observe that the code inserts 4 integers and then 2 strings into the list. There's no way to know that's what was inserted after the fact. The code in main() is dreadfully non-general. The support code can handle it — but heterogeneous lists are tricky; don't try it until you don't run into this sort of problem. One list of integers; fine. One list of strings; fine. One list of integers and strings — dodgy!
Related
I wrote a program that creates Linkedlists with two values.
It worked when I just had int values in it but now that I added char* this error messages shows
runtime error: null pointer passed as argument 1, which is declared to never be null
As mentioned before this worked fine until I added char* to the constructor and the struct. Not sure where it goes wrong as the error seems to come from different lines in the code everytime I run it... So what do i need to change ?
#include <stdio.h>
#include <cs50.h>
#include <string.h>
typedef struct node {
int val;
char* name;
struct node *next;
} node_t;
void addFirst(int value, char* word, node_t** nd) {
//initialize new node, allocate space, set value
node_t * tmp;
tmp = malloc(sizeof(node_t));
tmp->val = value;
strcpy(tmp->name, word);
//let the new nodes next pointer point to the old head
tmp->next = *nd;
//Make tmp the head node
*nd = tmp;
}
int findItem(int value,char* word, node_t *nd) {
if(nd->val == value)
return 0;
while(nd->next != NULL) {
if(nd->val == value && strcmp(word, nd->name) == 0)
return 0;
if(nd->next != NULL)
nd = nd->next;
}
return -1;
}
int main (void) {
node_t *head = malloc(sizeof(node_t));
head->val = 0;
strcpy(head->name, "");
head->next = NULL;
addFirst(15, "word", &head);
addFirst(14,"word2", &head);
printf("%i \n", findItem(15, "word", head));
}
The problem is in strcpy(head->name, "");. Here, you;re trying to use the memory location pointer to by head->name, but you never assigned a valid memory to it.
You need to make sure that the pointer points to a valid memory location, before you write to / read from that memory location. Attempt to access invalid memory invokes undefined behavior.
This is applicable for other uninitialized instances of name, too.
If you can live with POSIX standard, instead of strcpy(), you can make use of strdup()
I try to write my own custom malloc and free function in c. I worked around 12 hours on this and tried lots of things. But it doesn't work.
Maybe you guys can figure out the error. Allocated memory gets removed from the list with a next pointer to a specific address to identify it later in the free function. The current error is a segmentation fault 11 in the split method.
C-File:
Head:
#define MAGIC ((void*)0xbaadf00d)
#define SIZE (1024*1024*1)
typedef struct mblock {
struct mblock *next;
size_t size;
char memory[];
}mblock;
char memory[SIZE];
static struct mblock *head;
malloc:
void *halde_malloc (size_t size) {
printf("Starting\n");
printf("%zu\n",size);
if(size <= 0) {return NULL;}
if(head == NULL){
initializeBlock();
printf("Memory initialized\n");
}
mblock *temp_block = head;
while(temp_block != NULL) {
printf("IN\n");
if(temp_block->size == size) {
list_remove(temp_block);
temp_block->next = MAGIC;
return (void*)(temp_block);
} else if(temp_block->size > size) {
size_t temp_size = temp_block->size;
printf("size IS more than equal\n");
list_split_AND_Remove(temp_size - size, temp_block);
temp_block->size = size;
temp_block->next = MAGIC;
return (void*)(temp_block);
}
temp_block = temp_block->next;
printf("One block checked\n");
}
errno = ENOMEM;
return NULL;
}
Initialize:
void initializeBlock(){
printf("Initializing\n");
head = (mblock*)memory;
head->size=sizeof(memory)-sizeof(mblock);
head->next=NULL;
}
Split:
void list_split_AND_Remove(size_t size, mblock *lastBlock) {
printf("Split\n");
mblock *new = (void*)((mblock*)lastBlock+size+sizeof(mblock));
new->size = size - sizeof(mblock);
new->next = lastBlock->next;
lastBlock->next = new;
printf("START REMOVE");
list_remove(lastBlock);
}
Remove:
void list_remove(mblock *p) {
printf("Remove\n");
mblock *temp_block = head;
if(p == head) {
if(head->next == NULL) {
head = NULL;
return;
} else {
head = p->next;
return;
}
}
while(temp_block->next != NULL) {
if(temp_block->next == p) {
printf("Found P:");
temp_block = p->next;
return;
}
temp_block = temp_block->next;
}
}
Free:
void halde_free (void *ptr) {
printf("FREE\n");
mblock *new_block = ptr;
if(new_block->next == MAGIC) {
new_block->next = head;
head = new_block;
} else {abort();}
}
Issues with your code include, but are not necessarily limited to:
list_remove() does not actually remove the specified block from the list unless it happens to be the current list head. In every other case, therefore, halde_malloc() corrupts the list after calling list_remove() when it modifies the node's next pointer.
list_split_AND_Remove() performs incorrect pointer arithmetic. Specifically, mblock *new = (void*)((mblock*)lastBlock+size+sizeof(mblock)); does not do what you appear to want to do, because pointer arithmetic operates in units the size of the pointed-to type, whereas the size argument and the result of the sizeof operator have units of individual bytes. (Also, both casts are useless, albeit not harmful in themselves.)
Your allocator returns a pointer to the block header, not to its data. As a result, the user will very likely overwrite the block header's contents, leading to havoc when you later try to free that block.
You seem to assume that mblock objects have an alignment requirement of 1. That might not be true.
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;
}
}
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 = #
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.
I have a struct that I use to build a linked list as below;
struct my_struct{
char a[16];
struct my_struct *next;
}
I free that linked list by below function;
void free_my_list(struct my_struct* recv) {
if (recv->next != NULL)
free_my_list(recv->next);
free(recv);
recv = NULL;
}
In my program, I use a struct _my_list over and over but free and malloc it every time as below:
struct my_struct *_my_list;
free_my_list(_my_list);
_my_list = (my_list *) malloc(sizeof(my_list));
_my_list->next = NULL;
Every time I fill the list, I print char arrays and then reset _my_struct by above code.
Above code works fine on Ubuntu pc, but on Cent OS after printing first list(after first malloc _my_struct) correctly, following list are printed as corrupted data.
When I don't free and malloc memory during whole program execution it works fine in Cent OS too but I should reset list _my_list between printf() calls.
_my_list is filled and printed via below functions;
/*prints every item in my_list*/
void print_my_list(struct my_struct *recv, FILE *fd) {
my_list *tmp;
tmp = recv;
while (tmp != NULL) {
if (fwrite(tmp->a, 1, strlen(tmp->a), fd) == -1) {
pritnf("error\n");
}
tmp = tmp->next;
}
}
/*Add 'a' string to _my_list*/
void add_recv_to_list(struct my_struct **recv_list, char *recv) {
struct my_struct *tmp;
tmp = *recv_list;
if (*recv_list == NULL) {
*recv_list = (struct my_struct *) malloc(sizeof(struct my_struct));
tmp = *recv_list;
} else {
while ((tmp->next) != NULL) {
tmp = tmp->next;
}
tmp->next = (struct my_struct *) malloc(sizeof(struct my_struct));
tmp = tmp->next;
}
strncpy(tmp->a, recv, MAX_NAME_LEN);
tmp->next = NULL;
}
What can be the reason, any ideas?
I think that your problem may start here:
struct my_struct *_my_list;
free_my_list(_my_list);
_my_list = (my_list *) malloc(sizeof(my_list));
_my_list->next = NULL;
When you initialize the struc: struct my_struct *_my_list; you don't assign it any value, so it holds whatever garbage data was in memory beforehand. When you free() that in free_my_list, the behavior is undefined (you are freeing something that you never malloc()ed - so the result may very well be corruption of something or other later on. Try changing your declaration to: struct my_struct *_my_list = NULL; (always a good practice to initialize pointers to NULL, anyway) and changing your free_my_list function to:
void free_my_list(struct my_struct* recv) {
if (recv == NULL)
return;
if (recv->next != NULL)
free_my_list(recv->next);
free(recv);
recv = NULL;
}