Why is a char* being treated the same as a char** in C?
Asked Answered
D

4

5

I have the following test application:

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

int main(void){
    char buf[512];
    buf[0]= 0x1;
    buf[1]= 0x2;
    char *temp1 = &buf;
    char *temp2 = buf;
    char *temp3 = &buf[0];
    printf("temp1:%p, temp2:%p, temp3:%p\n",temp1,temp2,temp3);
    printf("0 = %d, %d, %d\n",temp1[0],temp2[0],temp3[0]);
    printf("1 = %d, %d, %d\n",temp1[1],temp2[1],temp3[1]);
    return;
}

It compiles with a warning:

gcc ./testptr.c -o testptr
./testptr.c: In function ‘main’:
./testptr.c:9: warning: initialization from incompatible pointer type

But when I run it, all three pointers behave the same.

./testptr
temp1:0x7fff3a85f220, temp2:0x7fff3a85f220, temp3:0x7fff3a85f220
0 = 1, 1, 1
1 = 2, 2, 2

I know that buf == &buf[0], but why does &buf == &buf[0]? Shouldn't &buf be a char**?

Danit answered 6/10, 2011 at 2:45 Comment(5)
&buf is actually a char(*)[512] (a pointer to a 512-item char array). They're not quite the same.Adur
You changed your code between capturing the compiler output and pasting the code into the question. The problem is on line 9 now.Sheritasherj
Sorry you are right, just added a new lineDanit
An almost same question has been answered here: #6473162Aquiver
@Aquiver Thanks, good answers there too, hadn't come up in my search.Danit
N
3

All pointers behave the same because you declared all of them to be char*. C is statically typed so the type is bound to the variable and not the value.

Now that the behaviour part is explained, we only need to find out why they actually have the same value (as per the %p printf). Well, this is just an artifact of pointers being implemented as a memory address by GCC (the offsets and sizing that make a * differ from a ** are all handled by the type system/compiler behind the scenes). Do note that like any of the most suspicious stuff that gives out warnings, this is likely to be undefined behaviour or at the least, a bad practice :)

Negotiation answered 6/10, 2011 at 3:0 Comment(0)
L
2

Arrays are not pointers, although they can be used in much the same way. You happen to have found one aspect in which array and pointer semantics differ.

Liable answered 6/10, 2011 at 2:49 Comment(3)
I discovered this when I had accidentally passed &buf instead of buf as the second argument of type void * to the recv function. Is it possible that this could cause a problem even though my example above does not illustrate it?Danit
@austinmarton: I prefer to err on the side of paranoia when it comes to C compiler warningsNegotiation
@missingno: Fair call. In my original application the mistake was passed as a void pointer so no warning was generated.Danit
M
1

You can work it out from the algebra of the * and & operators.

  • we know that buf is the address of the 0-th element of the buf array

  • we know that &buf[0] is also the address of the 0-th element

  • by definition buf[0] is equivalent to *(buf+0)

  • and &(*(a)) is equivalent to a.

So, &buf[0] becomes &(*(buf+0)) which is buf.

Update

Here, let's lay it out as a proof.

  1. &buf[0] Given.
  2. &(buf[0]) by C precedence rules with ()'s
  3. &((*(buf+0))) because buf[0] == *(buf+0).
  4. &(*(buf+0)) eliminating extraneous parens
  5. buf QED
Mussel answered 6/10, 2011 at 2:55 Comment(3)
I agree with what you are saying (buf == &buf[0]), but that is not quite what I am asking about (&buf == buf?).Danit
@austinmarton, follow the steps: they're a proof that, yes, &buf is equivalent to buf.Mussel
@Charlie: No, the proof says that &buf[0] is equivalent to buf, not that &buf is equivalent to buf, which was what the question was asking about.Radiolocation
S
1

If you think about what code is actually being generated by the compiler when it processes an array, it becomes more clear. The name buf references the address of the first (zeroth) element of the array (contiguous space for containing chars). If you look in the object at the symbol table's entry for "buf", you'll find the address of that first element. When you reference, e.g., buf[0], the compiler generates the address of buf, plus zero times the size of a char. This happens to be the same as the address of buf itself.

Syrian answered 6/10, 2011 at 3:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.