How is this statically allocated struct data available outside the function? - c

Here is a quick test C program that I've coded to see how struct memory allocation works...
#include <stdio.h>
#include <stdlib.h>
typedef struct _node {
int kk;
int zz;
} node;
node ** createNode(){
node** res = (node**) malloc(sizeof(node*)*10);
int i,j;
for(i= 0;i<10;i++){
res[i] = (node*) malloc(sizeof(node)*10);
for(j=0;j<10;j++){
res[i][j].kk=33;
}
}
return res;
}
int main(void) {
node ** g = createNode();
printf("%d",g[0][0].kk);
return 0;
}
This program prints the value "33". Now this has become obvious to me, but reflecting on it, I don't understand why...
Now that I think about it, shouldn't the variable g be of type node *** ?
And the print statement look something like printf("%d",g[0][0]->kk); ?
Where in the second version, I've essentially done the same thing as my original code, but I have a pointer to a node instead of the actual node.
What is the difference between the two in terms of the first being statically allocated (I think) and the second being dynamically allocated... and shouldn't the node values I created in my createNode() function be destroyed once outside the scope of that function?
Just a little confused is all :S I need someone to clarify this for me, what is the difference between node** and node***

Let's use a simpler function to make samples. For example we want to create a function which will be allocate memory for integer and assign some value. The function does the same thing as your one.
int* createInt() {
int *res = malloc(sizeof(int));
*res = 5;
return res;
}
This function creates a pointer and allocate dynamic memory for int. After this the function returns an address of memory where the int is but the res pointer won't exist. By the way look at this answer to similar question, it's worth reading.
As you understand in main function you use
int *myInt = createInt();
Because you want to assign an address of allocated memory to pointer to deal with that and free after all.
But you could do this
int** createInt() {
static int *res;
res = malloc(sizeof(int));
*res = 5;
return &res;
}
And in main
int **myInt = createInt();
Here you do the same things as above but create static pointer so it is retained from one call of the function to another. So you can return an address of this pointer. It will point to actual data after function ends.
As mentioned in comments my code isn't safe because if you call this function twice it leads to memory leak. You could do
int* createSingletonInt() {
static int *res;
if (res != NULL) {
return res;
}
res = malloc(sizeof(int));
*res = 5;
return res;
}
That can be useful if you want to deal with the same int. And more useful if you deal with something but not int :>
I think it can be applied to your example.

Related

Free in a structure element

