so, I just coded a Insertion Sort to sort a linked list (wiith dummy cell).
It works pretty good, but, at the end of the code, If I use free() in a pointer that I used as auxiliar, It's free also one of my cell (the last one it pointer in the loop).
So in order to avoid it free my cell, first I'm pointing de pointer to NULL, but here's my question: Wasn't it supposed to free just the pointer and not my cell if I didn't pointed NULL?
Here's my function
void
insertSort(cel *lst){
cel *temp = NULL;
cel *ordenado = lst->prox;
while(ordenado){
cel *valorOrdenando = ordenado->prox;
// removendo o valorOrdenado da lista
ordenado->prox = valorOrdenando->prox;
for (cel* i = lst; i != ordenado->prox; i = i->prox)
{
if (valorOrdenando->valor <= (i->prox)->valor || i->prox == ordenado->prox){
temp = i->prox;
i->prox = valorOrdenando;
valorOrdenando->prox = temp;
break;
}
}
ordenado = ordenado->prox;
}
// and here is where I point to NULL, otherwise I lost a cell
temp = NULL;
free(temp);
}
Here's the other part of the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct cel {
int valor;
struct cel *prox;
}typedef cel;
void inserir (cel **lista, int x) {
cel *temp = NULL, *aux = *lista;
temp = malloc(sizeof(cel));
temp->valor = x;
temp->prox = NULL;
if (*lista == NULL)
*lista = temp;
else {
for (; aux->prox != NULL; aux = aux->prox);
aux->prox = temp;
}
}
void imprimir(cel *lista) {
for (cel *aux = lista; aux != NULL; aux = aux->prox)
printf("%d ,", aux->valor);
printf("\n");
}
int main(){
cel *list = NULL;
inserir(&list, 3);
inserir(&list, 2);
inserir(&list, 1);
inserir(&list, 8);
inserir(&list, 6);
insertSort(list);
//bubbleSort(list->prox);
imprimir(list->prox);
return 0;
}
How should I code so that I didn't need to user *temp = NULL and why Is it happening currently??
You have a misconception about how pointers work in C. When you declare a pointer, it is just like declaring any other variable.
If you declare a pointer locally (inside a function, without a modifier such as static) the memory position it occupies will be handled by lower layers that the language C abstracts for you. One common implementation is to use a stack, when you declare a variable locally it will be pushed onto the stack when the function is called and will be popped out of the stack once the function returns, so there is no need to worry about deallocating your pointers.
However, a pointer points to a certain memory position and when you use a function like malloc it allocates a free memory block for you and the pointer points to the first position of the block. Now that block will only return to the free block list when you free it. So once you have finished using that memory location you should free it.
When you did:
temp = NULL;
free(temp);
You were trying to free the NULL memory position, which does not make sense.
So you are only going to free a memory once you do not need it anymore.
I suggest you search more about variables and pointers in the C language, this link might help you:
enter link description here
Related
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!
I'm making a HashMap in C but am having trouble detecting when a Node has been initialized or not.
Excerpts from my code below:
static struct Node
{
void *key, *value;
struct Node *next;
};
struct Node **table;
int capacity = 4;
table = malloc(capacity * sizeof(struct Node));
// At this point I should have a pointer to an empty Node array of size 4.
if (table[0] != NULL)
{
// This passes
}
I don't see what I can do here. I've read tons of other posts of this nature and none of their solutions make any sense to me.
malloc does not initialize the memory allocated. You can use calloc to zero-initialize the memory.
// Not sizeof(struct Node)
// table = calloc(capacity, sizeof(struct Node));
table = calloc(capacity, sizeof(*table));
After that, it will make sense to use:
if (table[0] != NULL)
{
...
}
I suggest you consider something like a HashMapCollection type that you create with a set of functions to handle the various memory operations you need.
So you might have code something like the following. I have not tested this nor even compiled it however it is a starting place.
The FreeHashMapCollection() function below would process a HashMapCollection to free up what it contains before freeing up the management data structure. This may not be what you want to do so that is something for you to consider.
The idea of the following is to have a single pointer for the HashMapCollection struct and the array or list of HashMapNode structs immediately follows the management data so a single free() would free up everything at once.
typedef struct _TAGHashMapNode {
void *key, *value;
struct _TAGHashMapNode *next;
} HashMapNode;
typedef struct {
int iCapacity; // max number of items
int iSize; // current number of items
HashMapNode *table; // pointer to the HashMapNode table
} HashMapCollection;
Then have a function to allocate a HashMapCollection of a particular capacity initialized properly.
HashMapCollection *AllocateHashMapCollection (int iCapacity)
{
HashMapCollection *p = malloc (sizeof(HashMapCollection) + iCapacity * sizeof(HashMapNode));
if (p) {
p->table = (HashMapNode *)(p + 1);
p->iCapacity = iCapacity;
p->iSize = 0;
memset (p->table, 0, sizeof(HashMapNode) * iCapacity);
}
return p;
}
HashMapCollection *ReallocHashMapCollection (HashMapCollection *p, int iNewCapacity)
{
HashMapCollection *pNew = realloc (p, sizeof(HashMapCollection) + sizeof(HashMapNode) * iNewCapacity);
if (pNew) {
pNew->table = (HashMapNode *)(pNew + 1);
if (p == NULL) {
// if p is not NULL then pNew will have a copy of that.
// if p is NULL then this is basically a malloc() so initialize pNew data.
pNew->iCapacity = pNew->iSize = 0;
}
if (iNewCapacity > pNew->iCapacity) {
// added more memory so need to zero out that memory.
memset (pNew->table + iCapacity, 0, sizeof(HashMapNode) * (iNewCapacity - pNew->iCapacity));
}
pNew->iCapacity = iNewCapacity; // set our new current capacity
p = pNew; // lets return our new memory allocated.
}
return p; // return either old pointer if realloc() failed or new pointer
}
void FreeHashMapCollection (HashMapCollection *p)
{
// go through the list of HashMapNode items and free up each pair then
// free up the HashMapCollection itself.
for (iIndex = 0; iIndex < p->iCapacity; iIndex++) {
if (p->table[iIndex].key) free (p->table[iIndex].key);
if (p->table[iIndex].value) free (p->table[iIndex].value);
// WARNING ***
// if these next pointers are actually pointers inside the array of HashMapNode items
// then you would not do this free as it is unnecessary.
// this free is only necessary if next points to some memory area
// other than the HashMapNode table of HashMapCollection.
if (p->table[iIndex].next) free (p->table[iIndex].next);
// even though we are going to free this, init to NULL
p->table[iIndex].key = NULL;
p->table[iIndex].value = NULL;
p->table[iIndex].next = NULL;
}
free (p); // free up the memory of the HashMapCollection
}
I am programming the classic Snake game in C using doubly linked lists and have written a function that creates a pointer, allocates the required space for the structure, then allocates memory for the next pointer in the list and so on. In the end the pointer to the first element is returned by the function and can be assigned to the head pointer in the main function.
When starting the game I want the snake to have a length of three so I had three malloc's in the function and used pointer, pointer->next, pointer->next->next and so forth and everything was working.
Since a lot of steps have to be repeated in this process I thought of putting all of this into a for-loop like this:
#include <stdio.h>
#include <stdlib.h>
typedef struct snake snake;
struct snake {
int x; /* x coordinate */
int y; /* y coordinate */
snake *previous;
snake *next;
};
snake *initSnake(void) {
snake *pointer, *tmp1, *tmp2 = NULL;
/* three iterations, so the snake will have a length of three */
for( int i = 0; i<3; i++, tmp1 = tmp1->next) {
if(NULL == (tmp1 = (snake*)malloc(sizeof(snake)))) {
return NULL;
}
/* coordinates */
tmp1->x = 20;
tmp1->y = 10 + i;
/* first previous points to NULL */
tmp1->previous = tmp2;
/* temporarily store last pointer to be used for next previous pointer */
tmp2 = tmp1;
if(0 == i) {
/* store first pointer so it can be returned */
pointer = tmp1;
}
}
/* the last next pointer has to point to NULL */
tmp1 = NULL;
/* now return the pointer to the first element in list */
return pointer;
}
int main() {
/* pointer to first element in list */
snake *head = NULL;
if(NULL == (head = initSnake() ) ) {
fprintf(stderr, "Not enough memory!\n");
return EXIT_FAILURE;
}
/* here everything works fine */
printf("%d\n", head->y);
printf("%d\n", head->previous);
/* when trying to acces the content of the next element, the program crashes... */
printf("%d\n", head->next->x);
/* pause */
getchar();
}
The problem is that when I try to access the second element of the list inside the main function, the game crashes. I suspect that something is wrong with
tmp1 = tmp1->next in the for-loop and I don't really access the next pointers but I am not completely sure.
Can you help me out?
You have a lot of mistakes that suggest you don't really understand how memory, variables & pointers work. For example doing tmp1 = tmp1->next in the end of the for loop, immediately followed by tmp1 = (snake*)malloc(sizeof(snake)) overwrites tmp1 and makes the previous operation pointless. Similar operations exist in other places in your code.
To clean that up, try this:
snake *initSnake(void) {
snake *head, **current, *prev;
/* three iterations, so the snake will have a length of three */
for(int i = 0, prev = NULL, current = &head; i<3; i++) {
if(NULL == (*current = malloc(sizeof(snake)))) {
return NULL; /* note that if this happens midway
through allocation, nothing gets freed */
}
/* coordinates */
(*current)->x = 20;
(*current)->y = 10 + i;
/* next, previous pointers */
(*current)->next = NULL;
(*current)->previous = prev;
prev = *current;
current = ¤t->next;
}
/* now return the pointer to the first element in list */
return head;
}
You have to set the last next pointer to NULL:
/* the last next pointer has to point to NULL */
tmp1->next = NULL; // -> next !
because tmp1 is a local variable and setting it to NULL just before returning will have no effect.
Edit:
Ooops, also don't do tmp1 = tmp1->next in the for loop: as it is not set at the moment you attempt to perform this operation. You need to set next together with previous:
/* first previous points to NULL */
tmp1->previous = tmp2;
if (tmp2)
tmp2->next = tmp1;
Online demo
I've encounter an issue in Visual Studio which drives me crazy.
It is regarding unallocated pointers.
I wanted to write a simple linked list app.The problem is that freed and unallocated pointers are not NULL which prevents me from iterating the list.
Consider following C code
#include "stdafx.h"
#include <malloc.h>
typedef struct _item
{
char data;
struct _item * pNext;
}item, *pItem;
int _tmain(int argc, _TCHAR* argv[])
{
pItem listHead;
pItem listTemp;
pItem listCurr;
listHead = (pItem) malloc(sizeof(listHead));
listHead->data = '0';
listHead->pNext = NULL; //will create exception in free
listTemp = listHead;
while(listTemp->pNext != NULL) //issue 1
{
listTemp = listTemp->pNext;//0xfdfdfdfd - never NULL? how to check?
}
listCurr = (pItem) malloc(sizeof(listHead));
listCurr->data = '1';
listCurr->pNext = NULL; //will create exception in free
listTemp->pNext = listCurr;
listTemp = listHead;
while(listTemp->pNext != NULL) //issue 2
{
printf("%d ", listTemp->data - 48); //"0 "
listTemp = listTemp->pNext;
}
printf("%d ", listTemp->data - 48);
free(listTemp); //is set to oxfeeefee not to NULL? //issue 3
listTemp = listHead;
while(listTemp->pNext != NULL) //issue 4
{
listTemp = listTemp->pNext;
}
free(listTemp);//Not null?
return 0;
}
in line issue 1 and issue 2, listTemp->pNext is not NULL but 0xfdfdfdfd. This prevents from getting the last element in the list
in line issue 3, free doesn't set the freed pointer to null but to 0xfeeefeee. This prevents me from getting last element again.
How can i handle these issues?
Thanks for help.
You seem to have a few issues here. One problem you are having is that you are not allocating enough memory.
listHead = (pItem) malloc(sizeof(listHead));
listHead is a pointer. So you only allocate enough memory to hold a pointer, and not to hold your entire item struct. It should be:
listHead = (pItem) malloc(sizeof(item));
I can't see how issue 1 could ever not be NULL the first time through. Did you step through with a debugger? However, the problem with not allocating enough memory could definitely cause the problem with free(), and it's a little difficult to say for sure what other problems it might cause.
Syntax altered slightly to suit my compiler. The two main issues were (1) not allocating enough memory, as already commented. (2) wrong sequence for parsing the list.
#include <stdio.h>
#include <stdlib.h>
typedef struct item {
char data;
struct item * pNext;
} item, *pItem;
void show (pItem list, int cue) {
printf("List %d: ", cue);
while(list != NULL) {
printf("%c ", list->data);
list = list->pNext;
}
printf("\n");
}
int main(int argc, char* argv[]) {
pItem listHead, listTemp, listCurr;
listHead = malloc(sizeof(item));
listHead->data = '0';
listHead->pNext = NULL;
show(listHead, 1);
listCurr = malloc(sizeof(item));
listCurr->data = '1';
listCurr->pNext = NULL;
listHead->pNext = listCurr;
show(listHead, 2);
printf("Freeing: ");
while(listHead != NULL) {
listTemp = listHead;
printf("%c ", listHead->data);
listHead = listHead->pNext;
free(listTemp);
}
printf("\n");
show(listHead, 3);
return 0;
}
The above code follows your method of adding the next item to the tail of the list, but I would normally add it before the head and set a new listHead.
listCurr = malloc(sizeof(item));
listCurr->data = '1';
listCurr->pNext = listHead;
listHead = listCurr;
and this will also work for the first item provided you initialised listHead = NULL to indicate an empty list.
The answer is that you have to set the pointer to the freed memory to NULL yourself. The free function will only release the memory at the pointer back to the heap. The pointer parameter is passed by value and cannot be modified by the free function itself.
Also, you will need to retain a reference to the previous item in your list, so that when you do free the memory and set the pointer to NULL, you do it in the list items and not on the temporary pointer.
listCurr = NULL;
listTemp = listHead;
while(listTemp->pNext != NULL)
{
listCurr = listTemp;
listTemp = listTemp->pNext;
}
if(NULL != listCurr)
{
free(listCurr->pNext);
listCurr->pNext = NULL;
}
Just trying to make a kind of hash table with each node being a linked list.
Having trouble just initializing the space, what am I doing wrong?
#include <stdlib.h>
typedef struct entry {
struct entry *next;
void *theData;
} Entry;
typedef struct HashTable {
Entry **table;
int size;
} HashTable;
int main(){
HashTable *ml;
ml = initialize();
return 0;
}
HashTable *initialize(void)
{
HashTable *p;
Entry **b;
int i;
if ((p = (HashTable *)malloc(sizeof(HashTable *))) == NULL)
return NULL;
p->size = 101;
if ((b = (Entry **)malloc(p->size * sizeof(Entry **))) == NULL)
return NULL;
p->table = b;
for(i = 0; i < p->size; i++) {
Entry * b = p->table[i];
b->theData = NULL;
b->next = NULL;
}
return p;
}
You need to change sizeof(HashTable*) to sizeof(HashTable) and similarly sizeof(Entry **) to sizeof(Entry *) . And the second thing is for every Entry you need to allocate memory using malloc again inside the loop.
if ((p = malloc(sizeof(HashTable))) == NULL)
return NULL;
p->size = 101;
if ((b = malloc(p->size * sizeof(Entry *))) == NULL)
return NULL;
I believe removing the malloc() result casts is best practice.
Plus, as #Naveen was first to point out you also need to allocate memory for each Entry.
Firstly your sizeofs are wrong. T * = malloc( num * sizeof(T)) is correct. You can also use calloc.
You are reusing b for different purposes so it is quite confusing. Not generally good using a single character variable.
p->table which was b is allocated but not initialised, i.e. it doesn't point to anything useful, then you are trying to dereference it.
You need to fill it will Entry* pointers first, and they must be pointing to valid Entry structs if you are going to dereference those.
Your process probably dies on the line b>theData = NULL
Also, you can statically declare your HashTable, either locally, or in some region high enough in the stack that the stack is non-ascending (in memory) while it is used and pass a pointer to the HashTable to your initialize function to avoid a malloc. malloc is slow.
So in main, you can do:
HashTable table;
InitializeHashTable(&table);
// use table (no need to free)
// just do not return table