"A heap has been corrupted" after using malloc twice - c

I have a linked list of "words" that I'm trying to build, I made a function called "add_to_mem" which adds to the linked list the next word.
I've made a couple of checks on the code, and found out that he works twice - once when the linked list is a NULL, and once when it's not - and it is does working, but in the third time I'm calling to the method - I'm getting an "A heap has been corrupted" error.
The code:
typedef struct { unsigned int val : 14; } word;
typedef struct machine_m
{
word * current;
int line_in_memo;
char * sign_name;
struct machine_m * next_line;
}Machine_Memo;
The function:
/*Adding a word to the memory.*/
void add_to_mem(word * wrd, int line, char * sign_name)
{
Machine_Memo * temp = NULL, *next = NULL;
if (machine_code == NULL)
{
machine_code = (Machine_Memo *)malloc(sizeof(Machine_Memo));
if (machine_code == NULL)
{
printf("Memory allocation has failed.");
exit(1);
}
machine_code->current = wrd;
machine_code->line_in_memo = line;
machine_code->sign_name = sign_name;
machine_code->next_line = NULL;
}
else
{
printf("token has been reached");
temp = machine_code;
next = (Machine_Memo *)malloc(sizeof(Machine_Memo)); //Line of error
if (next == NULL)
{
printf("MEMORY ALLOCATION HAS FAILED. EXITING PROGRAM.\nThe problem has occured on code line %d", 775);
exit(0);
}
next->current = wrd;
next->line_in_memo = line;
next->sign_name = sign_name;
next->next_line = NULL;
while (temp->next_line != NULL)
{
temp = temp->next_line;
temp->next_line = next;
}
}
}

As far as I understand the code, it does not create a linked list. it creates nodes, but does not link them together.
at first call, the machine_code (head of list) is created.
at next call, the node 'next' is created, however, the loop:
while (temp->next_line != NULL)
{
temp = temp->next_line;
temp->next_line = next;
}
does nothing as the 'machine_code->next' value is null. so code inside the loop is not executed. and we do not get here a linked list, but sporadic nodes not connected each to other.
you may wanted (as pointed at the other post here) to have something like:
while (temp->next_line != NULL)
{
temp = temp->next_line;
}
temp->next_line = next;

Here
while (temp->next_line != NULL)
{
temp = temp->next_line;
temp->next_line = next; // move out of the loop
}
you may want to move the last assignment outside of the loop.

Related

Problem passing non-duplicate entries from two linked lists to a third

