-2

As far as I've understood this far array[1] and array+1 are practically two ways of writing the same thing. However I've been looking at void pointers and arrays recently and made this program to test my understanding of it.

#include <stdio.h>
#include <stdlib.h>

int main(void){
    void** data;
    data = malloc(sizeof(int)*2);
    *((int*)data) = 5;
    *((int*)(data+1)) = 10;
    printf("%d\n", *((int*)data));
    printf("%d\n", *((int*)(data+1)));
    free(data);
    return 0;
}

That is the version of the program that works, for some reason however this version doesn't

#include <stdio.h>
#include <stdlib.h>

int main(void){
    void** data;
    data = malloc(sizeof(int)*2);
    *((int*)data[0]) = 5;
    *((int*)data[1]) = 10;
    printf("%d\n", *((int*)data));
    printf("%d\n", *((int*)data1]));
    free(data);
    return 0;
}

I'm not exactly getting compiler errors but program simply stops running, I've compiled this on a win 10 machine using gcc with the following flags -pedantic-errors -Wall and like i said before, the program compiles but when run I get the classic Program.exe has stopped working error message and so far I really can't think of a single reason why one of those would work and the other wouldn't.

zee
  • 2,933
  • 2
  • 16
  • 28
  • 7
    No: `array[1]` is the same as `*(a + 1)` — the `*` makes all the difference. – Jonathan Leffler Feb 27 '17 at 07:38
  • 2
    In your second example, you have: `printf("%d\n", *((int*)data1]));` — there's a missing `[`. – Jonathan Leffler Feb 27 '17 at 07:38
  • Why are you using void pointers? – Ed Heal Feb 27 '17 at 07:39
  • 3
    Do you realize `data = malloc(sizeof(int)*2);` is very wrong? – Sourav Ghosh Feb 27 '17 at 07:40
  • 3
    In your first listing, the expression `data` and `data+1` calculates the first and second `void*` in a sequence; a sequence that doesn't even *exist*, since you allocated two `int`, not two `void*`. You later take those phantom `void**` and dereference them to nowhere. Your first code does **not** "work". If it *appears* to, that's unfortunate, because you would have been better off *not* being lulled into a false sense of correctness. – WhozCraig Feb 27 '17 at 07:40
  • What's the point of using a double pointer: `void**`? – alk Feb 27 '17 at 07:45
  • [Here's a nice valgrind dump](http://pastebin.com/dYLKdSaP) of your first code **not** "work"ing. – WhozCraig Feb 27 '17 at 07:47
  • @M.M Well, sir, we all know the danger involved. :) – Sourav Ghosh Feb 27 '17 at 07:51
  • @jonathanleffler that second part with the printf was a typo sorry about that. I realize my implementation of this is wrong now, i just didn't fully understand void pointers (and some aspects of normal pointers). – zee Feb 27 '17 at 16:47

3 Answers3

2

data+1 is not valid C. You cannot do pointer arithmetic on void pointers, since that wouldn't make any sense.

So it would seem that you are using gcc in non-standard crap mode (default setting), which translates void pointer arithmetic to character arithmetic and therefore the program compiles, but as non-standard C. data+1 would then mean +1 byte, not +1 int.

Use gcc as a a standard C compiler instead -std=c11 -pedantic-errors. Then change the code to (int*)data+1.

Also the void** makes no sense, should be a void*. Please note that (int*)data[0] means "do pointer arithmetic on void** type, then cast the result to int*. This is an operator precedence bug. [] has higher precedence than the cast () operator.

Just toss that whole code out and use this:

#include <stdio.h>
#include <stdlib.h>

int main(void){
    void* data;
    data = malloc( sizeof(int[2]) );
    ((int*)data)[0] = 5;
    ((int*)data)[1] = 10;
    printf("%d\n", *(int*)data );
    printf("%d\n", *((int*)data+1) );
    free(data);
    return 0;
}
Lundin
  • 195,001
  • 40
  • 254
  • 396
  • 1
    `data` is not a void*, it is a void** on which arithmetic is perfectly defined – chqrlie Feb 27 '17 at 16:57
  • ah ok i though -pedantic-errors and -Wall would be enough to stop that. And thank you for letting me know about the operator precedence bug. However the reason I've been using `void **` was honestly because I've been looking at how dynamic arrays are done and I've seen multiple times people saying to use `void **` over `void*`. I'm somewhat confused as to why people would suggest `void **` is there an advantage to using it over just a void pointer? – zee Feb 27 '17 at 16:59
  • @chqrlie Well yeah, the summary is that the original code is strange and doesn't do what the OP thought it would. – Lundin Feb 27 '17 at 18:08
  • @zee It's because the people suggesting it are confused too. [Info about dynamic multi-dimensional arrays](http://stackoverflow.com/questions/42094465/correctly-allocating-multi-dimensional-arrays) – Lundin Feb 27 '17 at 18:08
0

Both your examples are not correct.

void** data = malloc(sizeof(int)*2);

is allocating 2 int integers, but data if of type void**.If you wish to still use this, which is not recommended, you need to allocate 2 void* pointers. This would then be:

void** data = malloc(sizeof(void*)*2);

Having said this, using void** is not needed here. You can just use void* as pointed out in @Lundin's post. Your code would be optimal if you use int *data instead though, as it doesn't really make sense to use void* pointers here. If you decide to do this, your code can just be:

#include <stdio.h>
#include <stdlib.h>

int main(void){
    int *data;
    data = malloc(sizeof(int)*2);
    data[0] = 5;
    data[1] = 10;
    printf("%d\n", data[0]);
    printf("%d\n", data[1]);
    free(data);
    return 0;
}

Which is more straightforward, and skips the complications that void* pointers bring in code.

Note: You must check return of malloc() always, as it can return NULL on failure.

RoadRunner
  • 25,803
  • 6
  • 42
  • 75
  • ok thank you, i thought i was supposed to allocate using the sizeof what that pointer was goin to point to. As for using int* im only giving this code as an example so this isn't the way im actually using it, I'm mainly trying to understand pointers and generic pointers as well as how arrays and dynamic arrays work. – zee Feb 27 '17 at 17:33
-2

first: please change the type of data to int* or at least to void*. don't mess with void** unless you need to pass to a function a pointer.

second: change data[0/1] to &data[0/1].data[] is an argument and &data[] is his pointer. if you still using the void* choose *((int*)data+?). if yopu changed to int* use data[?].

third: why to use pointers in this function? this is not a function that need pointers.

fourth: i would suggest in this case to use an array instead of the pointers. if you already know the type and size of your argument so you better use arrays. more comfortable.

Roy Avidan
  • 769
  • 8
  • 25