0

I'd like to allocate memory for the 2d int ptr below, but I'm not 100% positive I've done it correctly, so any pointers (ha ha) on that would be great. Is the way I free the array and its indexes in the for loop correct? Also, what is the difference between the first malloc and the second malloc: (int *) and (int)?

int **array = NULL;
int mem_size = 0;
int i = 0, j = 0;

// leaving out how mem_size is calculated, but it can vary

array = malloc(sizeof(int *) * mem_size);
if (array == NULL) {
    // some error message
    return;
}
for (i = 0; i < mem_size; i++) {
    array[i] = malloc(sizeof(int) * 2);
    if (!(array[i])) {
        // some error message
        for (j = 0; j < i; j++)
            free(array[j]);
        free (array);
        return;
    }
}

This is only a section of the code I wrote. At the end, I am freeing the array:

for (i = 0; i < mem_size; i++)
   free(array[i]);

free(array);
Aelyn
  • 37
  • 1
  • 7

3 Answers3

2

It is just a compile time constant - size of pointer in first case, size of int in second. It may vary between systems (e.g. if compiling for 32bit systems, pointer would be 4 bytes, while on 64bit systems it is 8 bytes).

In case any of the mallocs fail in the for loop, should I be freeing the array there

You should be freeing everything you've allocated so far - each array[0..(i-1)] and array itself.

malloc(sizeof(int *) * mem_size)

Allocates memory for array of mem_size pointers.

malloc(sizeof(int) * 2);

Allocates memory for 2 ints.

Also you should consider allocating ordinary 1D array and just calculating index when you want to access it.

keltar
  • 17,711
  • 2
  • 37
  • 42
  • Yes, but in that case you can't use your ordinary cleanup code, because it will try to free each element - while not all of them are allocated. Simpler way would be initialising entire `array` to NULL pointers - because `free(NULL)` is defined as no-operation, it would be safe to call it for every element. – keltar Jun 23 '14 at 10:41
  • Sorry for the comments that were deleted, still getting used to using stackoverflow. I updated the for loop to free the array/indexes. Would this be a proper way to free them? – Aelyn Jun 23 '14 at 11:29
  • `free (effect_data);` should be performed only once, not on every loop iteration. Move it outside the loop. Aside from that, it is correct (well, variable names are inconsistent - it is `array` somewhere, then `effect_data`. I hope it is because of copy-paste problems and actual code don't have this problem) – keltar Jun 23 '14 at 11:34
  • "32 bit system" and "64 bit system" more often refers to the native `int` width. Number of processors have a pointer width different from `int` width; both greater and smaller exist. – chux - Reinstate Monica Jun 23 '14 at 16:52
  • 1
    @chux what? sizeof(int)==4 on both 32 and 64 linux/gcc (or clang). sizeof(void*), however, is 4 and 8. As I recall, it is the same on windows. – keltar Jun 23 '14 at 17:13
  • @chux or were you talking about word size? I'm almost sure it have to be the same as pointer size, though. – keltar Jun 23 '14 at 17:19
  • @keltar See [word size](http://en.wikipedia.org/wiki/Word_(computer_architecture)#Table_of_word_sizes). Also, modern embedded processors may have `int` sizes of 1 (non C compliant), 2, 4 and differing pointer size. Early DOS/Windows had 16 bit `int` and 32 _or_ 16 bit pointers depending on data type and compilation options used. The main point is that pointer size is independent of `int` size and the C spec certainly allowed in the past and for future growth using various sizes. Robust code does not depend on `sizeof(int) == sizeof (int*)` – chux - Reinstate Monica Jun 23 '14 at 17:37
0

sizeof(int) is equal to 4 bytes

sizeof(int *) is also equal to 4 bytes

... since a pointer only holds 4 bytes.

When you call malloc(int) and malloc(int *) - in both cases, the memory manager allocates 4 bytes on the heap and returns a pointer to the allocated memory.

Since you are going to store that address into the array (which is a double pointer and can thus only hold the address of another pointer), the following is illegal:

array = malloc(sizeof(int *) * mem_size); --- illegal to use

You may implement what you want in the following way: int *ptr = NULL;

int **p_ptr = NULL;

ptr=(int *)malloc(sizeof(int *));

p_ptr = &ptr;

**p_ptr = 100 or any other value; now, whatever changes you made will be reflected in the allocated size of 4 bytes

lnjuanj
  • 1,744
  • 1
  • 12
  • 23
  • 2
    While I agree that correct type isn't required here and only serves a readability, statement "sizeof(int) is equal to N" is at least "isn't always true", especially when you don't say what architecture, OS and compiler you're talking about. – keltar Jun 23 '14 at 10:47
  • @keltar, yes you're right, I gave that answer in perspective of GCC compiler – rangineni balu Jun 23 '14 at 10:55
  • 1
    gcc on my 64bit linux gives pointer size of 8 (as it should be). Oh, and just realised that your statement about "illegal use" (silly me, need to read more carefully before commenting) is wrong - `malloc` returns `void*`, it is automatically casted to any pointer type. – keltar Jun 23 '14 at 11:01
  • In C++ the cast is necessary, but not in C. – Aelyn Jun 23 '14 at 11:10
  • 1
    wrong. A pointer is most probably 8 bytes on 64-bit system. And it may have other sizes on other systems – phuclv Jun 23 '14 at 12:07
  • 1
    gcc isn't only an 32-bit x86 compiler. It supports lots of architectures and operating systems, including 8/16-bit embedded systems where pointers inherently aren't 4/8 bytes. And [don't cast the result of malloc in c](http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc) either – phuclv Jun 23 '14 at 12:10
  • "sizeof(int) is equal to 4 bytes" is _not_ supported by the C specification. – chux - Reinstate Monica Jun 23 '14 at 16:58
  • @keltar i am using 64bit system, in my system i got 4 bytes. still i stick with that illegal use. How do you justify that storing addressing of memory in a double pointer - you can't do that! in c you need to do type casting - it will give you warning not errors but still it is a unreliable coding, i think its better u study before you post. – rangineni balu Jun 24 '14 at 04:43
  • @ranginenibalu if you have 64bit linux and gcc, and compiling program as 64bit ELF, then sizeof(void*) = 8; 4 bytes simply can't address more than 4 Gb of memory; int - yes, 4 bytes, but some systems have only 2. As for casting - no, `void **a = malloc(N);` is perfectly valid in C. In C++, void* isn't casted automatically, in that language you have to cast manually. And your 'example' of "double pointer" (hate this name) just can't work with array of pointers. If I may, I suggest you follow your own suggestion [sorry, can't resist sarcasm]. – keltar Jun 24 '14 at 05:04
0

Each one of them is determined according to a different characteristic within your platform.


The size of int is determined by the compiler, which is typically designated for a specific processor.

So it is effectively derived from the CPU architecture.

It is usually 4 bytes, but may be 2 bytes on some platforms.


The size of int* (or any other pointer) is determined by the size of the virtual memory address space.

So it is effectively derived from the MMU architecture.

It is 4 bytes on 32-bit systems and 8 bytes on 64-bit systems.

barak manos
  • 29,648
  • 10
  • 62
  • 114