Value of Passed-By-Value Struct Does Not Change - c

I am trying to understand how to pass a struct by reference in order to create a linked list. The method I am using is similar to the example code given below. However, when this code is run, the *tester declared in the main function always stays as NULL. Is the passing of a struct to the addNode() function in this way inappropriate (the compiler does not raise any warnings)?
struct test{
int num;
struct test *next;
};
void addNode (int num, struct test* tester);
int main (void){
struct test *tester = null;
addNode(1, tester);
}
void addNode(int num, struct test* tester){
struct test *example = malloc(sizeof(struct test));
example->num = num;
if (tester == NULL){
tester = example;
} else{
tester->next = example;
}
}

In addNode function the pointer tester no longer points to the location pointed by the tester in main. function and change your function to
void addNode(int num, struct test** tester){
struct test *example = malloc(sizeof(struct test));
if (NULL == example )
exit(0); // Not enough memory
example->num = num;
if (NULL == *tester)
*tester = example;
else
(*tester)->next = example;
}
Call this function from main as addNode(1, &tester);. Now *tester is an alias for tester in main.

First off, you're assigning NULL to your input. This:
if (tester = NULL)
should be
if (tester == NULL)
Secondly, in that same branch, you assign a new value to tester. However, everything in C is passed by value (copy), so your function receives a copy of a pointer. Therefore, you are only mutating the function's local copy. You need another level of indirection:
#include <assert.h>
struct test{
int num;
struct test *next;
};
void addNode (int num, struct test* tester);
int main (void){
struct test *tester = NULL;
addNode(1, &tester);
}
void addNode(int num, struct test** tester){
/ * wrong, check next item */
assert(tester != NULL);
struct test example = malloc(sizeof(struct test));
example->num = num;
if (*tester == NULL){
*tester = example;
} else{
(*tester)->next = example;
}
}
Last, malloc returns a void*, which can implicitly be converted to any other type of pointer. It does not however return an "instance". So this is wrong:
struct test example = malloc(sizeof(struct test));
and should be:
struct test *example = malloc(sizeof *example);

You are saving the pointer returned by malloc as a struct:
struct test example = malloc(sizeof(struct test));
Perhaps you wanted to store it as a pointer to struct, so that example and tester have matching types:
struct test* example = malloc(sizeof(struct test));
Then, this will make sense:
tester = example;

Related

Initialisation of struct elements

Why aren't the struct pointers initialized to NULL using the following code
code
#include <stdio.h>
#include <stdlib.h>
struct list_el
{
int val;
struct list_el * right, * left, *parent;
}item_default={0,NULL,NULL,NULL}; //Default values
typedef struct list_el node;
int main(int argc, char const *argv[])
{
node * new_node = (node*) malloc (sizeof(node));
(new_node == NULL) ? printf("0\n") : printf("1\n");
(new_node->parent == NULL) ? printf("0\n") : printf("1\n");
(new_node->right == NULL) ? printf("0\n") : printf("1\n");
(new_node->left == NULL) ? printf("0\n") : printf("1\n");
(new_node->val == 0) ? printf("0\n") : printf("1\n");
return 0;
}
Output
1
1
1
1
0
Is it some issue regarding the pointer initialisation syntax?
struct list_el
{
int val;
struct list_el * right, * left, *parent;
}item_default={0,NULL,NULL,NULL}; //Default values
This does not do what you think it does. You've basically written...
typename typedefinition variable = initial_value;
You've declared the type struct list_el, defined it as { int val; struct list_el * right, * left, *parent; }, declared a new variable of that type called item_default, and assigned it the value {0,NULL,NULL,NULL}.
Aside from the type definition, this is basically int foo = 0.
We can test that by printing out the parts of item_default.
int main(int argc, char const *argv[])
{
printf("%d\n", item_default.val);
printf("%p\n", item_default.right);
printf("%p\n", item_default.left);
printf("%p\n", item_default.parent);
return 0;
}
And these will be 0, 0x0 (ie. NULL), 0x0, 0x0.
Unfortunately, C has no defaults for types. You always must initialize them. When working with structs, this typically means writing new and destroy functions so initialization and cleanup happens consistently.
// Declare the type and typedef in one go.
// I've changed the name from node to Node_t to avoid clashing
// with variable names.
typedef struct node
{
int val;
struct node *right, *left, *parent;
} Node_t;
// Any functions for working with the struct should be prefixed
// with the struct's name for clarity.
Node_t *Node_new() {
Node_t *node = malloc(sizeof(Node_t));
node->val = 0;
node->right = NULL;
node->left = NULL;
node->parent = NULL;
return node;
}
int main() {
Node_t *node = Node_new();
printf("%d\n", node->val);
printf("%p\n", node->right);
// and so on
return 0;
}
Note that I did not use calloc. calloc fills the memory with zeros, but the machine's representation of a null pointer is not necessarily zero. Using NULL and 0 are safe, the compiler can do the translation from context, but calloc doesn't know what you're going to do with the memory its zeroing. It's a relatively minor portability concern that's probably more of a problem these days for embedded systems.
Structure is a data type, you don't give default values to data types. What you're doing is like give an int the default of 3. What you want is give an instance of your struct a default value, but that is not possible in C.
You could have a function to help you with that:
void init_struct(node* nd) {
if (nd != NULL) {
nd->val = 0;
nd->parent = nd->right = nd->left = NULL;
}
}

