2

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!

Community
  • 1
  • 1
Nobilis
  • 7,310
  • 1
  • 33
  • 67
  • Per the C standard you are not supposed to know where things are. Automatic variable management happens... automatically. Dynamically allocated things with `malloc()` and the co are to be `free()'d`. You get valid pointers if you use them correctly and that's enough. Why would you want to know where stuff is? – Alexey Frunze Oct 18 '12 at 09:25
  • 3
    @AlexeyFrunze This is not even remotely a duplicate of that, and your previous comment completely fails to grasp or address the OP's misconceptions. – Jim Balter Oct 18 '12 at 09:32
  • 1
    @AlexeyFrunze When you do programming, you will eventually run into something called debugging. It is a form of troubleshooting, using a particular program called debugger, designated to run your program in controlled forms. When debugging you will need to look for specific, common bugs such as dynamic memory leaks, stack overflow, runaway code caused by incorrect pointer addresses, array out of bounds access... and so on. If you don't know where the variables are allocated in memory, you cannot find these bugs using a debugger. You'll notice this when you try one out. – Lundin Oct 18 '12 at 09:35
  • My bad, sorry. I do use debuggers myself, no problem with that. – Alexey Frunze Oct 18 '12 at 09:41

6 Answers6

6

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.

hmjd
  • 120,187
  • 20
  • 207
  • 252
  • Just to check if I've got it correctly, say that `ptr->s` was user input from the command line, in order not to run into any problems with the input size I would need to also allocate memory for it, correct? – Nobilis Oct 18 '12 at 10:39
  • 1
    @Nobilis, correct. You would also need to ensure when reading the user input you do not overrun the buffer allocated to `ptr->s`. – hmjd Oct 18 '12 at 10:40
4

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().

Mr.C64
  • 41,637
  • 14
  • 86
  • 162
4

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).

P.P
  • 117,907
  • 20
  • 175
  • 238
2

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.

Lundin
  • 195,001
  • 40
  • 254
  • 396
2

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).

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
2
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.

Jeyaram
  • 9,158
  • 7
  • 41
  • 63