C memory allocation

I have a question about memory allocation order. In the following code, I highlight 4 lines in a loop. But when I print the addresses, they do not seem to stand out one after another ... Am I doing something wrong or is this some kind of protective mechanism implemented by the OS to prevent possible buffer overruns? (I am using Windows Vista).

Thanks.

char **stringArr; int size=4, i; stringArr=(char**)malloc(size*sizeof(char*)); for (i=0; i<size; i++) stringArr[i]=(char*)malloc(10*sizeof(char)); strcpy(stringArr[0], "abcdefgh"); strcpy(stringArr[1], "good-luck"); strcpy(stringArr[2], "mully"); strcpy(stringArr[3], "stam"); for (i=0; i<size; i++) { printf("%s\n", stringArr[i]); printf("%d %u\n\n", &(stringArr[i]), stringArr[i]); } 

Output:

ABCDEFGH 9650064 9650128

good luck 9650068 9638624

Mullahs 9650072 9638680

stam 9650076 9638736

+6
c malloc windows-vista buffer-overflow
source share
7 answers

Usually, when you request memory via malloc() , the C runtime library will round up your request size to a certain minimum size. This ensures that:

  • A runtime library has room for its accounting information.
  • it is more efficient for the runtime library to manage allocated blocks that are all multiples of a certain size (for example, 16 bytes).

However, these are implementation details, and you cannot really rely on any specific malloc() behavior.

+7
source share

But when I type the addresses, they don't seem to stand out one by one ...

So?

Am I doing something wrong or is it some kind of protective mechanism implemented by the OS to prevent possible buffer overflows?

Probably not.

Just out of interest, what addresses do you get?

+4
source share

You should not depend on any particular order or range of values ​​returned by malloc. He behaves mysteriously and unpredictably.

+4
source share

It is usually reasonable to expect a series of chronological allocations to result in memory addresses that are somehow related, but as others have pointed out, this is certainly not a requirement of the heap manager. In this particular case, however, it is possible that you see the results of a low fragmentation heap . Windows stores lists of small pieces of memory that can quickly satisfy a request. They can be in any order.

+4
source share

You cannot depend on malloc to provide you with adjacent addresses. It completely depends on the implementation and, apparently, the current state of the heap; some implementations may, many will not.

If you want the addresses to be contiguous, select one large block of memory and set up pointers to point to different areas within it.

+3
source share

As already mentioned, there is no standard to indicate in which order the memory blocks allocated by malloc () should be located in memory. For example, freed blocks can be scattered throughout the heap and can be reused in any order.

But even if blocks occur one after another, they most likely do not form a continuous block. To reduce fragmentation, the heap manager only allocates blocks of a certain size, for example, the power of two (64, 128, 256, 512, etc.). So, if you reserve 10 bytes for a string, then maybe 22 or 54 unused bytes after that.

Memory overhead is another reason why dynamic memory allocation is not recommended if it is really necessary. It is much easier and safer to use a static array.

+2
source share

Since you are interested in knowing the addresses returned by malloc() , you need to make sure that you type them correctly. Correctly, I mean that for printing addresses you should use the correct format specifier for printf() . Why are you using "%u" for one and "%d" for the other?

You must use "%p" to print pointers. This is also one of the rare cases when you need cast in C: because printf() is a variational function, the compiler cannot say that the pointers you pass as an argument must be of type void * or not.

In addition, you should not specify the return value of malloc() .

Fixed above, program:

 #include <stdio.h> #include <stdlib.h> #include <string.h> int main(void) { char **stringArr; int size=4, i; stringArr = malloc(size * sizeof *stringArr); for (i=0; i < size; i++) stringArr[i] = malloc(10 * sizeof *stringArr[i]); strcpy(stringArr[0], "abcdefgh"); strcpy(stringArr[1], "good-luck"); strcpy(stringArr[2], "mully"); strcpy(stringArr[3], "stam"); for (i=0; i<size; i++) { printf("%s\n", stringArr[i]); printf("%p %p\n", (void *)(&stringArr[i]), (void *)(stringArr[i])); } return 0; } 

and I get the following output at startup:

 abcdefgh 0x100100080 0x1001000a0 good-luck 0x100100088 0x1001000b0 mully 0x100100090 0x1001000c0 stam 0x100100098 0x1001000d0 

On my computer, char ** pointers are 8 bytes long, so &stringArr[i+1] is 8 bytes longer than &stringArr[i] . This is guaranteed by the standard: if you malloc() some space, this space is contiguous. You have allocated space for 4 pointers, and the addresses of these four pointers are located next to each other. You can see this more clearly by doing:

 printf("%d\n", (int)(&stringArr[1] - &stringArr[0])); 

This should print 1.

About the subsequent malloc() s, since each stringArr[i] obtained from a separate malloc() , the implementation can freely assign them any suitable addresses. In my implementation, with this particular launch, all addresses are divided by 0x10 bytes.

For your implementation, it seems that char ** pointers are 4 bytes long.

About your individual string addresses, it looks like malloc() is doing some sort of randomization (which is allowed to be done).

+1
source share