Scope of memory using linked list functions - c

I'm having a little trouble understanding an example function my professor has given as an example for linked lists. It seems that the memory allocated is not actually in the scope of main. But it seems to work. Here are the example functions:
#define NEW(x) (x*)malloc(sizeof(x))
NODE *make_node (void *data) {
NODE *temp;
temp = NEW(NODE);
if (temp != NULL) {
temp->data = data;
temp->next = NULL;
}
return temp;
}
int insert_at_tail(ROOT *r, DATA *d) {
NODE *temp;
temp = make_node(d);
if (temp == NULL) // fail, cannot create new NODE
return -1;
if (r == NULL) {
r = make_root();
if (r == NULL) // fail, cannot create ROOT
return -1;
}
(r->num)++;
if (r->num == 1) { // if previously the list is empty
r->head = r->tail = temp;
}
else {
r->tail->next = temp;
r->tail = temp;
}
return 0;
}
It seems to me that the function insert_at_tail calls the make_node function which then returns a memory location in the function insert_at_tail. But that memory location is in the scope of that function? The memory is then assigned to linked list data. How is it that when in the main function the linked list data can still access that memory? I thought malloc was not global. Thanks for reading! Hopefully someone can help my confusion.

malloc is how you allocate heap memory; the allocated memory sticks around until the pointer is explicitly free-ed. Anyone with access to that pointer can use it until the pointer is passed to free.
malloc isn't "global" in the sense that it can return pointers to memory that isn't preallocated in global space, but that doesn't mean the memory it allocates is disposed of automatically when the scope in which malloc was called exits.

Related

C memory leak, where there is no memory leak? (valgrind)

valgrind is telling me that a specific line in my code creates a memory leak, but when looking at that line, it does not seem to even be able to create one.
I am working with this pretty simple Linked List struct list.h:
typedef struct _linekd_list{
void* object;
struct _linked_list* next;
}linked_list;
And this is how a list is initialized in list.c:
linked_list* newlist(){
linked_list * list = malloc(sizeof(linked_list));
list->next = NULL; //As a flag, that there is no next element
list->object = NULL;
return list;
}
My queue works so, that the first object of the first linked_list is always NULL, the first object is stored in the next linked_list.
Now here is where the memory leak occurs:
int list_add(void* new_object, linked_list* list){
while(list->next != NULL) { //First go to the end of the queue
list = list->next;
}
list->next = malloc(sizeof(linked_list)); //Vangrind says there is a leak
list->next->next = NULL; //Set the next list-object to NULL (acts like a flag)
list->next->object = new_object; //And now store the pointer of the actual object
if(list->next->object == new_object) {
return 0;
} else {
return 1;
}
return 0;
}
This is what valgrind tells me:
==33369== 16 bytes in 1 blocks are definitely lost in loss record 1 of 3
==33369== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==33369== by 0x402219: list_add (list.c:11)
==33369== by 0x4012D0: main (test_list.c:38)
==33369==
Here is the function that recursively frees the list (no memory leak detected):
void free_list(linked_list* list){
if(list->next != NULL) {
free_list(list->next);
free(list);
}
}
You don't free the last node in the list.
free_list does nothing if list->next is NULL. But you don't want to do nothing. You want to not recurse, but you still need to free the node. So move the call to free out of the conditional, or change the test to check whether list itself is NULL

How do I free a pointer without break the list?

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

Free and reset stack in c

So I'm having a problem with memory leaks in my program. One of my functions free_stack is suppose free all the memory in the stack and the stack should not be used after this function call. My other problem is in my reset_stack function which is suppose to free any memory not in use anymore. The stack can be used after the function call and the function is also suppose to reset the stack to its original contents in *make_stack.My program is not doing this. Here's my code.
struct int_stack *make_stack(int node_capacity){
struct int_stack *stk = malloc(sizeof(struct int_stack));
struct is_node *head = malloc(sizeof(struct is_node));
head->contents = malloc(node_capacity * sizeof(int));
head->next_index = 0;
head->next = NULL;
stk->node_capacity = node_capacity;
stk->head = head;
stk->size = 0;
return stk;
}
void free_stack(struct int_stack *stk) {
while(stk->head->next != NULL) {
free(stk);
}
}
void reset_stack(struct int_stack *stk) {
free_stack(stk);
*make_stack(stk->node_capacity);
}
calling free doesn't do anything to your allocated memory, and also value of pointers you called free on. And also your function *make_stack(stk->node_capacity); returns pointer to the newly allocated stack, use that. stk = *make_stack(stk->node_capacity);.

How to detect if memory was allocated? (Linked lists)

