Unable to understand Memory allocation of structure - c

Consider following C code -
typedef struct node
{
int data;
}node;
int main()
{
node *temp;
temp->data=100;
printf("%d",temp->data);
return 0;
}
It gives Segmentation fault on line containing temp->data=100; because (I think) I haven't allocate memory for it. So, there is nothing such as temp->data.But, when I try with -
int main()
{
node *temp,*n;
n=(node*)malloc(sizeof(node));
n->data=100;
temp->data=n->data;
printf("%d",temp->data);
retrun 0;
}
It gives proper output 100.
I haven't allocate memory where temp will point. But still I am copying n->data to temp->data. How ??

The temp pointer takes some garbage value as its not initialised. By chance temp has a garbage value which may happen to be legal address for your program so it runs. If garbage value has illegal adress it will generate segment fault.

You're lucky.
Local variables are not initialized automatically, so when the program begins, both temp and n contain whatever values happen to be on the stack. Next, memory is allocated and n is set to point to it. The value 100 is stored in the data member of the structure.
But temp is still uninitialized, so the value 100 is copied into an unspecified area of memory. Depending on where that memory happens to be, the program may segfault, or it may simply corrupt memory that it doesn't own.

That you haven't got a segfault in temp->data=n->data; is just coincidence. temp is not initialized and hence it points into the digital nirvana.
When you've called malloc you've allocated sizeof node bytes (in reality it may be even a little more) and then you have full memory access to the block pointed to by n.
In general you should call malloc in this way:
node *n;
n = malloc(sizeof *n);
without a cast
with sizeof *n instead of sizeof <datatype>. If you change the datatype (for example you have a typo and instead of typedef .... node you've writen typedef ... nhode. Then you only have to change the declarations of the variables and the rest of the code doesn't have to be changed at all.

Your first code is also right just "temp" is pointing to a garbage value so you have to initialized that.
temp=(node *)malloc(sizeof(node));

Your right on the first part, it segfaults because node* temp isn't pointing anywhere (well, somewhere, but not to allocated memory).
I don't know why the second one "works". I suspect it only appears to work, in that it's not crashing. But since temp was never initialized, who know where it's sticking that '100'. Maybe just hanging around to crash later. Either way, writing to unitialized memory isn't a good idea ;-0

Related

C: Is my understanding about the specifics of heap and stack allocation correct?

I have a sort of linked list implemented (code at bottom) in C (which has obvious issues, but I'm not asking about those or about linked lists; I'm aware for instance that there are no calls to free() the allocated memory) given below which does what I expect (so far as I've checked). My question is about the first couple of lines of the addnodeto() function and what it does to the heap/stack.
My understanding is that calling malloc() sets aside some memory on the heap, and then returns the address of that memory (pointing to the beginning) which is assigned to struct node *newnode which is itself on the stack. When the function is first called, *nodetoaddto is a pointer to struct node first, both of which are on the stack. Thus the (*nodeaddto)->next = newnode sets first.next equal to the value of newnode which is the address of the newly allocated memory.
When we leave this function, and continue executing the main() function, is *newnode removed from the stack (not sure if 'deallocated' is the correct word), leaving only struct node first pointing to the 'next' node struct on the heap? If so, does this 'next' struct node have a variable name also on the stack or heap, or it is merely some memory pointed too? Moreover, is it true to say that struct node first is on the stack, whilst all subsequent nodes will be on the heap, and that just before main() returns 0 there are no structs/variables on the stack other than struct node first? Or is/are there 1/more than 1 *newnode still on the stack?
I did try using GDB which showed that struct node *newnode was located at the same memory address both times addnodeto() was called (so was it removed and then happened to be re-defined/allocated in to the same location, or was perhaps the compiler being smart and left it there even once the function was exited the first time, or other?), but I couldn't work anything else out concretely. Thank you.
The code:
#include <stdio.h>
#include <stdlib.h>
#define STR_LEN 5
struct node {
char message[STR_LEN];
struct node *next;
};
void addnodeto(struct node **nodeaddto, char letter, int *num_of_nodes){
struct node *newnode = malloc(sizeof(struct node));
(*nodeaddto)->next = newnode;
newnode->message[0] = letter;
(*nodeaddto) = newnode;
*num_of_nodes += 1;
}
int main(void){
struct node first = {"F", NULL};
struct node *last = &first;
int num_nodes = 1;
addnodeto(&last, 'S', &num_nodes);
addnodeto(&last, 'T', &num_nodes);
addnodeto(&last, 'I', &num_nodes);
printf("Node: %d holds the char: %c\n", num_nodes-3, first.message[0]);
printf("Node: %d holds the char: %c\n", num_nodes-2, (first.next)->message[0]);
printf("Node: %d holds the char: %c\n", num_nodes-1, ((first.next)->next)->message[0]);
printf("Node: %d holds the char: %c\n", num_nodes, (last)->message[0]);
return 0;
}
Which when run outputs:
Node: 1 holds the char: F
Node: 2 holds the char: S
Node: 3 holds the char: T
Node: 4 holds the char: I
As expected.
My understanding is that calling malloc() sets aside some memory on the heap, and then returns the address of that memory (pointing to the beginning)…
Yes, but people who call it “the heap” are being sloppy with terminology. A heap is a kind of data structure, like a linked list, a binary tree, or a hash table. Heaps can be used for things other than tracking available memory, and available memory can be tracked using data structures other than a heap.
I do not actually know of a specific term for the memory that the memory management routines manage. There are actually several different sets of memory we might want terms for:
all the memory they have acquired from the operating system so far and are managing, including both memory that is currently allocated to clients and memory that has been freed (and not yet returned to the operating system) and is available for reuse;
the memory that is currently allocated to clients;
the memory that is currently available for reuse; and
the entire range of memory that is being managed, including portions of the virtual address space reserved for future mapping when necessary to request more memory from the operating system.
I have seen “pool” used to describe such memory but have not seen a specific definition of it.
… which is assigned to struct node *newnode which is itself on the stack.
struct node *newnode is indeed nominally on the stack in common C implementations. However, the C standard only classifies it as automatic storage duration, meaning its memory is automatically managed by the C implementation. The stack is the most common way to implement that, but specialized C implementations may do it in other ways. Also, once the compiler optimizes the program, newnode might not be on the stack; the compiler might generate code that just keeps it in a register, and there are other possibilities too.
A complication here is when we are talking about memory use in a C program, we can talk about the memory use in a model computer the C standard uses to describe the semantics of programs or the memory use in actual practice. For example, as the C standard describes it, every object has some memory reserved for it during its lifetime. However, when a program is compiled, the compiler can produce any code it wants that gets the same results as required by the C standard. (The output of the program has to be the same, and certain other interactions have to behave the same.) So a compiler might not use memory for an object at all. After optimization, an object might be in memory at one time and in registers at another, or it might always be in a register and never in memory, and it might be in different registers at different times, and it might not be any particular place because it might have been incorporated into other things. For example, in int x = 3; printf("%d\n", 4*x+2);, the compiler might eliminate x completely and just print “14”. So, when asking about where things are in memory, you should be clear about whether you want to discuss the semantics in the model computer that the C standard uses or the actual practice in optimized programs.
When the function is first called, *nodetoaddto is a pointer to struct node first, both of which are on the stack.
nodetoaddto may be on the stack, per above, but it also may be in a register. It is common that function arguments are passed in registers.
It points to a struct node. By itself, struct node is a type, so it is just a concept, not an object to point to. In contrast, “a struct node” is an object of that type. That object might or might not be on the stack; addnodeto would not care; it could link to it regardless of where it is in memory. Your main routine does create its first and last nodes with automatic storage duration, but it could use static just as well, and then the nodes would likely be located in a different part of memory rather than the stack, and addnodeto would not care.
Thus the (*nodeaddto)->next = newnode sets first.next equal to the value of newnode which is the address of the newly allocated memory.
Yes: In main, last is initialized to pointer to first. Then &last is passed to addnodeto, so nodeaddto is a pointer to last. So *nodeaddto is a pointer to first. So (*nodeaddto)->next is the next member in `first.
When we leave this function, and continue executing the main() function, is *newnode removed from the stack (not sure if 'deallocated' is the correct word), leaving only struct node first pointing to the 'next' node struct on the heap?
newnode is an object with automatic storage duration inside addnodeto, so its memory is automatically released when addnodeto ends.
*newnode is a struct node with allocated storage duration, so its memory is not released when a function ends. Its memory is released when free is called, or possibly some other routine that may release memory, like realloc.
If so, does this 'next' struct node have a variable name also on the stack or heap, or it is merely some memory pointed [to]?
There are no variable names in the stack or in the heap. Variable names exist only in source code (and in the compiler while compiling and in debugging information associated with the compiled program, but that debugging information is generally separate from the normal execution of the program). When we work with allocated memory, we generally work with it only by pointers to it.
Moreover, is it true to say that struct node first is on the stack, whilst all subsequent nodes will be on the heap,…
Yes, subject to the caveats about stack and “heap” above.
… and that just before main() returns 0 there are no structs/variables on the stack other than struct node first?
All of the automatic objects in main are on the stack (or otherwise automatically managed): first, last, and num_nodes.
Or is/are there 1/more than 1 *newnode still on the stack?
No.

Will a pointer declaration to a structure allocate memory for its members?

check the image of program on turbo c++
output of program
#include< stdio.h>
struct node {
int data;
};
int main() {
struct node *ptr;
ptr->data=3;
printf("%d",ptr->data);
return 0;
}
Output: 3
My question is that even though I have not declared an instance of structure node.
e.g struct node n;
Also I have not assigned memory for ptr using malloc, it still allocates space for ptr->data. Why?
Shouldn't it just assign memory for address ptr on stack.
And where this memory for data field is allocated, on stack or heap.---------
In your code, ptr->data=3; invokes undefined behavior, as ptr does not point to any valid memory location.
You need to make sure that ptr points to a valid memory location before making any attempt to de-reference it.
It appears to work properly in your case, that is also one of the most dangerous side effects of undefined behavior.
That said, ptr is having automatic storage. The memory it would point to, will depend on the allocation used. C standard does not have a notion of stack or heap - that is dependent on the implementation.
Also I have not assigned memory for ptr using malloc, it still allocates space for ptr->data.
Nothing's been allocated. Without an initializer, the value of ptr is indeterminate, and in this case just happens to point to memory that you can write to without immediately crashing your program. You managed to not overwrite anything "important", but that's a matter of luck more than anything else.
You should get in the habit of initializing pointers as you declare them, either as NULL or as the result of the & operator or as the result of a malloc/calloc/realloc call.
When you are creating the pointer struct node *ptr; it will be placed on your stack.
The place where this variable is placed can be anywhere in your stack.
For example it is placed on address 0x100.
When the variable is placed on that location, the data that is there is not set to 0.
So on address 0x100 was the data 0x200 for example, you will have a struct node *ptr pointing to the address 0x200.
Then at that point you are doing the following ptr->data=3; As the code thinks that there is a struct node placed at your address 0x200, it will fill the variable data in there. So on the address 0x200 will the value 3 be written.
When you are in luck (well actually it isn't really luck, as it could cause lots of problems later on) the writing of the value 3 at the address 0x200will not cause any problems, because the memory at address 0x200 wasn't used.
But keep in mind that your code only THINKS that the struct node was placed at that location, but actually there isn't one, so any other variable could be on that location. And when there is a different variable on that address. when you write the value 3 to that address you are you are overwriting the value of that variable. And that could create some very strange behavior in your code.

No warnings when trying to access freed memory in C [duplicate]

This question already has answers here:
Why do I get different results when I dereference a pointer after freeing it?
(7 answers)
Closed 8 years ago.
I'm trying to understand the how the memory is managed in C. In the sample code below, in the comments I have added my understanding on how the memory is managed.
I would like to know if I'm correct
In the final part of the code, I'm trying to access a part of memory which is already freed. I'm surprised why the compiler did not through any warnings
struct node
{
int keys[2];
int *pkeys;
};
int main()
{
int temp[2] = {10,20}; // creates a temp array in stack
struct node* node = malloc(sizeof(struct node)); //allocates a block of memory on heap pointed by node
node->keys[0]=1;node->keys[1]=2; // assigns values for keys present in heap
node->pkeys = malloc(2*sizeof(int)); // creates a pointer pkeys in heap
node->pkeys = temp; // the pointer pkeys in heap points to the temp array in stack
free(node); // the block of memory on heap pointed by node is freed
node->keys[0] = 9; //**Why does the compiler ignore that I'm accessing freed memory?**
}
The compiler in C does not do that sort of checking. If gives enough rope to hang yourself.
It is up to you to do the checks. That is also true for bounds checking of arrays.
Also you need to note that malloc/free does not always have to beg/give to the OS. That means it may still be accessible by the process without seg fault.
The compiler does not check for illegal memory access and your program will cause undefined behaviour or may even crash (segmentation fault). The behaviour is unpredictable and next time you run your program, it may crash.
Few things about your code:
The signature of main should either be int main(void) or int main(int argc, char *argv[]).
The comment for this statement is wrong.
node->pkeys = malloc(2*sizeof(int)); // creates a pointer pkeys in heap
You created the pointer pkeys when you allocated memory and made node point to it. This statement is dynamically allocating memory for array of 2 ints and making pkeys point to it. So when you do node->pkeys = temp, you lose handle on the dynamically allocated array and will cause memory leak. So before reassigning pkeys, you must free the memory it points to.
free(node->pkeys);
// now reassign node->pkeys
The space allocated to node is freed but node still points to the same location. So it is still accessible. But if you are unlucky (that is the OS reused the memory for its own purposes) you will get a segmentation fault.

Trouble with Malloc for Structs

I keep constantly getting a segmentation error with a small portion of code and I have no idea why, I'm using malloc and cant see any reason with that, just as soono as it hits the portion of data, its crashes.
The Data is:
listNode* node = (listNode*)malloc(sizeof(listNode)); <-This is the Line
strcpy(node->entry, string);
node->next = NULL;
Using the struct definition:
typedef struct
{
char* entry;
struct listNode* next;
}listNode;
The data does get freed at one point, however it cannot reach said point.
Thanks for the help!
Are you sure you're crashing on the malloc call? It's much more likely that you're crashing on the strcpy. In fact, the strcpy in this case is almost guaranteed to cause bad behavior, although to be precise the behavior is undefined.
The malloc should succeed as long as you haven't filled up your heap. However, because you called malloc and not calloc, you have no guarantees about the contents of node->entry. The C standard doesn't define what is stored in memory allocated with malloc, so node->entry is filled with garbage. By trying to copy to a bad pointer, your app is crashing for attempting to accessing an incorrect memory address.
Alexey Frunze is 100% correct on the fix - malloc space and change node->entry to point at the newly allocated memory, then copy string into node->entry. This avoids undefined behavior for using an uninitialized pointer, as I described in another SO answer.
You didn't allocate memory for the entry pointer. You're trying to copy your string to a bogus location specified by the uninitialized pointer entry. You might do this instead:
node->entry = malloc(strlen(string) + 1);
strcpy(node->entry, string);
You are not allocating allocate memory for the entry pointer. as while allocationg structure just 4 bytes allocated for *entry pointer
you should do
listNode* node = (listNode*)malloc(sizeof(listNode)); // allocate memory for structure
node->entry = malloc(strlen(string) + 1);// allocate memory for string
strcpy(node->entry, string); //copying strings
now it will run fine

Variable Declaration in C

I am trying to declare a integer variable m and a pointer to integer data type n.
int m,*n;
*n=2;
printf("%d",*n);
above code works fine.
But
int *n,m;
*n=2;
printf("%d",*n);
gives segmentation fault.
please explain why?
Both versions are wrong—you just got lucky with the one that worked. You've declared a pointer but not allocated any storage for it. Try this:
int *n,m;
n=&m;
*n=2;
printf("%d",*n);
Or using malloc():
int *n;
n=malloc(sizeof(int));
*n=2;
printf("%d",*n);
free(n);
Both code segments invoke undefined behaviour, because you dereference an uninitialized pointer. When there is UB, nasal demons fly out of your nose... or your program orders pizza, or it crashes, or it works... You must alllocate memory first.
int* n = malloc(sizeof(int));
*n = 2;
free(n);
Or set it to an address of another object;;
int *n, m;
n = &m;
*n = 2;
When you declare a pointer variable, it allocates some block of space in memory. This space already contains some data left over from whatever it was used for before this program. It gives a segmentation fault because whatever data is in the pointer refers to a memory location outside of your space on the hard drive. As Armen said, you have to initialize the pointer by telling it where to point. This will replace the data currently in the pointer with the address of your variable m (or wherever you want it to point).
n is uninitialized pointer. Access to it causes error.
You are lucky the first one works at all. Both of them are accessing a non-initialized pointer.
What does "n" point to? Since it is uninitialized, it is pointing to nothing. In each case, you are assigning whatever n is pointing to the value of 2. The first will eventually lead to a nasty bug. You are lucky on the second one because it crashed right away.
Use malloc to create some memory for n to point to, and then assign it.

Resources