There seems to be a fundamental misunderstanding.
malloc (sizeof (struct a) * n) allocates n elements of type struct a.
No, this is what is commonly used, as after such a call. malloc(size) allocates a memory area of size bytes. What you do with this region is entirely up to you. The only thing that matters is that you do not cross the boundaries of the allocated memory. Assuming 4 bytes of float and int and 8 bytes of double , after successful malloc(100*sizeof(float)); you can use the first 120 of 400 bytes as an array of 15 double s, and the next 120 as an array of 30 float s, then put an array of 20 char right behind it and fill in the remaining 140 bytes of 35 int if you want. This is a completely harmless defined behavior.
malloc returns a void* , which can be implicitly passed to a pointer of any type, therefore
some_type **array = malloc(100 * sizeof(data *));
excellent, it may just not be the amount of memory you wanted. In this case, this is very likely because the pointers are the same size no matter what they point to.
Most likely you will get the wrong amount of memory
data *array = malloc(n * sizeof(data*));
how did you do it. If you use the allocated memory as an array of n elements of type data , there are three possibilities
sizeof(data) < sizeof(data*) . Then your only problem is that you are losing space.sizeof(data) == sizeof(data*) . Everything is fine, with no spaces, as if you had no typo.sizeof(data) > sizeof(data*) . You will then gain access to memory, which you should not access when you touch the later elements of the array, which is undefined. Depending on different things that could work sequentially as if your code was correct, immediately crash with segfault or something in between (technically, it could behave in such a way that it could not be meaningfully placed between the two, but that would be unusual).
If you intentionally do this, knowing point 1. or 2., it applies. Bad practice, but not a mistake. If you do this unintentionally, it is a mistake, no matter which item is applied, harmless but hard to find, and 1. or 2. applied, harmful, but usually easier to detect in case 3.
In your examples. data was 4 respectively. 8 bytes (possibly) that on a 64-bit system put them in 1, respectively. 2. with a high probability, on a 32-bit system by 2, respectively. 3.
The recommended way to avoid such errors is to
type *pointer = malloc(num_elems * sizeof(*pointer));