Where are character arrays in dynamically allocated structs stored? [duplicate] - c

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
C Array Instantiation - Stack or Heap Allocation?
When dynamically allocating a struct containing a char pointer, what happens with the actual char pointer? Where is it stored?
And once the struct is freed, is the char pointer freed along with it?
For example consider the following struct:
struct mix
{
int a;
float b;
char *s;
};
typedef struct mix mix;
And then the following code that allocates memory for it:
int main()
{
mix *ptr = (mix*)malloc(sizeof(mix));
ptr->a = 3;
ptr->b = 4.5f;
ptr->s = "Hi, there, I'm just a really long string.";
free(ptr);
return 0;
}
Is *s allocated on the stack and then freed along with *ptr? I can imagine it is indeed allocated on the stack as it's not in any way dynamically allocated (unless malloc has some functionality I'm not aware of). And I guess 'going out of scope' for *s would be at the point of freeing *ptr. Or have I got it completely wrong? :)
Thanks very much!

The space for the char* member named s is allocated on the heap, along with the rest of the members of mix after the call to malloc() (whose return value you do not need to cast). The string literal to which s is assigned is not allocated on the heap or the stack, but is part of the actual binary and has static storage duration. So this:
ptr->s = "Hi, there, I'm just a really long string.";
assigns the address of the string literal to ptr->s. If you want ptr->s to point to something other than a string literal then you need to malloc() memory for it. And for every malloc() there must be a free() so ptr->s would need to be free()d before ptr is (if ptr->s is pointing to dynamically allocate memory only).
After the call to free(), dereferencing ptr is undefined behaviour.

When you dynamically allocate mix with malloc(), you are actually allocating a block of memory to store mix structure data members, i.e.
an int (a)
a float (b)
a pointer to a char (s)
And when you call free(), you just release that block.
So, you don't allocate the string, you just allocate the string pointer.
If you want to dynamically allocate the string, you must do it explicitly (with another call to malloc()), and to avoid memory leaks you should also free the string explicitly, using free().

When you malloc for ptr, memory is allocated for all members of the struct including the pointer s which is no different to memory allocated for any other member of the struct.
You are assigning a string literal to s, so it's fine which is usually stored in the read-only section. Otherwise, you'll need to malloc for the ptr->s as well and free. Since, it's a string literal, there's no need to free s here (doing so is UB).

mix* ptr is allocated on the stack. The contents that ptr point at, a variable of type mix, is allocated dynamically on the heap, including the pointer s.
Please note that s doesn't point at anything, the pointer doesn't do anything useful. You have to set it to point at something, which could be allocated anywhere. Whatever it points to is not freed when your struct is freed. In this case you set it to point at a constant string literal allocated in ROM, so you won't need to worry about that.

Is *s allocated on the stack
*s (that is, the result of dereferencing the pointer s) isn't allocated at all. Following the malloc, ptr->s is an uninitialized pointer. It doesn't point to anything, and the expression *(ptr->s) has undefined behavior until you do ptr->s = "Hi, etc".
Once you've initialized ptr->s to point to the string literal, *(ptr->s) is the first character of the string literal, so it probably exists in some data section of the executable. Nothing is dynamically allocated other than the sizeof(mix) bytes for the struct (probably 12 bytes on a 32bit implementation).

what happens with the actual char pointer? Where is it stored?
char* is also like other members, take some bytes(take 8 byte in 64 bit machine, similar to other pointer). In your case, you are allocating memory for that structure instance in heap. so the memory for this pointer also will be allocated in same heap block which is allocated for that structure instance.
Consider this code. This gives where the char* will be:
#include <stdio.h>
typedef struct
{
int a;
float b;
char *s;
}mix;
int main()
{
printf("\n%d ,float:%d, int:%d, char*:%d", sizeof(mix), sizeof(float), sizeof(int), sizeof(char*));
return 0;
}
so size of this structure is 16 bytes. consist of 4 byte integer, 4 byte float and 8 byte char*. (In 64 bit OS, char* will be 4 bytes if OS is 32 bit.)
And once the struct is freed, is the char pointer freed along with it?
Usually the block which is pointed by char* will not be freed(If it points to a block allocated by malloc()). only the structure block will be freed. we know free() needs valid address which is returned during allocation for peaceful de-allocation. If you free without freeing that char*, it will leads to memory leak.
But your case "Hi, there, I'm just a really long string.";
the above given string is string literal which is allocated in read-only section of your program.
use gcc -S Yourprogram.c
This will generate .s file. You can look at .read_only section for this string. so even you delete your structure instance, there will be no memory leak. Because you are just pointing a address which is read-only. You are not at-all allocating memory for this string.

Related

Invalid (Aborted)core dumped error while using free() in C

