2

I'm relatively new to C, and I've been messing around with pointers to an int array to help solidify my understanding. Here is some code I typed up that confused me:

#include <stdio.h>

int main(int argc, char **argv)
{
    int sizeOfInt = sizeof (int);
    printf("The size of an int is %d \n",sizeOfInt);

    int StaticArray[10];
    int staticSize = sizeof(StaticArray);
    printf("The size of the static array with 10 elements, all unused, is %d\n\n", staticSize);


    int *DynamicArray = malloc( 10  * sizeof(int) );
    printf("The dynamic array *DynamicArray has been allocated 10 int elements worth of memory\n");
    int sizeOfDynamic = sizeof(DynamicArray);
    printf("Since none of those elements have been assigned an int yet, the array currently takes up %d memory\n\n", sizeOfDynamic);

    *DynamicArray = 10;
    printf("The first element, at address %x , is %d \n",DynamicArray, *DynamicArray); //DynamicArray refers to address of start of array
    printf("The address of the pointer *DynamicArray is %x \n",&DynamicArray); //&DynamicArray refers to address of pointer

    DynamicArray[1] = 20;
    printf("The second element, at address %x , is %d \n",DynamicArray, DynamicArray[1]); //DynamicArray refers to address of start of array

    sizeOfDynamic = sizeof(DynamicArray);
    printf("The size of the array after assigning 2 int elements is now %d", sizeOfDynamic);

    //Free unused memory
    free(DynamicArray);
    return 0;
}

When I run this program, I get the following output:

The size of an int is 4
The size of the static array with 10 elements, all unused, is 40

The dynamic array *DynamicArray has been allocated 10 int elements worth of memory

Since none of those elements have been assigned an int yet, the array currently takes up 8 memory

The first element, at address 1f69b0 , is 10

The address of the pointer *DynamicArray is 62fe08
The second element, at address 1f69b0 , is 20

The size of the array after assigning 2 int elements is now 8
  1. Why is it that before assigning any elements to *DynamicArray, its size is 8?

  2. Since *DynamicArray had a size of 8 to begin with, how does it still only have a size of 8 after assigning two elements to it?

  3. If I allocated 10 int elements worth of memory for *DynamicArray, it is initially as wasteful of memory as a static array of 10 elements until I call free(DynamicArray), correct?

Thank you for any clarification!

Govind Parmar
  • 20,656
  • 7
  • 53
  • 85
