-2
#include<stdio.h> 
int main() 
{ 
   int a[2] = {1, 2}; 
   void *ptr = &a; 
   ptr = ptr + sizeof(int); 
   printf("%d", *(int *)ptr); 
   return 0; 
} 

For this code i am getting 2 as output But i just read that a=&a[0] ,ie, name of array = base address of array so why its giving correct output if i wrote void *ptr=&a which is actually putting ptr=&&a[0] is this undefined behaviour

ps: i am a beginner and posting question for the first time please explain it thoroughly

Edit: Also why it is not working if we use int *ptr ,ie,integer pointer

  • `a` means `&a[0]` *only in places where `a` doesn't work*. Otherwise `a` just means `a`. In this case `a` just means `a`. – user253751 Aug 31 '20 at 13:24
  • `ptr = ptr + sizeof(int);` throws a compile error. Performing arithmetic on a void pointer is non-compliant. (It is allowed only with a GNU extension.) Then once performed (if allowed by your compiler.), _using_ that pointer would invoke undefined behavior. – ryyker Aug 31 '20 at 13:37
  • Unless you are using a compiler that provides extensions, the code you posted would never allow you to build, so running would not be possible. What compiler (and compiler version) are you using? Is the code posted _exactly_ the code you are running? – ryyker Aug 31 '20 at 13:41
  • yes its exactly the same code i am using in gcc (tdm-1) 5.1.0 i dont know much abt it – ayush tamra Aug 31 '20 at 13:47
  • https://stackoverflow.com/questions/4019671/can-i-do-arithmetic-on-void-pointers-in-c – pm100 Aug 31 '20 at 13:52

2 Answers2

3

There is only one thing wrong here - the void pointer arithmetic is a GCC extension!

ptr.c: In function ‘main’:
ptr.c:7:14: warning: pointer of type ‘void *’ used in arithmetic [-Wpointer-arith]
    7 |    ptr = ptr + sizeof(int);
      |              ^

You should use a character pointer instead:

#include<stdio.h> 

int main(void) 
{ 
   int a[2] = {1, 2}; 
   void *ptr = &a; 
   ptr = (char*)ptr + sizeof(int); 
   printf("%d", *(int *)ptr); 
   return 0; 
}

The void type is not a complete type, hence you cannot perform arithmetic on it.

As for

void *ptr = &a; 

vs

void *ptr = a; 

&a would be a pointer to an array, i.e. of type int (*)[2], whereas a, after type decay, would be pointer to the first element, i.e. of type int *. But both of them would point to the same memory location and after conversion to void * would result the in the exact same pointer value.

As for why it does not work for integer pointer - of course it does, but you need to increment it not by sizeof(int) but by 1.

Antti Haapala
  • 117,318
  • 21
  • 243
  • 279
1

All of the expressions a, &a and &a[0] will yield the same address1 - the address of the array is the same as the address of its first element:

   +---+
a: | 1 | a[0]
   +---+
   | 2 | a[1]
   +---+

The difference is in the types of the expressions. a has type int [2], but unless it is the operand of the sizeof or unary & operators, it "decays" to type int * and the value of the expression will be the address of the first element2. &a[0] has type int *, and &a has type int (*)[2] (pointer to 2-element array of int).

This is why it didn't work when you wrote

int *ptr = &a; // int * = int (*)[2]

The types aren't compatible. It would have worked if you had written

int *ptr = a; // int * = int *

Again, a has type int [2], but unless it's the operand of the sizeof or unary & operators, it "decays" to type int * and its value is the address of the first element - in this context, it's identical to writing &a[0].


  1. Not accounting for any type conversion - on platforms like x86 and x86-64, int * and int (*)[2] have the same size and representation, but that's not guaranteed everywhere.
  2. This is important - an array expression is not a pointer. It will be converted to a pointer as necessary, but there's no separate pointer object that explicitly points to the first element of the array.
John Bode
  • 106,204
  • 16
  • 103
  • 178