Hello I have a question regarding malloc and free type of things.
suppose I have a structure with another structure inside it
typedef struct All{
int number;
} A;
typedef struct Bet{
A *point;
} B;
Then I create a B.
B* first = malloc(sizeof(B));
first->point=malloc(sizeof(A));
Now lets say I want to make a function that deletes the struct B entirely.
For the delete function I know we have to use
free(first);
So do I also have to free(first->point) or will it disappear automatically if i do free(first);
I want to add more to what #thisisbenmanley said and build an actual explination that will also show how to wrap part of the code you write.
The basics
I'll cover just malloc() and free() here. Whenever you call malloc() there should be a free() also. Let's take this example with a simple int.
int *p = malloc(sizeof(int));
*p = 5;
printf("%d", *p);
free(p);
It is the same for a struct. Another example:
typedef struct Person
{
int Age;
int Height;
}Person;
Person* p = malloc(sizeof(Person));
p->Age = 20;
p->Height = 185;
// do something with it ...
free(p);
Another very important thing you have to know: malloc() can return NULL if the allocation fails. It actually means that there is no space to allocate the block. It is very important to actually check for it. For example:
int* v = malloc(sizeof(int)*999999999);
if (v == NULL)
{
printf("Allocation failed.");
return -1;
}
// Allocation successfull. Do something with the vector ...
Structures in structures and structures with pointers
If structures do not contain pointers just free() will do the job. Example:
typedef struct Point
{
int x;
int y;
}Point;
typedef struct Line
{
Point a;
Point b;
}Line;
// this will allocate actually 4 ints
Line* p = malloc(sizeof(Line));
// this is how you access each point's coordinates.
p->a.x;
// do something ...
// this will free both points (the 4 ints)
free(p);
Now this is where code can get very unclear depending on each situation. If a structure contains one or more pointers if might prove difficult to keep the code simple to read. Suppose the following struct:
typedef struct Person
{
int Age;
int Height;
char* FName;
char* LName;
char* Address;
}Person;
If you want to allocate a Person you need 4 malloc() calls. If you also add error checking it will be quite voluminous. Definetly this should be wrapped inside a function:
Person* AllocPerson()
{
// i'm skipping it now so that my point is clear, but checking
// if malloc returned NULL is recommended
Person* p = malloc(sizeof(Person));
p->FName = malloc(sizeof(char)*30);
p->LName = malloc(sizeof(char)*30);
p->Address = malloc(sizeof(char)*40);
return p;
}
Now whenever you need a Person you can just Person* p = AllocPerson();. Same goes with a FreePerson() function which will take 4 free() calls so that after you finished working with the struct, you simply call FreePerson(p).
void FreePerson(Person* p)
{
free(p->FName);
free(p->LName);
free(p->Address);
free(p);
}
You can evolve the AllocPerson function even further and turn it into a Create function:
Person* CreatePerson(int Age, int Height, char* FirstName, char* LastName, char* Address)
{
// i'm skipping it now so that my point is clear, but checking
// if malloc returned NULL is recommended
Person* p = malloc(sizeof(Person));
p->FName = malloc(sizeof(char)*30);
p->LName = malloc(sizeof(char)*30);
p->Address = malloc(sizeof(char)*40);
p->Age = Age;
p->Height = Height;
strcpy(p->FName, FirstName);
strcpy(p->LName, LastName);
strcpy(p->Address, Address);
return p;
}
Now you can just do this whenever you need a person:
Person* p = CreatePerson(20, 180, "Alex", "Boris", "Street nr. 5");
The CreatePerson() function both allocates and initialises fields of a Person instance. This aproach of making a Create and Delete function to a structure is widely used in C, especially when you have to use an already made API.
Important notes
Always free() memory even though after exiting main() your OS will take care of the blocks still allocated. This is considered good practice.
Try to use dynamic memory as less as possible. The Heap is slower than the Stack!
Try to reuse allocated space whenever possible. Allocating and Freeing are expensive operations!
You would also have to free(first->point). When you free(first), all that will deallocate is the bytes holding the struct first, which only holds a pointer. That alone will not touch the actual memory address pointed to by point; free(first->point) beforehand would cover that.

I can alter a struct member from one location but not from the other

I am trying to implement a linked list in C - starting simple, with one list containing one node. However, I stumble upon some issues when trying to add data to the node. Here's my implementation thus far:
struct mylist_node {
int data;
};
struct mylist {
struct mylist_node *head_pt;
};
void mylist_init(struct mylist* l){
struct mylist_node head_node;
head_node.data = 5; //First try
l->head_pt = &head_node;
l->head_pt->data = 5; //Second try
};
And my main method:
int main()
{
struct mylist ml, *ml_pointer;
ml_pointer = &ml;
mylist_init(ml_pointer);
printf("%d\n", ml_pointer->head_pt->data);
ml_pointer->head_pt->data = 4;
printf("%d\n", ml_pointer->head_pt->data);
return 0;
}
This should print out
5
4
If my knowledge of pointers is correct. However, it prints out
0
4
As you can see I try to set the node data twice within the mylist_init method. Neither appears to be working - meanwhile, writing to and reading from it from my main method works just fine. What am I doing wrong?
In mylist_init, you're storing the address of a local variable in the struct pointed to by l. That variable goes out of scope when the function returns, so the memory it occupied is no longer valid, and thus the pointer that previously pointed to it now points to an invalid location. Returning the address of a local variable a dereferencing that address invokes undefined behavior.
Your function needs to allocate memory dynamically using malloc so the memory will still be valid when the function returns.
void mylist_init(struct mylist* l){
struct mylist_node *head_node = malloc(sizeof(*head_node));
l->head_pt = head_node;
l->head_pt->data = 5;
};
Also, don't forget to free the memory when you're done using it.
For starters, you have to allocate memory for your node, the way you were doing it, your node is a local variable on the stack which will likely get overwritten after the function exits.
void mylist_init(struct mylist* l)
{
struct mylist_node *head_node = (struct mylist_node *)malloc(sizeof(struct mylist_node));
head_node.data = 5; //First try
l->head_pt = head_node;
};

why and when is a double-pointer required?