here's the code:
can anyone explain this issue
how can i deallocate the memory of s in main
char *get(int N)
{
char *s=malloc(10*sizeof(char));
s="hello";
return s;
}
int main()
{
char *s=get(4);
printf(s);
free(s);
}
This here:
s="hello";
Doesn't write "hello" to the allocated memory. Instead, it reassigns s to point to a read-only place where "hello" is stored. The memory you allocated with malloc is leaked, and the free(s); is invalid, because you can't free that read-only memory.
If you want to copy "hello" into s, try strcpy(s,"hello"); instead.
By doing
s="hello";
you're overwriting the returned pointer by malloc() with the pointer to the first element of the string literal "hello", which is not allocated dynamically.
Next, you are passing that pointer (to a string literal) to free(), which causes the undefined behavior.
You may want to change the assignment to
strcpy(s, "hello");
Additionally, by overwriting the originally returned pointer by malloc(), you don't have a chance to deallocate the memory - so you also cause memory leak.
You have two bugs here:
You reassign the pointer s with the reference of the string literal "hello", loosing the memory allocated by malloc
You allocate not enough space for the "hello" string. You need at least 6 characters (not 4)
A variable of type char * is a pointer (memory address) to a character. In C, it is customary to implement strings as zero-terminated character arrays and to handle strings by using variables of type char * to the first element of such an array.
That way, variables of type char * do not actually contain the strings, they merely point to them.
For this reason, the line
s="hello";
does not actually copy the contents of the string, but rather only the pointer (i.e. the memory address) of the string.
If you want to copy the actual contents of the string, you must use the function strcpy instead.
By overwriting the pointer that you use to store the address of the memory allocated by malloc, you are instead passing the address of the string literal "hello" to free. This should not be done. You must instead only pass memory addresses to free that you received from malloc.

Freeing char[] in C gives error and how do C compiler handle that char[]

Although arrays are basically pointers, freeing char[] in C gives an error.
#include <stdlib.h>
int main(void) {
char ptr[] = "Hello World";
free(ptr); // this gives error at run time
}
ERROR: nexc(4212,0x10038e3c0) malloc: * error for object 0x7fff5fbff54c: pointer being freed was not allocated
* set a breakpoint in malloc_error_break to debug
The interesting part is that, it is saying I am freeing a pointer which is not allocated.
How could this happen?
But in C++, compiler gives me a compile time error instead.
int main(void) {
char ptr[] = "Hello World";
delete ptr; // this gives error at compile time
}
like,
Cannot delete expression of type char[12]
I thought this is because of compiler handles the char[12] by allocating when the function is called and deallocating the memory when the function ends. So, I write some codes after free(ptr); before the function ends.
#include <stdlib.h>
int main(void) {
char ptr[] = "Hello World";
free(ptr); // this still gives error at run time
printf("\n");
printf("\n");
printf("\n");
printf("\n");
printf("\n");
}
This still gives error. How is this happening?
You only free what you have allocated using malloc (directly or indirectly) or related function (like realloc).
Attempting to pass a pointer not returned by malloc will lead to undefined behavior.
That you get a compiler error for delete in C++ is first and foremost because C and C++ are different languages with different rules.
And remember, an array is an array, not a pointer. Though an array can decay to a pointer to its first element in many situation (like when passing it to a function).
You only call free on dynamic memory that you've allocated using malloc, calloc &c.. Similarly, you only call delete on memory allocated with new. In your case, the C++ compiler is required to issue a diagnostic since pointer decay is not permitted to occur in this particular instance, and delete requires a pointer type.
The behaviour on attempting to call free on automatic memory is undefined.
You only need to free what was malloced.
Your ptr is not a pointer, it is an array; an automatic local (inside main()) variable. It does not need freeing and attempting to free it is a mistake.
All the static Strings will be allocated in the data section. You can't free data from this section. Threrefore, you can free only data the you have allocated with malloc (calloc / ralloc)
in C programming language, you cannot write the instruction you made for obvious reasons. First of all, it must be understood that a pointer variable is a variable like so many others with a type except that it contains only addresses, so it is called a pointer variable because it contains the address of what is in memory. A pointer is therefore an address associated with a type of data and these two elements are inseparable.
If the pointer variable contains the address of an object of the whole type, the pointed object is used to know how to interpret the bits that make up this object, as well as its size. The instruction you wrote is therefore a constant pointer to a character type stored somewhere in memory. The string is therefore probably placed in a read-only data segment and therefore you cannot modify the string or release its memory, because the pointer variable does not point to a string in a space allocated dynamically beforehand by the "malloc" or "calloc" allocation function, and that is why you have the error message.
The second error is due to a confusion of your part here too, you must understand that there is a difference between an array of characters and a pointer. In simpler terms, a pointer variable is not an array and an array is not a pointer, but access to the element is done in the same way. For an array, the characters that make up the string and end with "\0" can be changed, but the array of characters will always point to the same address in memory and the pointer can contain another address, but beware, if you allocate the memory with a pointer and then point to other pars without releasing the memory you allocated creates a memory leak.
This is the proper way of using delete ! you first have to let the compiler know that the variable ptr is dynamic by using new!
#include<iostream>
#include<new>
using namespace std;
int main(void) {
char *ptr;
try{
ptr = new char [20];
} catch(bad_alloc xa){
cout<<"error";
}
ptr= "Hello World";
cout<<ptr;
delete [] ptr;
}

What is the difference between assigning a string pointer first to allocated memory and directly to a string literal?

