0

When the array type is a "void *", then it can be allocated by:

void **void_array;

void_array = malloc(sizeof(void*) * 1);

But, if the array type is a struct Hello *, then what should be used in the sizeof():

typedef struct Hello {
    int world;
} Hello;

Hello **hello_array;

/** allocated by using the struct name */
hello_array = malloc(sizeof(Hello) * 1);

/** or? */

/** allocated by using the struct name with pointer */
hello_array = malloc(sizeof(Hello*) * 1);

Which one is correct? sizeof(Hello) or sizeof(Hello*)? Or are both correct?

6
  • 2
    Looks like Hello **hello_array is supposed to point to an array of pointers. I.e. each element is a Hello* and therefore sizeof(Hello*) is correct. BTW - why do you multiply by 1 ? if you want only 1 element simply keep the sizeof (or don't use an array at all..). Commented Oct 2 at 10:15
  • If only sizeof(Hello*) can be used for allocating the array, then is sizeof(Hello*) = sizeof(void *)? As they are both are pointers, the pointer * type length should be the same for any types in c language. Can I simply use hello_array = malloc(sizeof(void*) * 1);? Commented Oct 2 at 10:21
  • 1
    "Can I simply use hello_array = malloc(sizeof(void*) * 1);?" Only if the pointers really are the same size, which is true on most architectures, but should not be assumed for portability. On some architectures, function pointers are not the same size as object pointers, for example. Commented Oct 2 at 11:57
  • Re "is sizeof(Hello*) = sizeof(void *)", This probably happens to be the case in the environment you are using, but it's not guaranteed. Pointers of different type do not have to be the same size, and have not always been the same size historically. void* will be at least as large as any non-function pointer, but it could be larger than Hello*. Commented Oct 2 at 16:20
  • @stackbiz "array type is a void *" --> note that void * is a pointer, not an array nor an array type. Array are not pointers. Pointers are not arrays. Commented Oct 2 at 17:48

3 Answers 3

7

The easy way to always get this right is malloc(sizeof *hello_array). In other words, use the expression we're assigning to, dereference that to get the size of the object it expects to see there.

Sign up to request clarification or add additional context in comments.

4 Comments

I think this is the best approach, +1 (although in order to technically answer the question you could mention that of the 2 options, only sizeof(Hello*) is correct).
What's the difference between hello_array = malloc(sizeof(Hello*)) and hello_array = malloc(sizeof *hello_array)?
The latter is more clearly right (you don't need to look at anything else in the program), and it remains right if you change the type to which hello_array points. But in the context of your current declarations, both those alternatives reserve the same amount of memory and assign hello_array to point to that.
The 2nd stays valid if you change the type of elements.
5

sizeof has a feature that it will know the type of an expression. So, if p is an int, then sizeof p will produce the number of bytes in an int. (Note that sizeof is an operator, not a function, so you do not need parentheses for its operand here.)

If p is a pointer to an int, then the type of *p is int. Then sizeof *p is the size of an int. You can use this whenever you allocate memory for a single object and assign it to a pointer to that type of object:

p = malloc(sizeof *p);

You can also use it when declaring and initializing a pointer:

int *p = malloc(sizeof *p);

(Even though p is not initialized when the value of malloc(sizeof *p) is evaluated, this works because the value of p is not used in the expression. Only its type is used.)

To allocate space for multiple objects of the same type, simply multiply the size:

int *p = malloc(3 * sizeof *p);

This works for any type of object, including pointers to pointers. This code allocates space for 3 pointers to int:

int **p = malloc(3 * sizeof *p);

The above saves you the trouble of figuring out the syntax for types. However, if you wish to do it yourself, there are two rules:

  • The pointer to an object type has one more pointer level than the object type. When assigning to an int *, the size of an int should be used. When assigning to an int **, the size of an int * should be used.
  • When using types in expressions, you do need parentheses around them. This is not because sizeof is a function but because the grammar needs help distinguishing types:
int **p = malloc(3 * sizeof (int *));

Hello **hello_array; declares hello_array to be a pointer to a pointer to hello_array. This can act as a two-dimensional matrix of Hello objects, not a one-dimensional array of Hello objects.

Since hello_array points to pointers to Hello, you need to allocate space for pointers:

hello_array = malloc(n * sizeof (Hello *));
hello_array = malloc(n * sizeof *hello_array); // Same result.

When allocating memory for the Hello objects, which you will point to with *hello_array or hello_array[i], you need to allocate space for Hello objects:

hello_array[i] = malloc(m * sizeof (Hello));
hello_array[i] = malloc(m * sizeof *hello_array[i]);
// Simple rule: Always use `sizeof *x`, where `x` is the pointer being assigned to.

2 Comments

I think I will accept this as answer because this explains everything in detail. But I don't understand the usage of int *p = malloc(3 * sizeof *p);, I think * + variable_name should only be used to declare a SINGLE object pointer point to only ONE object, it should only used as int *p = malloc(sizeof *p);? When I declare an array pointer, I always use int **p or int *p[array_size] but not int *p. Is the int *p also an array declaration?
A pointer p may point to one object. However, you may use pointer arithmetic to change what it points to. p+0 points to the same object. p+1 points to the next object (of the same type). p+2 points to the object beyond that. Applying * produces the element pointed to. So *p or *(p+0) is the object pointed to. *(p+1) is the next object. p[i] is an abbreviation for *(p+i). So p[0] is the object pointed to, p[1] is the object after that, p[2] is the object next object, and so on. (Pointer arithmetic is defined only within arrays.)
3

The correct one is:

hello_array = malloc(sizeof(Hello*) * 1);

This is because hello_array is a pointer of type Hello* (a pointer to a pointer of type Hello). So the allocated memory is allocated for a pointer. Therefore, you need to allocate memory for the pointer to Hello, not for the Hello struct itself.

This is based on your question. If you intended to allocate memory for an array of type Hello then you should have applied:

Hello *hello_array = malloc(sizeof(Hello) * 1);

2 Comments

I think Hello *hello_array is not an array, is it just a pointer in Hello *hello_array = malloc(sizeof(Hello) * 1);?
it is a pointer pointing to a Hello object. This line allocates the memory for 1 Hello object, which you'd call an array of size 1 in this case. But i'm just using your own variable names here. Maybe look a bit more into pointers because I feel you miss a bit of basics here.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.