Changing a global structure in a function in C - 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;
}

Related

Value of Passed-By-Value Struct Does Not Change

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;

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

Assign struct to char array

I am trying to create my own malloc but I am stuck on one point. As we know we have to assign struct as a meta data in available space as it is mentioned in this picture.
char heap_space[MEM_BUFFER];
struct myblock
{
struct myblock *next;
struct myblock *prev;
int size;
char *buffer;
}
I have my heap_space which will be my "RAM" . Now I am stuck on one point:-
How to assign my structure myblock to heap_space, and one thing which we should keep in mind that every time when new request will come, the place of the myblock will be changed as per allocated (requested) space.
I'm not sure to understand your problem but why don't you try something like:
#define MEM_BUFFER 4096
#define size_t unsigned int
char heap_space[MEM_BUFFER] = {0};
struct myblock
{
struct myblock *next;
struct myblock *prev;
int size;
char *buffer;
};
void *malloc(size_t size)
{
struct myblock *tmp = heap_space;
if (tmp != 0) // != 0 since NULL is in stdlib
while (tmp->next != 0)
tmp = tmp->next;
struct myblock *new_elem = tmp; //your question I guess
new_elem->prev = tmp;
new_elem->size = size;
new_elem->buffer = new_elem + sizeof(*new_elem);
new_elem->next = new_elem->buffer + new_elem->size;
return (new_elem->buffer);
}
int main()
{
char *str1 = malloc(10);
char *str2 = malloc(10);
strcpy(str1, "Hello");
strcpy(str2, "World");
printf("%s %s\n", str1, str2);
}
You should just think your memory in a different way I guess, where inside your heap_space you can have many things.
If you don't understand something please ask.
You should also use void * and unsigned int instead of int
Furthermore you still have some stuff to do:
Check if the size required is available in your array
Give a little more space in case you want to implement your
realloc
Implement your free function
And if you are on linux, you should try to use brk/sbrk instead of having your 'heap space'. But the greatest thing is to run 'real' programs with your own malloc (using LD_PRELOAD)
If it's C++, you should use myblock *free_ptr = reinterpret_cast<myblock*>(heap_space); to initialize your free pointer, and then initialize the size, next, prev and buffer of free_ptr.
In C, you would use a regular C style cast, struct myblock *free_ptr = (struct myblock*)heap_space;.
You should declare
struct myblock
{
struct myblock *next;
struct myblock *prev;
int size;
char buffer[0];
}
so your malloc will return myblockvar.buffer.

How to pass a char array in C?

I have this basic Linked List structure:
struct node
{
char *name;
float salary;
struct node *nextNode;
};
struct list
{
struct node *firstNode;
};
This is my insert function:
void insert(struct list *pList, char *newName, float newSalary)
{
struct node *newNode;
newNode = (struct node *)malloc(sizeof(struct node));
newNode->salary = newSalary;
newNode->name = newName;
if (pList->firstNode == NULL)
{
pList->firstNode = newNode;
newNode->nextNode = NULL;
}
else
{
struct node *pos = pList->firstNode;
for(; pos->nextNode; pos = pos->nextNode);
pos->nextNode = newNode;
newNode->nextNode = NULL;
}
}
This is my main():
int main(void)
{
struct list lst;
struct list *plst = &lst;
createList(plst); //initializes the list
char name1[] = "John";
char name2[] = "Thomas";
char name3[] = "Albert";
insert(plst, name1, 1000);
insert(plst, name2, 2000);
insert(plst, name3, 3000);
}
Everything works great except for the transfer of the char array. I thought the best way to pass a char array would be by passing a pointer to the first char in the char array, but I can't see what I did wrong.
Also, would it be better to first create a new node and then pass a pointer to this node to the insert function? It's similar, but perhaps it is more acceptable?
newNode->name = newName;
This is not the right way to copy c-strings. use strcpy or strncpy:
strcpy(newNode->name,newName);
As #Pablo pointed out you didn't allocate memory for string, so first allocate and then copy:
newNode->name = malloc(strlen(newName)+1);
strcpy(newNode->name,newName);
The code seems fine to me. But what do you mean by works great except for the transfer of the char array? Do you get an error, segfault, something unexpected and if so what?

A simple stack implementation using C

I had written a program in C to implement a simple stack. But I am getting segmentation fault in my program and finding it hard to find out what is wrong. Can any one help,
#include<stdio.h>
#include<stdlib.h>
struct stack_structure{
int stack_array[10];
int stack_pointer;
};
void push_into_stack(struct stack_structure *,int);
int main(){
int no = 8;
struct stack_structure *st;
st->stack_pointer = -1;
push_into_stack(st,no);
return 0;
}
void push_into_stack(struct stack_structure *s,int no){
s -> stack_pointer++;
s -> stack_array[s -> stack_pointer] = no;
}
struct stack_structure *st;
This only creates a pointer to a struct stack_structure. It does not allocate memory for the struct stack_structure itself.
You can try with this:
struct stack_structure st;
st.stack_pointer = -1;
push_into_stack(&st,no);
The other option is to dynamically allocate (and free) that structure:
struct stack_structure *st = malloc(sizeof(struct stack_structure));
...
// when you're done with it
free(st);
See these lines:
struct stack_structure *st;
st->stack_pointer = -1;
You've declared a pointer variable but then you're using it uninitialized. A pointer has to point at something, and this one doesn't have anything to point to. The simplest fix would be to change these lines to:
struct stack_structure st1, *st=&st1;
st->stack_pointer = -1;
You need to malloc some space for the structure:
struct stack_structure *st = malloc(sizeof(struct stack_structure));

Resources