So my understanding is that these two block of codes are valid and do the same thing.
1.)
char *ptr = malloc(5);
ptr = "hi";
2.)
char *ptr = "hi";
I would want to know the difference between the two like if there any advantages of one over the other.
The former is a bug, and that code should never have been written.
It overwrites the pointer returned by malloc() with the address of a string literal, dropping the original pointer and leaking memory.
You must use strcpy() or some other memory-copying method to initialize newly allocated heap memory with a string.
The second just assigns the (run-time constant) address of the string literal to the pointer ptr, no characters are copied anywhere.
The first bit is a possible memory leak, the second relies on the implicit const storage class being used, and assigns the memory address of an immutable string to a pointer.
Basically:
char *ptr = malloc(5);//allocates 5 * sizeof *ptr
//then assigns the address where this block starts to ptr
//this:
ptr = "hi";//assigns position of 'h','i', '\0' in read-only mem to ptr
Now, the address you've allocated, that ptr pointed to, still is allocated. The difference is that you have no "handle" on it anymore, because ptr's value changed. There's no pointer pointing to the dynamic memory you allocated using malloc, so it's getting rather tricky to manage the memory... You probably won't be able to free it, and calling free on ptr now will result in undefined behaviour.
If you write:
char *ptr = "hi";
Then you're actually writing:
const char *ptr = "hi";
Which means you can't change the string to which ptr points:
ptr[0] = 'H';//IMBOSSIBRU
Alternatives are:
char string[] = "Hi";//copies Hi\0 to string
//or
char *ptr = malloc(5);
strcpy(ptr, "hi");//requires string.h
The difference between the two snippets above is that the first creates a stack array, the second allocates a block of memory on the heap. Stack memory is easier to manage, faster and just better in almost every way, apart from it being less abundant, and not really usable as a return value...
There is a pool of string literals for every process. Whenever you create a string literal inside your code, the literal is saved in the pool and the string's address (i.e. an address pointing somewhere to the pool) is returned. Therefore, you are creating a memory leak in your first option, because you are overwriting the address you received with malloc.
In the first case
char *ptr = malloc(5);
ptr = "hi";
There is a memory leak and later you are pointing ptr to a string literal "hi" which does require any memory from the heap (that's why there is memory leak).
But if you are allocating the memory and if you are using
strcpy (ptr, "hi");
then if you wish you can modify it
strcpy (ptr, "hello")
with one condition that you allocate sufficient memory before.
But in your case you are assigning a pointer ptr with a string literal, here you will not be able to modify it
ptr = "hello" // not valid. This will give a segmentation fault error
In your second case there is no memory leak and you are making a pointer to point to a string literal and thus it's value cannot be modified as it will be stored in read only data segment.

Is malloc-ing a char the same as referencing a char array?

I think I have got my head mostly around the difference, but if I am correct, then this should be correct also:
1.)
char *string1 = (char*) malloc(runtime_determined_number);
2.)
char string2val[runtime_determined_number];
char *string2 = &string2val;
Here I would expect string1 and string2 to be the same, is this the case?
string1 and string2 are not pointed to the same memory area
string1 is a pointer pointing to a char array allocated dynamically with malloc
string2 is a pointer pointing to a char array allocated statically
They both point to uninitialized blocks of memory of the same length. So in that respect they are the same, yes.
Note that in case 1, you are responsible for freeing the memory once you're finished. And in case 2, you can't safely return the pointer from a function as the memory will go out of scope on exit.
Using malloc you are asking the OS for memory during runtime. If malloc succeeded you are able to work with the allocated memory. You must deallocate this memory later on!
In your second part you are creating a char-array and then assign its address to a pointer. In this case the memory is taken from the stack and will be freed automatically when the array goes out of scope.
Your char*s won't be the same as they will be pointing to different locations in memory. There is aminor chance they contain the same garbage as you have not initialized them...
They are similar in that they have the same type and have at least runtime_determined_number bytes allocated for them.
They are different in that:
the first version requires an explicit free() to avoid a memory leak;
the lifetime of the two objects may or may not be the same.
Note that the second version is only valid in C99, since it makes use of a variable-length array.

Why can I assign a longer string to a pointer in C?

#include <stdio.h>
#include <stdlib.h>
int main()
{
char *ptr = malloc(sizeof(char) * 1);
ptr = "Hello World";
puts(ptr);
getchar();
}
im not a malloc() expert but isn't that code supposed to give an error since i allocated only one byte but assigned a value that contains 11 bytes to *ptr pointer ?
or does the H get stored in the place i assigned and then the rest of the string just goes in the places after it ?
You are reassigning the pointer 'ptr' to another block of memory, so you won't see any error. However, the block of memory (size 1) that you allocated is "lost" and leads to a memory leak.
When using malloc you're requesting some memory and malloc returns the first address of that memory (if it can be given). When you re-assign the pointer you're not doing anything with the memory it points to. You just change what the pointer points to.
What you're doing here is technically valid C but you're creating a memory leak because you lose the address of the malloced memory, which you must free when you're done with it.

Resources