I have been a sysadmin most of my life, but recently decided to practice some my dev knowledge and attempt a devops position. I have as such been practicing some C and Python skills and wrote some code for inserting a number into a linked list.
void list_insert(struct list *h, int d)
{
struct list *elem = malloc(sizeof(struct list));
elem->data = d;
elem->next = NULL;
if (!h) {
h = elem;
} else {
elem->next = h;
h = elem;
}
}
I noticed that this function doesn't seem to alter the outside view of the variable h (i.e whatever is passed to list_insert) and I noticed that printing at the end of the insert function seems to work. So having tried to look for answers online, I couldn't find anything, obvious but I found most list implementations would have double-pointers. I changed my function to use double-pointers and then it suddenly started working. Could someone help me understand what's happening here as I know pointer management is an important concept and I think I understand what a pointer is and how it relates to memory, but I don't think I get why a single pointer does not get changed, whereas a double-pointer does.
Thanks!
In C, arguments to function are passed by values. Even pointers are passed by values.
For example:
#include<malloc.h>
#include<stdio.h>
int allocatingMemory(int* ptr)
{
ptr = malloc(sizeof(int));
if(ptr==NULL)
return -1;
else
return 0;
}// We are not returning the pointer to allocated memory
int main(void)
{
int* ptr;
int allocated = allocatingMemory(ptr);
if(allocated == 0)
{
*ptr = 999;// Boom!!!
free(ptr);
}
return 0;
}
To overcome this issue, we use
int allocatingMemory(int** ptr)
{
*ptr = malloc(sizeof(int));
if(*ptr == NULL)
return -1;
else
return 0;
}
int main(void)
{
int* ptr;
int isAllocated = allocatingMemory(&ptr);
if(isAllocated == 0)
{
*ptr = 999;
free(ptr);
}
return 0;
}
If you are working with linked lists and say for example, you want to modify the head. You will pass a pointer to pointer (Note that, it is not called as double pointer) to head node.
To change memory in the caller's context, a function needs to have a pointer to that memory.
If the caller of your function has an empty list in a variable, and does an insert on that list like so:
struct list *numbers = NULL;
list_insert(numbers, 4711);
then of course inside list_insert() all we have is the NULL pointer, so we can't change the value of the variable numbers in the caller's context.
If, on the other hand, we're given a pointer to the variable, we can change the variable.
That said, it's much cleaner (in my opinion) to return the new head of the list, i.e. make the function's signature be struct list * list_insert(struct list *head, int x);.
h is actually a copy of the original pointer, so your original pointer doesnot get modified. That is why you should use a double pointer.
There are numerous questions related to that on SO. for example Using single versus double pointers in Linked lists implemented in C

A hashtable of pointers in C?

I am trying to build an initialize a hashtable whose pointers point to another struct in my program. But it seems to give me a segfault when I try to initialize(H). I think I may be allocating memory incorrectly, but I'm not sure if that's what a segmentation fault actually means. The way it is set up, H->hashtable should be an array of hashnodes, right? hashnodes themselves are the pointers to my other structs. Why am I only getting a seg fault at initialize?
#include <stdio.h>
#include <stdlib.h>
typedef struct Position{
char data[12];
struct Hashnode *previous;
struct Position *next;
char letter;
char direction[5];
} *position;
typedef struct Hashnode{
struct Position *INSIDE;
} *hashnode;
typedef struct hash_table{
hashnode *hashtable
} *HTABLE;
HTABLE NewHashtable(){
HTABLE H = (HTABLE) malloc(sizeof(struct hash_table));
if(H == NULL){ printf("Malloc for new hashtable failed."); exit(1);}
return H;
}
void initialize(HTABLE H){
H->hashtable = (hashnode*) malloc(100003*sizeof(hashnode));
int toofer;
for(toofer = 0; toofer<100003; toofer++){
H->hashtable[toofer]->INSIDE = NULL;
}
}
int main(){
HTABLE H = NewHashtable();
initialize(H);
return 0;
}
This:
HTABLE H = (HTABLE) malloc(sizeof(struct hash_table));
is just horrible. It mixes a typedef:ed pointer (why do people still do this?) with the underlying struct name, making it the reader's job to make sure they match. Plus, that cast is a bad idea, too.
It should be:
HTABLE H = malloc(sizeof *H);
if you insist on keeping the typedef.
That said, the code in initialize() is probably failing its malloc() call, which is not checked before being relied on. This is a very bad idea.
Further, there's confusion about what exactly is being allocated. The malloc() code allocates 100003*sizeof(hashnode), but hashnode is (again) typedef:ed as a pointer, not a struct. Then the pointers are dereferenced in the loop, causing mayhem.
H->hashtable = (hashnode*) malloc(100003*sizeof(hashnode));
int toofer;
for(toofer = 0; toofer<100003; toofer++){
H->hashtable[toofer]->INSIDE = NULL;
}
}
The first line allocates a bunch of memory for H->hashtable. It contains random garbage.
Thus, when you enter the loop, H->hashtable[0] is random garbage (because all of H->hashtable is random garbage). But you attempt to follow that random garbage pointer in in your loop. Dereferencing an uninitialized pointer is the fastest way to get a segmentation fault.
Here's a way to help you see it. Say you decided to zero that memory to be safe. Your code would be:
H->hashtable = (hashnode*) malloc(100003*sizeof(hashnode));
memset(H->hashtable, 0, 100003 * sizeof(hashnode));
int toofer;
for(toofer = 0; toofer<100003; toofer++){
H->hashtable[toofer]->INSIDE = NULL;
}
}
Clearly, after that memset, *(H->hashtable) is 0 since that sets all of H->hashtable to 0. So H->hashtable[0] is 0 too and thus H->hashtable[toofer]->INSIDE dereferences a null pointer.
H->hashtable = (hashnode*) malloc(100003*sizeof(hashnode));
should better be
...sizeof(struct Hashnode)...