I want to create a function that adds an element to the end of a linked list. It also has to return 0 if the element was added successfully, or a 1 if memory could not allocated/saved to for the element.
The question is, how do I know if the memory was allocated successfully or if the element was added successfully? This is the code:
int push_back(pos_t *head, int new_value) {
pos_t *temp = head;
while (temp->next != NULL) {
temp = temp->next;
}
pos_t *temp1 = (pos_t *)malloc(sizeof(pos_t));
temp1->data = new_value;
temp1->next = NULL;
temp = temp1;
}
You need to add the following code
if (temp1 == NULL) { return 1; }
because malloc is defined to either return a pointer to the allocated memory, or
if the size is zero, return NULL.
on error, return NULL.
You can control that you don't request a size of zero, so if you used a positive size, and malloc returned NULL, you can deduce an error occurred.
Many systems have "manuals" installed. If you are using a Linux system, the command "man malloc" will pull up the manual page for malloc. If you are working on a Windows system, a web search for the manual for malloc will give you enough detail to handle the details.
The function has a shortcoming: it cannot be used to allocate the first node in the list, ie if the list is empty.
The prototype should be changed to
int push_back(pos_t **headp, int new_value);
passing the address of the list pointer instead of its value.
Testing for malloc() failure is simple: juts compare the returned pointer to NULL or 0.
Here is the corresponding code:
int push_back(pos_t **headp, int new_value) {
pos_t *temp = *headp;
pos_t *temp1 = malloc(sizeof(pos_t));
if (temp1 == NULL) { // allocation failure
return 1;
}
temp1->data = new_value;
temp1->next = NULL;
if (temp == NULL) { // empty list
*headp = temp1;
} else {
while (temp->next != NULL) {
temp = temp->next;
}
temp->next = temp1; // append node to the end of the list
}
return 0;
}

How to check if free(node) works

Here is the code for freeing the whole linked list
void free_list(RecordType *list)
{
RecordType *tempNode; /* temporary Node to hold on the value of previous node */
while(list != NULL) /* as long as the listnode doesn't point to null */
{
tempNode = list; /* let tempNode be listNode in order to free the node */
list = list->next; /* let list be the next list (iteration) */
free(tempNode); /* free the node! */
}
}
I think this code itself is working ok (?), but I have no idea how to check.
I only applied the theory (e.g. # of frees must = to the # of mallocs)
So here are some questions that I'm wondering...
Does this method work?
Do I need to malloc tempNode?
I initialized tempNode before while loop... but after I free, tempNode still works... I don't really get that part
The theory that I used:
# of free() == # of malloc()
You need a temporary node to hold the current node
Let the current node equal to the next node
Free the current node by using the temporary node
If any of my theory sounds wrong, please explain!
Thanks!
Does this method work?
Yes, assuming the list nodes were all dynamically allocated and haven't been previously freed
Do I need to malloc tempNode?
You don't need to allocate any memory inside free_list but all list elements must have been dynamically allocated previously. You can only call free on memory that was allocated using malloc (or calloc)
I initialized tempNode before while loop... but after I free, tempNode
still works... I don't really get that part
Calling free returns ownership of memory to the system. It may choose to reuse this memory immediately or may leave it untouched for some time. There's nothing to stop you accessing the memory again but the results of reading or writing it are undefined.
If you want to make it harder for client code to accidentally access freed memory, you could change free_list to NULL their pointer
void free_list(RecordType **list)
{
RecordType *tempNode;
while(*list != NULL) {
tempNode = *list;
list = tempNode->next;
free(tempNode);
}
*list = NULL;
}
If you also want to check that you really have freed all memory, look into using valgrind. This will report any memory leaks and also flags some types of invalid memory access.
The method certainly works - but it should be mallocd first before freeing. Otherwise it is undefined behavior.
You don't need to malloc() tempNode only if list has been previously malloc()d.
The third part is undefined behavior. After free() the data may still exist, but is flagged for being overwritten. You cannot rely on the node once it is free()d
The best way to check your code is interactive tracing by means of Debugger. Gdb in KDevelop on Linux or MS Visual Studio's debugger on MS Windows are perfect. I'll use the later for this demonstration.
This code defines a uni-directed list of integers with three functions: ListPush() adds an integer to the list, ListPrint() displays the list contents and ListDestroy() destroys the list. In main() I insert 3 integers into the list, print them and destroy the list.
#include <malloc.h>
#include <stdlib.h>
#include <stdio.h>
typedef struct Node NODE, *PNODE;
typedef struct Node {
int item;
PNODE next;
};
PNODE ListPush(PNODE head, int item) {
PNODE p;
PNODE n = (PNODE) malloc(sizeof(NODE));
if ( !n ) exit(1);
n->next = 0;
n->item = item;
if (!head) {
head = n;
}
else {
for ( p=head; p->next != 0; p=p->next );
p->next = n;
}
return head;
}
void ListPrint(PNODE head) {
PNODE p;
printf("List contents:\n\n");
for (p=head; p!=0; p=p->next) {
printf("%d ", p->item );
}
}
void ListDestroy( PNODE head ) {
PNODE n, c = head;
if ( !head ) return;
do {
n = c->next;
free(c);
c = n;
} while (c );
}
int main() {
int i;
int a[3] = {1,2,3};
PNODE head = 0;
for ( i = 0; i<3; ++i ) {
head = ListPush(head, a[i]);
}
ListPrint(head);
ListDestroy(head);
return 0;
}
Three attached images illustrate 2 stages of the program (MSVS2012 Debugger).
The first shows state of relevant local vars after for() cycle finishes. Look at head variable and proceed on the tree. You can see three nodes with their contents: integers 1,2 and 3 respectively.
The second image shows the variables inside ListDestroy() after first call to free(). You can see that head points to freed memory (red circles) and pointer in variable c points to the next node being destroyed on the next loop.

Resources