Modifying a structure passed as pointer in C

I'm a noob student trying to write a program that uses binary search tree to organize the workers of a company. My teacher told me if I want to be able to create a new instance of the Worker structure, i can use malloc with the structure, which will return pointer to a new struct every time it's used, then i can edit the details of that new struct from another function. But how can i do it? No matter what i do it gets so complicated and i can't do it. Here's the code i've been able to write this part of the code, just to test if i can create and edit a new structure.
The main thing i ask is, how can i edit the newly created structure?
#include<stdlib.h>
#include<stdio.h>
struct btnode
{
int value = 5;
struct btnode *l;
struct btnode *r;
};
int test(int *p)
{
printf("%d", &p->value);
}
int main()
{
int *asdf = (int *)malloc(sizeof(struct btnode));
test(asdf);
}
Here is a mod of your program which allocates memory for one struct, fills in values for its members, and calls test() to print one member.
#include <stdlib.h>
#include <stdio.h>
struct btnode
{
int value;
struct btnode *l;
struct btnode *r;
};
void test(struct btnode *p)
{
printf("%d", p->value);
}
int main(void)
{
struct btnode *asdf = malloc(sizeof *asdf);
if(asdf != NULL) {
asdf->value = 5;
asdf->l = NULL;
asdf->r = NULL;
test(asdf);
free(asdf);
}
return 0;
}
There are a number of small changes to detail too, I leave you to spot the differences.
First of all there are some mistakes in the code.
1) You can not assign values in the structure.
2) When you are making a pointer for the structure you need pointer of the structure not of the int (does not matter what you want from the inside of the structure)
This is the modified code which runs perfactly
#include<stdio.h>
struct btnode
{
int value;
struct btnode *l;
struct btnode *r;
};
int test(struct btnode *p)
{
printf("%d", p->value);
}
int main()
{
struct btnode *asdf = (struct btnode*)malloc(sizeof(struct btnode));
asdf->value = 5;
test(asdf);
}

Changing a global structure in a function in C

I defined a structure as follows:
typedef struct myStruct{
char *val1;
char *val2;
struct myStruct *prev;
struct myStruct *next;
} myStruct;
I also wrote a function to add a node to this structure:
void add_to_struct(struct myStruct *strct, char *val1,
char *val2){
// create the node for new element
struct myStruct *my_new = malloc(sizeof(struct myStruct));
my_new->val1 = val1;
my_new->val2 = val2;
my_new->next = strct;
my_new->prev = NULL;
strct->prev = my_new;
}
Adding a node to the struct using this function doesn't seem to work though. I guess the problem is that I do not pass my structure (which I defined as a global variable) by reference correctly, but I don't know why. Any idea what I am doing wrong?
EDIT
How I call it:
void main(){
struct myStruct *headPrev = Malloc(sizeof(struct myStruct *));
struct myStruct *headNext = Malloc(sizeof(struct myStruct *));
char *headval1 = Malloc(sizeof(char) * MAXLEN);
char *headval2 = Malloc(sizeof(char) * MAXLEN);
my_struct = Malloc(sizeof(struct myStruct));
my_struct->prev = headPrev;
my_struct->next = headNext;
my_struct->val1 = headval1;
my_struct->val2 = headval2;
newVal1 = "abcd";
newVal2 = "bl";
....
add_to_struct(my_struct,newVal1,newVal2);
}
looks pretty close, just a few minor issues --
my_new should be allocated to be sizeof(struct myStruct)), not cacheElement, no?
also, this looks like a linked list, but you need to return my_new so you can use it as the new head of list.
You're allocating memory using malloc and collecting the address of the memory using my_new variable. So the function is doing nothing effectively. Let me provide an anology. A man comes to ask water at your home. You should either take his bottle, fill it with water and give it back. Or you can give your own bottle to him filled with water. But you're simply taking your own bottle, filling it with water and keeping it to yourself.
You either have to do return my_new or use strct=malloc.... and also change argument of sizeof to myStruct
Try to use void add_to_struct(struct myStruct **strct, char *val1, char *val2).
void add_to_struct(struct myStruct **strct, char *val1,char *val2)
{
// create the node for new element
struct myStruct *my_new = malloc(sizeof(struct myStruct));
my_new->val1 = "abcd";
my_new->val2 = "efgh";
my_new->next = strct;
my_new->prev = NULL;
(*strct)->prev = my_new;
}