Values in array of structs turning into garbage values

I have an issue that's really confusing me... Below I am calling an initialize function:
void Initialize (List *L) {
char* initialize = "initialize";
int i;
for (i=0; i<MAXLISTSIZE; i++) {
strncpy(L->items[i].name,initialize,MAXNAMESIZE);
L->items[i].name[MAXNAMESIZE - 1] = '\0';
L->items[i].grade = 0;
printf("L->items[i].name = %s\n", L->items[i].name);
printf("L->items[i].grade = %d\n", L->items[i].grade);
}
L->count = 0;
}
And it seems to work, I print the values in the loop and it's fine. If I also print inside an identical loop in main to double check it works as well but If I just print the values in main after the initialize function (no print statements in Initialize) I get complete garbage.
It seems the memory I'm storing my values in isn't staying consistent and I can't figure out why.
Do I need to malloc memory for the structs? Since I don't need a variable amount of storage I thought it was not necessary... I am unsure of how to go about that.
My Structs:
typedef Student Item;
#define MAXLISTSIZE 4
typedef struct {
Item items[MAXLISTSIZE];
int count;
} List;
#define MAXNAMESIZE 20
typedef struct {
char name[MAXNAMESIZE];
int grade;
} Student;
I am simply calling Initialize from main:
int main () {
List *newList;
/*call initialize function*/
newList = callInitialize();
return 0;
}
callInitialize:
List *callInitialize () {
List *L;
List studentList;
L = &studentList;
Initialize(L);
return L;
}
Now that you posted the function that causes the actual problem, we see what's wrong: You are returning the address of a local variable that goes out of scope! This is not valid.
List * foo()
{
List x; // <--- x comes to life
return &x; // <--- x dies here...
}
int main()
{
List * p = foo(); // ... but its address is used here!
p->name ... // dereferencing an invalid address!!
}
Your situation calls for dynamic (or "manual") allocation, which means memory allocation whose lifetime is controlled only by you, and not by the local scope.
List * initList()
{
return malloc(sizeof(List)); // this memory is permanent
}
Any manual allocation needs to come with a clean-up routine:
void freeList(List * p)
{
free(p);
}
Now that you've posted the remainder of your code, the problem is obvious:
List *callInitialize () {
List *L;
List studentList;
L = &studentList;
Initialize(L);
return L;
}
Within this function you create a local variable studentList which you the pass to Initialize to set it up.
Unfortunately, the scope of the studentList variable ends when you exit the callInitialize function. That's why it may contain rubbish when you attempt to use it later on.
Despite your comment about not needing malloc because the structure is small, you do need it if you want the scope of the data to exist beyond the function it's created in.
Probably the "minimal-change" solution would be:
List *callInitialize (void) {
List *L = malloc (sizeof (List));
if (L != NULL)
Initialize(&L);
return L;
}
and then remember that it needs to be freed at some point by the caller, unless the malloc fails and this function therefore returns NULL.

Resources