Quabs
  • 51
  • 9
  • 1
    "Here is some code I typed up that confused me:" --> It is surprising someone who can write this code would have these questions. – chux - Reinstate Monica Jun 17 '17 at 16:09
  • Solution: pointer are not array. – Stargateur Jun 17 '17 at 16:10
  • 1
    "how does it (DynamicArray) still only have a size of 8" `DynamicArray` is a pointer. Its size does not change. – chux - Reinstate Monica Jun 17 '17 at 16:10
  • 3
    Note that `sizeof(DynamicArray);` tells you nothing about the memory you allocated. It is the size of the pointer, whether or not it is initialised. – Weather Vane Jun 17 '17 at 16:10
  • 1
    Possible duplicate of [How to find the 'sizeof' (a pointer pointing to an array)?](https://stackoverflow.com/questions/492384/how-to-find-the-sizeof-a-pointer-pointing-to-an-array) – Stargateur Jun 17 '17 at 16:14
  • Once you have allocated memory and gotten the pointer to that memory, there is no way of getting the size of that memory afterwards just from the pointer. You as a programmer have to make sure to keep in mind (or memory) for how many elements you originally allocated the memory for. – Patrick Günther Jun 17 '17 at 16:17

3 Answers3

1

I was right where you a few months ago.

  1. DynamicArray itself is just a "container" (roll with it...) for a memory address, which has a certain size dependent upon platform. It points to a memory address, and whatever values reside at that memory address do not change the size of its address. If you put a fat person in a house, it does not change the houses address.

  2. Same answer as 1?

  3. "Wasteful" maybe not the right phrase, but it takes up the same amount of memory. Difference is the one allocated with malloc(...) is on the heap, and outlives the scope of the function it was called in, until explicitly free()'d.


sizeof(DynamicArray[i]) = sizeof(int), whether assigned a value or not (assuming i is within bound). sizeof(DynamicArray) = sizeof(int*)

You are compiling to 64-bit it seems. Change to 32-bit and watch sizeof DynamicArray get cut in half. That might help you visualize?

Stargateur
  • 24,473
  • 8
  • 65
  • 91
DWR
  • 888
  • 1
  • 8
  • 15
  • "sizeof(DynamicArray[i]) = sizeof(int), whether assigned a value or not (assuming i is within bound). " Thanks, this also provides some clarification. But then, since sizeof(DynamicArray[i]) is the same regardless of whether there's anything assigned to it, what is the advantage of a Dynamic Array? Is the only advantage the fact that I can call free(DynamicArray) to get that memory back throughout the rest of the program? – Quabs Jun 17 '17 at 16:29
  • @Quabs The main advantage of `malloc` and `free` is that the lifetime of the array is not limited to where the array was declared. You can pass the pointer out of the function, etc. – aschepler Jun 17 '17 at 16:32
  • Allocated on stack, versus allocated on heap. That is outside the scope of the original question but you are in for a fun ride! – DWR Jun 17 '17 at 16:32
  • @aschepler & David Rogers Ahh I see, thank you! I'm so unfamiliar with memory management in C still that I'm always forgetting stuff like this. – Quabs Jun 17 '17 at 16:46
0

Pointers and arrays are not the same thing in C. If you use a function like malloc to dynamically allocate an array to a pointer variable, it is your job as the programmer to ensure that assignment to the array you allocated does not exceed its boundaries.

Technically, this is also the case with stack-allocated arrays of fixed length, but sizeof will return the actual number of bytes that were allocated in that case.

What you've stumbled upon is actually one of the reasons that strings in C need to be null-terminated - a string of type char * does not have any information about its length, so the only way for library functions to know when they're done processing a string is by searching for a null terminator. For example, the library function strcat, which appends two strings, is usually implemented like so:

void strcat(char *dest, char *src)
{
     while(*dest != '\0') *dest++;
     while(*src != '\0') *dest++ = *src++;
}

The check for the null is required because there is no information about how long the string actually is in either dest or src - if you were to try to determine the length of dest using sizeof it would fail because you'd get the size of a pointer on your architecture.

Govind Parmar
  • 20,656
  • 7
  • 53
  • 85
  • thank you, this answer cleared things up for me some I believe. So when I called sizeof(DynamicArray) twice throughout that program, it was just returning the size of the actual pointer itself both times, and had nothing to do with the size of the actual contents of that array, correct? Also, since only character arrays are null-terminated, when using an int array I need to keep track of how much space I have manually, correct? (ie there's no way to "null terminate" an array of ints) – Quabs Jun 17 '17 at 16:23
  • "so the only way", what this should be the only way ? – Stargateur Jun 17 '17 at 16:23
  • @Stargateur I'm not sure what you're asking me – Govind Parmar Jun 17 '17 at 16:24
  • @GovindParmar "library functions", could take the size as argument. – Stargateur Jun 17 '17 at 16:25
  • @Stargateur Yes, but they don't, like in the case of `strcat` and many other standard string functions – Govind Parmar Jun 17 '17 at 16:26
  • @GovindParmar My point is there are not only one way to handle this problem. – Stargateur Jun 17 '17 at 16:27
  • @Stargateur You're right that you can write a function that takes a string length as an argument, but none of the *standard library functions* in `` (`strlen`, `strcat`, `strcpy`, `strlwr`, `strupr`, `strcmp`) take the length of the string as an argument. – Govind Parmar Jun 17 '17 at 16:31
  • 1
    @Quabs Actually, you can null terminate an array of ints, if you prefer. This may be less efficient than also passing an explicit size, since other code would need to search for the end. And it requires some "sentinel" value like 0, -1, or MIN_INT which you know can't be in the actual data. – aschepler Jun 17 '17 at 16:34
  • @aschepler This makes sense, thanks for the response! So in general, when I'm using malloc for an array of a type other than char, its likely best to manually keep track of the amount of elements the array can hold? Like int *arrayMax5 = malloc(5 * sizeof(int)); or int *array1 = malloc(10 * sizeof(int)); int sizeOfArray1 = 10; – Quabs Jun 17 '17 at 16:49
0

Why is it that before assigning any elements to *DynamicArray, its size is 8?

And

Since *DynamicArray had a size of 8 to begin with, how does it still only have a size of 8 after assigning two elements to it?

You are doing sizeof(DynamicArray) which will return size of integer pointer and you are running this program on 64-bit machine where pointer will of of 8 bytes. Try following

  1. Run above program on 32-bit machine (32-bit OS)

  2. Run above program under MS-DOS / Turbo C++ (16-bit environment)

size is 4 and 2 bytes respectively.

Pointer size is depended on the environment you are running your program in.

If I allocated 10 int elements worth of memory for *DynamicArray, it is initially as wasteful of memory as a static array of 10 elements until I call free(DynamicArray), correct?

Yes and No. All the dynamic allocation is done on heap space and managed by different routine than than of stack space. So technically, it is as wasteful as array of ten elements. But recommended if you really are going to use 10 elements of space than doing in chunk - lets say allocate 5 first and then reallocate extra 5.

bhushan23
  • 481
  • 1
  • 4
  • 13
  • FWIW, the heap allocated memory will likely contain a heap management header and trailer before and after the allocated memory which the stack allocated memory will not. – pat Jun 17 '17 at 17:20
  • Right. and heap allocation is more complex and also costly in terms of time – bhushan23 Jun 17 '17 at 17:22