Is it possible to generically free linked lists' memory in C

If I have several linked structures in C like:
struct structA {
int a;
int b;
struct structA *next;
}
struct structB {
char a;
int b;
struct structB *next;
}
and I dynamically allocate memory like this:
struct structA *mystructA = (struct structA*) malloc(sizeof(struct structA));
mystructA->next = (struct structA*) malloc(sizeof(struct structA));
struct structB *mystructB = (struct structB*) malloc(sizeof(struct structB));
mystructB->next = (struct structB*) malloc(sizeof(struct structB));
do I always have to free it for each struct type like this:
struct structA *p, *pNext;
for (p = mystructA; p != NULL; p = pNext) {
pNext = p->next;
free(p);
}
struct structB *p, *pNext;
for (p = mystructB; p != NULL; p = pNext) {
pNext = p->next;
free(p);
}
or is there any generic solution? I assume there is no other solution because the free() procedure must know how many bytes have to be freed. But maybe I'm wrong and someone can teach me better.
The standard way is to make the "list part" the first element of the structure, and let each derived struct share this same prefix. Since the first element is guaranteed to be placed at offset zero this wil work.
Example snippet:
#include <stdlib.h>
#include <string.h>
struct list {
struct list *next;
};
struct structA {
struct list list;
int a;
int b;
};
struct structB {
struct list list;
char a;
int b;
};
void *create_any(size_t size)
{
struct list *this;
this = malloc (size);
if (!this) return this;
memset(this, 0, size);
this->next = NULL;
return this;
}
void free_all_any(struct list **lp) {
struct list *tmp;
while ((tmp = *lp)) { *lp = tmp->next; free(tmp); }
}
#define CREATE_A() create_any(sizeof(struct structA))
#define CREATE_B() create_any(sizeof(struct structB))
#define FREE_A(pp) free_any((struct list **) pp)
#define FREE_B(pp) free_any((struct list **) pp)
int main(void)
{
struct structA *ap;
struct structB *bp;
ap = CREATE_A ();
bp = CREATE_B ();
// some code here ...
FREE_A( &ap);
FREE_B( &bp);
return 0;
}
This is more or less the method used in the linux kernel, but a lot more preprocessor magic is used there. (and there is no malloc there, obviously)
Since free() accepts pointers to void * and structA and structB both have the same size, you can pass both pointer types.
This is, however, not optimal in terms of elegance. You should think about the following questions:
Why do you have two different structs with the same members?
Why do you not have a generic list item type, such as the following:
struct list_node {
void *data;
struct list_node *next;
}
Actually, this is a very interesting question. The part is true that you have to free() each struct type individually, as they have been malloc()-ed individually, and each memory block has been allocated specifically for that type.Also, on some systems char and int have different storage sizes, but you can try a solution like Phillip provided. For more info, read about the doom memory engine. On a side note, please don't cast malloc() in C. The funny thing is that once the program is terminated, the operating system will reclaim the memory, so if you only deallocate the structures near the end of the program, when you don't need them anymore, it may not be necessary to free() them

Linked List Null in C