I tried to make a function, that takes two linked lists' heads as an input, and creates a third one, that only includes the entries from both lists, that only appear in their respective list. The problem is that when I print the third list, I see that it includes every entry from both lists.
Example list 1: 1->13->32->4->5, list 2: 2->13->42->5
Desired outcome: list 3 1->32->4->2->2, actual outcome: 1->13->32->4->5->2->13->42->5
The head of every list is declared as a global variable.
typedef struct list_path *lp;
struct list_path
{
int row,column;
lp next;
};
lp head_list_1,head_list_2,head_list_3,temp_list,aux_path,temp_union,temp_insert_union,aux_union,aux_path_1,aux_path_2,head_list;
void path_union(lp head_list_1, lp head_list_2)
{
aux_path_1 = head_list_1;
aux_path_2 = head_list_2;
int exist;
while (aux_path_1 != NULL)
{
exist = 0;
while (aux_path_2 != NULL)
{
if (aux_path_1->row == aux_path_2->row && aux_path_1->column == aux_path_2->column)
{
exist=1;
}
aux_path_2 = aux_path_2->next;
}
if (exist == 0)
{
insert_union(head_list_3, aux_path_1->row, aux_path_1->column);
}
aux_path_1 = aux_path_1->next;
}
aux_path_1 = head_list_1;
aux_path_2 = head_list_2;
while (aux_path_2 != NULL)
{
exist = 0;
while (aux_path_1 != NULL)
{
if (aux_path_2->row == aux_path_1->row && aux_path_2->column == aux_path_1->column)
{
exist = 1;
}
aux_path_1 = aux_path_1->next;
}
if (exist == 0)
{
insert_union(head_list_3, aux_path_2->row, aux_path_2->column);
}
aux_path_2 = aux_path_2->next;
}
}
void insert_union(lp head_list_3, int key_a, int key_b)
{
lp union_temp;
lp list_aux = head_list_3;
while (list_aux->next != NULL)
{
list_aux = list_aux->next;
}
union_temp = (lp)malloc(sizeof(struct list_path));
union_temp->row = key_a;
union_temp->column = key_b;
list_aux->next = union_temp;
union_temp->next = NULL;
}
The first function uses 2 nested whiles to find which entries appear only once and the second one passes those keys to the third list.
The problem is that after the inner while loops as for example after this inner while loop
while (aux_path_2 != NULL)
{
if (aux_path_1->row == aux_path_2->row && aux_path_1->column == aux_path_2->column)
{
exist=1;
}
aux_path_2 = aux_path_2->next;
}
the pointers aux_path_2 and aux_path_1 become equal to NULL. So in next iterations of the outer while loops the inner while loops are skipped due to their conditions like this
while (aux_path_2 != NULL)
that at once evaluate to logical false.
You need to reset the values of the pointers aux_path_2 and aux_path_1 in the beginning of the outer while loops before the inner while loops as for example
while (aux_path_1 != NULL)
{
exist = 0;
aux_path_2 = head_list_2; // <===
while (aux_path_2 != NULL)
{
//...
}
Also as soon as the variable exist is set to 1 there is no sense to continue iterations of the inner while loops.
So the inner for loops should be rewritten as for example
while (aux_path_1 != NULL)
{
exist = 0;
for ( aux_path_2 = head_list_2;
!exist && aux_path_2 != NULL;
aux_path_2 = aux_path_2->next )
{
if (aux_path_1->row == aux_path_2->row && aux_path_1->column == aux_path_2->column)
{
exist = 1;
}
}
//...
There are multiple problems in your code:
the implementation is flawed: you should initialize aux_path_2 = head_list_2 at the beginning of each iteration of the first loop and aux_path_1 = head_list_1 at the beginning of each iteration of the second loop.
the general idea is incorrect: you would only insert elements that are in one list only. Elements common to both lists will be skipped in both loops hence never inserted in the union list. You should instead clone the first list and use the test only in the second loop.
the insert_union function cannot start from an empty list. You should return the updated value of head_list_3 from this function and store it in the caller.
there is no need to use global variables for this task: created or updated list pointers should be returned by both functions.
it is confusing and error prone to hide pointers behind typedefs. Instead of defining lp, define list_path as a typedef for struct list_path and use list_path * to keep pointers visible.
Here is a modified version using an auxiliary function to check if a node has given coordinates. Using small generic functions and variable names helps improve code readability:
#include <stdlib.h>
typedef struct list_path list_path;
struct list_path {
int row, column;
list_path *next;
};
int path_find(list_path *head, int row, int column) {
for (list_path *aux = head; aux != NULL; aux = aux->next) {
if (aux->row == row && aux->column == column)
return 1;
}
return 0;
}
list_path *path_insert(list_path *head, int row, int column) {
list_path *temp;
list_path *aux;
temp = malloc(sizeof(*temp));
if (temp == NULL) {
perror("cannot allocate list_path structure");
abort();
}
temp->row = row;
temp->column = column;
temp->next = NULL;
if (head == NULL) {
// empty list: allocated node is the new head
head = temp;
} else {
// otherwise find the last node of the list
for (aux = head; aux->next != NULL; aux = aux->next) {
continue;
}
// and append the newly allocated node
aux->next = temp;
}
return head;
}
list_path *path_union(list_path *list1, list_path *list2) {
list_path *list3 = NULL;
// clone the first list into list3
for (list_path *aux1 = list1; aux1 != NULL; aux1 = aux1->next) {
list3 = path_insert(list3, aux1->row, aux1->column);
}
// append elements only present in list2
for (list_path *aux2 = list2; aux2 != NULL; aux2 = aux2->next) {
if (!path_find(list1, aux2->row, aux2->column)) {
list3 = path_insert(list3, aux2->row, aux2->column);
}
}
// return a pointer to the union list.
return list3;
}

i want to make sure that my linked list work

Is this a right way to do a linked list ? I am having a problem in a big school project and now i want to make sure that this is true.
void addnode(int a){
struct house* tmp = houses[i].next;
while (tmp != NULL) {
tmp = tmp->next;
}
tmp = (struct house*)malloc(sizeof(struct house));
tmp->id=a;
tmp->next=NULL;
}
i figured out that the error can be in other parts of the code. Now i will share the parts i suspect i hope you can help me.
houses[i] is an array of linked lists. if houses[i].id==-1 it is empty
struct house get_house_byid(int id) {
for (int i = 0; i < 1000; i++) {
if (houses[i].id != -1) {
if (houses[i].id == id) {
return houses[i];
}
if (houses[i].next != NULL) {
struct house* tmp = houses[i].next;
while (tmp != NULL) {
if (tmp->id == id) {
return *tmp;
}
tmp = tmp->next;
}
}
}
}
struct house housep;
housep.id = -1;
return housep;//if it cant find that id it returns housep
}
There may be other issues with your code that is not shown, but there are issues with addnode:
addnode does not set the head of the list (i.e. houses[i].next).
Thus, the newly added node is never connected to anything [and is a memory leak].
Ignoring the [obvious] typo/syntax error: void addnode{int a} instead of void addnode(int a).
The loop on tmp discards the pointer to the tail of the list. We need a separate variable (e.g. prev).
Note that i is global. That's fine, but the function would be cleaner if i was an argument to addnode instead.
Don't cast the return of malloc: Do I cast the result of malloc?
Here's is some refactored code. It is annotated:
void
addnode(int i,int a)
{
struct house *tmp;
struct house *prev;
// find the tail of the list
prev = NULL;
for (tmp = houses[i].next; tmp != NULL; tmp = tmp->next)
prev = tmp;
// allocate the new node
tmp = malloc(sizeof(*tmp));
tmp->id = a;
tmp->next = NULL;
// append to the tail of the [non-empty] list
if (prev != NULL)
prev->next = tmp;
// add to front of the empty list
else
houses[i].next = tmp;
}

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

Binary Search Tree - Memory Leak at insertion

I am trying to create a binary search tree and insert a new node in an iterative way. It is all working well except I am getting a memory leak in this function.
Valgrind says 7 blocks (I am adding 7 nodes) are missing.
I couldn't see where my leak is. I would appreciate another look at my code.
void bst_insert_node(bstree* bst, unsigned long phone, char *name) {
bst_node* current = bst->root;
bst_node* parent = NULL;
bst_node* new = (bst_node *)malloc(sizeof(bst_node));
new->phone = phone;
new->left = new->right = new->parent = NULL;
new->name = malloc(sizeof(char) * (strlen(name)+1));
strncpy(new->name,name,(strlen(name)+1));
while(current != NULL) {
parent = current;
if(phone < current->phone) {
current = current -> left;
}
else if(phone > current->phone) {
current = current -> right;
} else {
free(new);
printf("Diese Nummer ist schon bekannt \n");
return;
}
}
new->parent = parent;
if(parent == NULL) {
bst->root = new;
}
else if(new->phone < parent->phone) {
parent->left = new;
}
else {
parent->right = new;
}
}
Free methods:
void bst_free_subtree(bst_node* node) {
if (node == NULL) return;
bst_free_subtree(node->left);
bst_free_subtree(node->right);
printf("\n Deleting node: %lu \t %s", node->phone,node->name);
free(node);}
void bst_free_tree(bstree* bst) {
if(bst != NULL && bst->root != NULL) {
bst_free_subtree(bst->root);
bst->root = NULL;
}
}
As we all discussed in the comments, your memory leak is that you're not freeing the node->name strings that you have allocated. You need to add two more frees to your code:
in bst_insert_node, in the case where you can't insert the node, free(new->name) before you free(new)
in bst_free_subtree, free(node->name) before you free(node)
There is also an off-by-one error allocating space for a copied string, as in your answer. It might be simplest to just new->name = strdup(name) instead, which will do both the allocate and the copy in one go.
As an aside, if these are phone numbers then I'd probably store them as strings, not integers (or libphonenumber if you want to go the whole hog, but C++ not C) and if there's a problem inserting one then it might be better to return the error to the calling code (e.g. return true if inserted, false if not) and let that raise errors rather than printing from this code.

C Quicksort (linked list) segmentation fault

I have to create a quicksort on a linked list (in C).
I have my first and last pointer an the pivot (in this code it's the first element of the list).
The structs I have to use:
typedef struct list_element list_element;
struct list_element {
char *password;
int count;
list_element* next;
};
typedef struct list list;
struct list {
list_element* first;
list_element* last;
};
I have a file with 100 passwords and counts.
Like this:
password1 123 (next line) password2 435 (next line) password3 133 ...
The passwords have to be sorted (according to their count) in the end of this programm.
There isn't needed any extra memory allociation for the left and right lists because I only have to use the next pointers. (That's what the hint in the exercise says.)
The given main-function:
int main(int argc, char** args)
{
if (argc != 2)
{
printf("Nutzung: %s <Dateiname>\n",args[0]);
return 1;
}
list mylist;
init_list(&mylist);
read_data(args[1],&mylist);
qsort_list(&mylist);
printf("Sortierte Liste:\n");
print_list(&mylist);
free_list(&mylist);
return 0;
}
I have initialized my list:
void init_list(list* mylist)
{
mylist->first = NULL;
mylist->last = NULL;
}
And insert a new element at end (passwort = passwords in file, hauefigkeit = counts in file):
void insert_list(list_element* le, list* mylist)
{
if (mylist->first != NULL) {
le->next = mylist->last;
mylist->last = le;
le->next= NULL;
}
else {
mylist->last->next = le;
mylist->last = le;
mylist->last->next = NULL;
}
}
Read data from file:
void read_data(char* filename, list* mylist)
{
FILE *file_in = fopen(filename, "r");
if (file_in == NULL) {
perror("Could not open input file!");
exit(1);
}
char buffer[999] = "0";
char *passwort = (char*) calloc(1,sizeof(passwort));
int haeufigkeit = 0;
while (fgets(buffer, sizeof(buffer), file_in) != NULL) {
sscanf(buffer, "%s %d", passwort, &haeufigkeit);
list_element* le = (list_element*)calloc(1,sizeof(list_element));
for(int i = 0; i <=100; i++) {
le->password[i] = passwort[i];
}
le->count = haeufigkeit;
le->next = NULL;
insert_list(le, mylist);
}
fclose(file_in);
}
Partition of the list:
list_element* partition( list* input, list* left, list* right )
{
list_element* pivot = NULL;
if (input->first != NULL) {
list_element* temp;
pivot = input->first;
input->first = input->first->next;
pivot->next = NULL;
left->first = NULL;
right->first = NULL;
while (input->first != NULL) {
if((pivot->count)>(input->first->count)){
temp=input->first->next;
insert_list(input->first, left);
input->first=temp;
}
else {
temp = input->first->next;
insert_list(input->first, right);
input->first = temp;
}
}
}
return pivot;
}
The actual quicksort:
void qsort_list(list* mylist)
{
if(mylist->first == mylist->last){
}
else{
list* left = calloc(1,sizeof(list));
list* right= calloc(1,sizeof(list));
list_element* pivot = partition(mylist, left, right);
qsort_list(left);
qsort_list(right);
if(left->first == NULL){
mylist->first = pivot;
}
else{
mylist->first = left->first;
left->last->next = pivot;
}
if(right->first == NULL){
pivot->next = NULL;
mylist->last = pivot;
}
else{
pivot->next = right->first;
mylist->last = right->last;
}
free(right);
free(left);
}
}
In the end print list:
void print_list(list* mylist)
{
list_element *elem = mylist->first;
while (elem != NULL) {
printf("%s %d\n", elem->password, elem->count);
elem = elem->next;
}
}
And free list:
void free_list(list* mylist)
{
list_element *current;
list_element *second;
current = mylist->first;
while (current != NULL) {
second = current->next;
free(current);
current = second;
}
}
Syntax should be ok. GCC (c99, Wall) compiles without any problems.
But there is an segmentation fault. I have been searching for hours now and I have no idea where the problem could be. Maybe you can help me with this problem.
After the first two answers there isn't any segmentation fault. But still have a problem with read_data function.
The program can't read the passworts correctly. Maybe i misunderstood you answers in relation to the read function.
That's the current function:
void read_data(char* filename, list* mylist)
{
FILE *file_in = fopen(filename, "r");
if (file_in == NULL) {
perror("Could not open input file!");
exit(1);
}
char buffer[999] = "0";
int haeufigkeit = 0;
while (fgets(buffer, sizeof(buffer), file_in) != NULL) {
char passwort[100];
sscanf(buffer, "%s %d", passwort, &haeufigkeit);
list_element* le = (list_element*)
calloc(1,sizeof(list_element));
le->password = passwort;
le->count = haeufigkeit;
le->next = NULL;
insert_list(le, mylist);
}
fclose(file_in);
}
As Leonardo Alves Machado pointed out, the first reflex when having trouble with a C/C++ program is to run it with a debugger like gdb. Here is the basics:
gcc -g main.c -o main
gdb main
(gdb) run
Note the -g compilation flag: this will add debug information to the executable.
In read_data, the lines
for(int i = 0; i <=100; i++) {
le->password[i] = passwort[i];
}
really bug me. You allocate space for passwort (which you never free by the way) and try to copy it to le->password, which is a simple pointer (no allocated space). What you actually need is to make le->password point to passwort, i.e.
le->password = passwort;
In free_list, don't forget to deallocate the passwort space before deallocating the list_element space with:
while (current != NULL) {
second = current->next;
free(current->password);
free(current);
current = second;
}
One of the first issues your program encounters is that read_data() does not allocate enough space for passwort. It's unclear, actually, why you are dynamically allocating this at all, but given that you are doing so, sizeof(passwort) is the size of one pointer to char (since that's what passwort is) -- probably either 4 or 8 bytes. Later, you seem to assume that the allocated space is 100 bytes long when you (attempt to) copy its contents into a list element. Why not simply declare it as a 100-char array?
char passwort[100];
Indeed, if you also declare list_element.passwort the same way then your password-copying code inside the loop will be correct, albeit a bit non-idiomatic.
As it is, that code is problematic, as #Derlin observes. His proposed solution is incorrect, however; you must not make the list elements point to the local passwort as long as that is allocated only once for the whole routine. Then all list elements will have the same password string, which is not what you want. If you want your list elements to contain pointers to the passwords, as they do now, then you'll want to move the declaration and allocation of passwort inside the loop, so that you get separate password space allocated for each list element. Then the suggestion to assign le->password = passwort would be correct.
Another early issue is that your insert_list() function is badly broken.
Consider first what happens when you try to insert an element into an empty list, as initialized by init_list(). The list's next and last members will both be null, and insert_list() will therefore attempt to execute this code:
mylist->last->next = le;
mylist->last = le;
mylist->last->next = NULL;
Observe that mylist->last is null, therefore the first line invokes undefined behavior by attempting to dereference a null pointer. A segmentation fault is an eminently plausible observed result. You might fix that by changing the first of those lines to
mylist->next = le;
Now consider what happens when you try to insert into a non-empty list. In that case, you execute these lines:
le->next = mylist->last;
mylist->last = le;
le->next= NULL;
Since your intention is to insert the new element at the end (i.e. to append it), it is odd that you set the new element's next pointer to the list's last element. It is especially odd that you later overwrite that value with NULL. You seem to have it backward: you want to set the initial last element to point to the new element as its next element, not the other way around:
mylist->last->next = le;
Indeed, that's exactly the code that was wrong for the empty-list case, but it's fine when the list is non-empty.
Overall, your function also suffers from an odd lack of parallelism and some hidden code duplication. I'd probably write the overall function something more like this:
void append_to_list(list_element* le, list* mylist)
{
le->next= NULL;
if (mylist->first != NULL) {
mylist->last->next = le;
mylist->last = le;
}
else {
mylist->first = le;
mylist->last = le;
}
}

Resources