I have created a linked list in C that is used to store data which is then modified as required. In creating the linked list I have used the following
struct car_elements
{
char car_rego[7];
double time_parked;
struct car_elements *next;
};
typedef struct car_elements car;
/* Defined as global variable to hold linked list */
car *head = NULL;
car *SetupCars()
{
car *ptr = head;
car *new_car = NULL;
new_car = (car*) malloc(sizeof(car));
if (!new_car)
{
printf("\nUnable to allocate memory!\n");
exit(1);
}
strcpy(new_car->car_rego, "empty");
new_car->time_parked = time(NULL);
new_car->next = NULL;
if (ptr == NULL)
{
return (new_car);
}
else
{
while (ptr->next)
{
ptr = ptr->next;
}
ptr->next = new_car;
return (head);
}
}
From main I call the following to create the linked list
for(int i = 0; i<TOTAL_CARS; i++) {
head = SetupCars(head);
}
The problem is that now I have a memory leak - Is there a better way to create a fixed size linked list. At the end of the program running I can
free(head);
However I cannot call within SetupCars method
free(new_car);
I could create new_car as a global variable I guess and free it at the end of the program but I cannot help but feel there is a better way to do it. I don't think global variables are evil if used properly however I would appreciate some advice.
WHy not just free it at the end? SOmething like this:
car *tofree;
car *ptr = head;
while(ptr) {
tofree = ptr;
ptr = ptr->next;
free(tofree);
}
You need a function to free the entire list, like:
void free_cars(car*p) {
while (p != NULL) {
car* nextp = p->next;
free (p);
p = nextp;
}
}
So you would call
free_cars (head);
head = NULL;
Perhaps even by having a macro
#define DELETE_CARS(CarsVar) do { \
free_cars(CarsVar); CarsVar = NULL; } while(0)
then just write DELETE_CARS(head); later in your code.
And indeed, manual memory management is painful, you need to avoid memory leaks. Tools like valgrind can be helpful. And you could consider instead to use Boehm's garbage collector, so use GC_MALLOC instead of malloc and don't bother freeing memory.... Read more about garbage collection.
Keep car *head as a global var. For SetupCars:
void SetupCars() /* void will do, unless you want a copy of the new "car" */
{
car *new_car = NULL;
new_car = malloc(sizeof *new_car); /* don't need to cast return value of malloc */
/* do checks and setup new_car... */
if (head == NULL) /* first element */
{
head = new_car;
}
else /* easier to add new_car as the FIRST element instead of last */
{
new_car->next = head;
head = new_car;
}
}
From main you create the linked list the same way:
for(int i = 0; i<TOTAL_CARS; i++) {
SetupCars(); /* without any arguments */
}
Then at the end, you loop through the list and free the objects. As Manoj Pandey posted in his answer:
car *tofree;
car *ptr = head;
while(ptr) {
tofree = ptr;
ptr = ptr->next;
free(tofree);
}
Related
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);
}
Kindly read the whole post since it includes small details which are highly important.
As known by C we should take care of incidents where malloc fails, for that case I created a function called destroyList() whose job is to take a pointer to Node and destroy it one by one.
But my function isn't being called correctly...
I tried to call it with ptr, merged_out and *merged_out (The last one was a suggestion from a member of the community) but nothing seems to work.
Why is that? the function sometimes receives NULL, Empty Lists or some random values.
Can someone please help me fix this issue and let me understand of what is going on?
typedef struct node_t {
int x;
struct node_t *next;
} *Node;
void destroyList(Node ptr) {
while (ptr) {
Node toDelete = ptr;
ptr = ptr->next;
free(toDelete);
}
}
Main Function:
ErrorCode mergeSortedLists(Node list1, Node list2, Node *merged_out) {
if (!list1 || !list2) {
return EMPTY_LIST;
}
if (!isListSorted(list1) || !isListSorted(list2)) {
return UNSORTED_LIST;
}
if (!merged_out) {
return NULL_ARGUMENT;
}
Node ptr = NULL;
int total_len = getListLength(list1) + getListLength(list2);
for (int i = 0; i < total_len; i++) {
int min = getMin(&list1, &list2);
ptr = malloc(sizeof(*ptr));
*merged_out = ptr;
if (!ptr) {
destroyList(*merged_out);
*merged_out = NULL;
return MEMORY_ERROR;
}
ptr->x = min;
ptr->next = NULL;
merged_out = &ptr->next;
}
return SUCCESS;
}
This is how the function should be called:
Node merged_actual = NULL;
ErrorCode merge_status = mergeSortedLists(list1, list2, &merged_actual);
Note: getMin() gets the minimum value and advances the pointer of the list which has that min value to the next node.
Start after those if checks.
Node ptr=NULL,last;
/* find out current tail of the list */
if (*merged_out!=NULL){
last=*merged_out;
while (last->next!=NULL){
last=last->next;
}
}
int total_len = getListLength(list1) + getListLength(list2);
for (int i = 0; i < total_len; i++)
{
int min = getMin(&list1, &list2);
ptr = malloc(sizeof(*ptr));
if (!ptr)
{
destroyList(*merged_out);
*merged_out=NULL;
return MEMORY_ERROR;
}
ptr->x = min;
ptr->next = NULL;
/* link ptr onto the list */
if (*merged_out==NULL){
/* if the list is empty, make ptr the head of the list */
*merged_out=ptr;
last=*merged_out;
}
else{
last->next = ptr;
last = ptr;
}
}
Please try not to copy and paste this block of code. It may or may not be correct, but try to understand what it did: iterate each time the function is called, in an effort to put last to point at the last element of the list. Therefore merged_out can always point to the head.
#user12986714 I lost my old account, and was told to not to care about the initial value of *merged_out could you update the solution (delete the first while loop and no need for 2 pointers)
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;
}
I'm currently playing with linked lists, and I've put together the following code for testing purposes.
First I'd like to point out, I'm aware of my unusual list setup, it was just a test, to get a not upside down list. My actual "problem" now is, that I don't seem to have any memory leaks once the program terminates, although I'm not freeing the list. I'm using drmemory on Windows for analyzing, and it always worked nicely. If I put some other mallocs in this code, it notices the not freed memory. Why doesn't it notice the list?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// ----------------------
typedef struct Item
{
char name[10];
struct Item *next;
} Item;
Item *items = NULL;
Item *items_add(const char* name)
{
Item *new = malloc( sizeof(Item) );
strcpy(new->name, name);
new->next = NULL;
if(items == NULL)
{
items = new;
}
else
{
Item *iter = items;
while(iter->next != NULL)
{
iter = iter->next;
}
iter->next = new;
}
return new;
}
void items_rem(const char* name)
{
if(items == NULL)
return;
Item *iter = items, *prev;
do
{
if(strcmp(iter->name, name) == 0)
{
prev->next = iter->next;
free(iter);
break;
}
prev = iter;
iter = iter->next;
}
while(iter->next);
}
// ----------------------
int main(void)
{
items_add("Item1");
items_add("Item2");
items_add("Item3");
items_add("Item4");
items_rem("Item3");
for(Item *iter = items; iter != NULL; iter = iter->next)
{
printf("%s\n", iter->name);
}
/*
Output:
Item1
Item2
Item4
*/
}
The reason, I can think of is that Item *items = NULL 'items' is a global variable. So, as far as the memory leak checking tool is concerned, the memory is still accessible from the code, so it may be assuming that you still need that memory.
Atleast IBM Rational Purify works in this way. In IBM Rational Purify, you can select the option to show "Memory in use" and it will display this pointer and number of bytes held by it.
Please note that a memory is considered leaked only when there are no pointer variables containing that address and it has not been freed also.
For Ex:
int main()
{
function();
}
int function()
{
char *ptr = NULL;
ptr = malloc(10);
return 0;
}
Now, in the above example, once you return from function, there is no way for you to access variable ptr. So, the memory allocated for ptr is definitely lost
drmemory doesn't show reachable allocations by default, try running drmemory with the -show_reachable option set
I've been working on a lab for a CSC class for a while, and unfortunately I'm a bit rusty with C (as you'll probably notice from the code). I'm encountering two particular problems, both related to memory management.
1) In the dequeue operation, I'm attempting to return a string value from the node at the end of the queue. Since I'm also trying to use free() and kill off that node once I retrieve the data, I need to use a method like strcpy() to grab the data. The program segfaults whenever I try to use strcpy, and Valgrind claims invalid r/w.
2) dequeue also is not properly updating the stringQueue struct for reasons I cannot understand. I have similar code for stacks where the alterations persist, but I can keep running dequeue all day and it won't actually remove the end node.
The relevant code:
typedef struct node {
char data [strMax];
struct node * next;
} queueNode;
typedef struct {
queueNode * head;
queueNode * tail;
} stringQueue;
char * dequeue(stringQueue *queue) {
char * data = malloc(strMax * sizeof(char));
if(empty(*queue)) {
return "Null list!";
}
else if(!(queue->head)->next) { // One item in the queue.
data = (queue->head)->data;
//free(queue->head);
queue->head = NULL;
queue->tail = NULL;
}
else { // Multiple items in the queue.
data = (queue->tail)->data;
free(queue->tail);
queueNode * trace = queue->head;
while(trace->next) // Seek the last node in the queue.
trace = trace->next;
queue->tail = trace;
}
return data;
}
Your main problem is in lines like data = (queue->head)->data;. You can't assign array like this. you should memcpy. (strcpy is for null-terminated strings, and I guess that it's not so)
edit: you can also use strncpy, to avoid buffer-overflow.
You probably want to declare data as a char * = NULL at first. Then when you want to return it use data = asprintf("%s", (queue->tail)->data);. That will only do the string allocation and copying when needed, and only the required size. Then your calling code must take responsibility for freeing that data itself.
You currently have a char[] in your node struct in memory on the heap. Later on, you are setting a pointer to the data member of the struct, then freeing the struct in memory. You are left with a 'dangling pointer' that points to where the struct used to be. Trying to use that pointer will end in almost certain doom (or worse, unpredictable behaviour).
I see a few problems with your code...
First you do not test that your queue argument is not NULL. Then you haven't included your definition of empty() but probably testing that queue->head is NULL should tell you that the list is empty. Here you are dereferencing it prior testing it's a valid pointer, very dangerous.
Secondly, you are mallocing some data which is not used properly. When you do the affection data = (queue->head)->next; you are loosing the pointer to your allocated memory, you probably want to do a strncpy() here like strncpy(data, queue->head->data, strMax). After this you can uncomment your free(). The function calling your dequeue one will have to free() that string later when it's not used anymore.
Why not allocate your data only when you are sure that the list is not empty? If you do not want to do this, you then have to free() that unsuded malloc'ed memory.
See the code below.
queueNode* find_before_tail(stringQueue* queue)
{
queueNode* node = NULL;
if (!queue || !queue->head)
return NULL;
node = queue->head;
while (node->next != queue->tail && node->next)
node = node->next;
return node;
}
char * dequeue(stringQueue *queue) {
char *data = NULL;
queueNode* to_queue = NULL;
if(!queue || !queue->head) {
/* Nothing to dequeue here... */
return NULL;
}
data = malloc(strMax * sizeof(char));
if (!data) {
printf("Error with malloc()...\n");
return NULL;
}
/* Only one element */
if(!(queue->head)->next == queue->head) {
strncpy(data, queue->head->data, strMax);
free(queue->head);
queue->head = NULL;
queue->tail = NULL;
}
else {
strncpy(data, queue->tail->data, strMax);
to_dequeue = queue->tail;
queue->head = queue->head->next;
queue->tail = find_before_tail(queue);
if (!queue->tail)
return NULL;
queue->tail->next = NULL;
free(to_dequeue);
}
data[strMax - 1] = 0;
return data;
}
There are probably some other issues with the rest of your code, judging by this one but hopefully it gives you some basis.
EDIT WITH YOUR QUEUE CODE
Here again you are not testing the return value of malloc(). Here is a version with a non-cyclic linked list (I've also updated the dequeue() function above to work with this).
int enqueue(stringQueue *queue, char *item)
{
queueNode * newNode = NULL;
if (!queue || !item)
return EINVAL;
newNode = malloc(sizeof(queueNode));
if (!newNode) {
perror("malloc()");
return errno;
}
strncpy(newNode->data, item, strMax);
newNode->data[strMax - 1] = 0;
if (!queue->head) {
/* Element is queue and tail */
queue->tail = newNode;
}
newNode->next = queue->head;
queue->head = newNode;
return 0; /* Everything was fine */
}
I have not tested the code but it should be very similar to this. In this scenario, when you have only one element, this_element->next is NULL and not pointing to itself.