i dont know why the list returned is NULL, this is the code:
In my List.h
struct nodo_ {
char* dato;
struct nodo_ *next;
};
struct nodo_ *Lista;
/*Def list */
void createList(struct nodo_ **Lista);
in my main.c
struct nodo_ *Lista;
int main(){
createList(Lista);
while(Lista != NULL){
printf("The date is %s\n ",Lista->dato); //Error here now
Lisa = Lista->next;
}
return 0 ;
}
in my List.c im create the List :
void createList(struct nodo_ *Lista){
struct nodo_ *Aux_List = list_D;
aux_List = malloc(sizeof(struct nodo_));
char* path_a = "Hello";
char* path_B = "Minasan";
/* Store */
aux_List->dato = path_a;
aux_List = Aux_List->next;
aux_List = malloc(sizeof(struct nodo_));
aux_List->dato = path_b;
aux_List->next = NULL;
}
Thanks.
That pointer is being passed by value, i.e., a copy is made. If you wish to initialize the pointer to a completely new value then you must use another level of indirection (i.e., a nodo_**).
On a side note, typedefing pointer types is almost always a bad idea unless the type is truly opaque (which yours is not). One reason for this "rule" is evident when you consider another bug in your code:
auxList = (Lista*)malloc(sizeof(Lista));
You're allocating space for a pointer to noda_, not enough for a noda_ object. Also, don't cast the return value of malloc in C. It is redundant as a void* is safely and implicitly converted to any other pointer type and, if you forget to include stdlib.h, malloc will be assumed to be a function which returns int, and the cast hides the error. (only applies to compilers which implement C89 or an older version)
EDIT:
To initialize a pointer argument within a function:
void init(struct node **n) {
if(n)
*n = malloc(sizeof(struct node));
}
int main() {
struct node *n;
init(&n);
}
Short answer to your actual question before I dig into the code:
... why the list returned is NULL ...
There is no returned list, you neither use return to pass a result, nor set the value of an out parameter.
In your edited code:
void createList(struct nodo_ **Lista){
struct nodo_ *Aux_List = list_D;
aux_List = malloc(sizeof(struct nodo_));
you first set Aux_List to the current value of Lista, which you know isn't initialized yet, because you're trying to initialize it. Then you discard that value, overwriting aux_List with a new address returned by malloc. You never store anything into *Lista, which would be the only way for this function to work as declared.
As Ed suggests, your typedef is hiding lots of useful information from you, so let's expand it out
struct nodo {
char* dato;
struct nodo *next;
};
/*Def list */
void createList(struct nodo* list_D);
Now, you can see this createList is wrong: you can pass in the head node of a list (which is no use to it anyway), but there is no way for it to return a newly-allocated list to the caller.
Frankly your createList isn't a useful primitive anyway, so I'm going to start with a sensible foundation first:
struct nodo *alloc_nodo(char *dato, struct nodo *next)
{
struct nodo *n = malloc(sizeof(*n));
n->dato = dato;
n->next = next;
return n;
}
Now, before we re-write your createList using this, let's see what it does now:
void createList(struct nodo *list_D)
{
struct nodo *aux_List = list_D;
aux_List = malloc(sizeof(struct nodo_));
/* ^ so, we take the input argument and immediately discard it */
char* path_a = "Hello";
char* path_B = "Minasan";
/* Store */
aux_List->dato = path_a;
aux_List = Aux_List->next;
/* ^ note that we haven't initialized aux_List->next yet,
so this is a random pointer value */
aux_List = malloc(sizeof(struct nodo_));
/* again, we set aux_List to something,
but immediately overwrite and discard it */
aux_List->dato = path_b;
aux_List->next = NULL;
}
So, it ignores its input, returns no output, and leaks two partially-initialized nodes which aren't connected to each other. I believe you wanted to achieve something more like this:
struct nodo* create_my_list()
{
struct nodo *tail = alloc_nodo("Minasan", NULL);
/* the end (tail) of the linked list has a NULL next pointer */
struct nodo *head = alloc_nodo("Hello", tail);
/* the head of the linked list points to the next node */
return head;
/* like a snake, you hold a singly-linked list by the head */
}
If we write main to use this function now, it looks like:
int main()
{
struct nodo *head = create_my_list();
struct nodo *n;
for (n = head; n != NULL; n = n->next)
{
printf("The date is %s\n ", n->dato);
}
}

Resources