I don't really understand why method 1 works but not method 2. I don't really see why it works for characters and not an int.
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
/// WORK (METHODE 1)
char **string_array = malloc(sizeof(char **) * 10);
string_array[0] = "Hi there";
printf("%s\n", string_array[0]); /// -> Hi there
/// DOES NOT WORK (METHODE 2)
int **int_matrix = malloc(sizeof(int **) * 10);
int_matrix[0][0] = 1; // -> Segmentation fault
/// WORK (METHODE 3)
int **int_matrix2 = malloc(sizeof(int *));
for (int i = 0; i < 10; i )
{
int_matrix2[i] = malloc(sizeof(int));
}
int_matrix2[0][0] = 42;
printf("%d\n", int_matrix2[0][0]); // -> 42
}
CodePudding user response:
In terms of the types, you want to allocate memory for the type "one level up" from the pointer you're assigning it to. For example, an int
pointer (an int*
), points to one or more int
s. That means, when you allocate space for it, you should allocate based on the int
type:
#define NUM_INTS 10
...
int* intPtr = malloc(NUM_INTS * sizeof(int));
// ^^ // we want ints, so allocate for sizeof(int)
In one of your cases, you have a double int
pointer (an int**
). This must point to one or more int
pointers (int*
), so that's the type you need to allocate space for:
#define NUM_INT_PTRS 5
...
int** myDblIntPtr = malloc(NUM_INT_PTRS * sizeof(int*));
// ^^ "one level up" from int** is int*
However, there's an even better way to do this. You can specify the size of your object it points to rather than a type:
int* intPtr = malloc(NUM_INTS * sizeof(*intPtr));
Here, intPtr
is an int*
type, and the object it points to is an int
, and that's exactly what *intPtr
gives us. This has the added benefit of less maintenance. Pretend some time down the line, int* intPtr
changes to int** intPtr
. For the old way of doing things, you'd have to change code in two places:
int** intPtr = malloc(NUM_INTS * sizeof(int*));
// ^^ here ^^ and here
However, with the 2nd way, you only need to change the declaration:
int** intPtr = malloc(NUM_INTS * sizeof(*intPtr));
// ^^ still changed here ^^ nothing to change here
With the change of declaration from int*
to int*
, *intPtr
also changed "automatically", from int
to int*
. This means that the paradigm:
T* myPtr = malloc(NUM_ITEMS * sizeof(*myPtr));
is preferred, since *myPtr
will always refer to the correct object we need to size for the correct amount of memory, no matter what type T
is.
CodePudding user response:
The method 1 works only becuse you assign the char *
element of the array string_array
with the reference of the string literal `"Hi there". String literal is simply a char array.
Try: string_array[0][0] = 'a';
and it will fail as well as you will dereference not initialized pointer.
Same happens in method 2
.
Method 3. You allocate the memory for one int
value and store the reference to it in the [0] element of the array. As the pointer references the valid object you can derefence it (int_matrix2[0][0] = 42;
)