سؤال

I have made this little code:

void  *toto = malloc(8 * sizeof(char *) * 8);
char  **tata = (char **)toto;
tata[5][5] = 'a'

But I have a segmentation fault. How can I convert my void * to a char ** ?

هل كانت مفيدة؟

المحلول

The malloc call is allocating space for 64 pointers of uninitialized memory. Then, you are using tata as a double indirection pointer. That's it:

  • tata points to the start of the 64 pointers.
  • tata[5] is the sixth element of the mallocd block, and since tata has type char**, tata[5] has type char*: a pointer with garbage.
  • tata[5][5] is the sixth element pointed from the start of tata[5]. But since tata[5] is garbage, tata[5][5] is a random element in your memory space.

نصائح أخرى

Yes, it is definitely possible. But you'll have to do more.

You have an array of voids named toto:

void *toto = malloc(8 * sizeof(char *) * 8);

In other words - toto is a pointer to a piece of memory containing 8 * sizeof(char *) * 8 voids - you've probably thought that because computation suggests it is an array of pointers, the compiler will figure it itself. It won't - what a compiler sees is something like this:

void *toto = malloc(64);

therefore you'll end up with a 1-dimensional "flat" array where each element is a void.

Now you cast it:

char  **tata = (char **)toto;

and it's all good so far. Now you have tata which points to an array of pointers to char arrays which is not initialized. The type of tata[5] is *char.

So when you do:

tata[5][5] = 'a';

you're:

  1. accessing that array of pointers (tata) - ok
  2. accessing 6th (indexing from 0) pointer tata[5] - ok
  3. but tata[5] is not initialized and contains either NULL or some garbage
  4. acessing 6th element of *tata[5] - SEGFAULT, because it's not valid pointer

What you must do is:

  • initialize toto to how many "rows" you need in resulting matrix
  • manually create all those end arrays yourself

So it could look like this:

void *toto = malloc(8 * sizeof(char *)); /* assuming 8 rows */
char **tata = (char **)toto;
int i;
for (i = 0; i < 8; i++) {
  tata[i] = (char*)malloc(8 * sizeof(char)); /* assuming 8 columns */
}
tata[5][5] = 'a'; /* all is well now */

Which would compile and run without SEGFAULT.

I also suggest doing the cast before malloc and using constants for numbers of rows and columns, which will give us this:

int num_rows = 8;
int num_cols = 8;
char **tata = (char**)malloc(num_rows * sizeof(char*));
int i;
for (i = 0; i < num_rows; i++) {
  tata[i] = (char*)malloc(num_cols * sizeof(char));
}
tata[5][5] = 'a';

It is possible to cast void * to any pointer type. Indeed, if it weren't you couldn't use malloc to allocate very well, since its return value is of type void *.

Of course the area of memory pointed to by the void * must still be valid for its use, i.e., large enough and aligned correctly. (In case of malloc the returned memory is correctly aligned for “any use”, at least as far a standard C is concerned.)

The bug in your code is here:

tata[5][5] = 'a'

You are dereferencing the 6th pointer to char * counting from the start of malloced block, which is uninitialised.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top