Address of an address in C. Valid or not?

127 Views Asked by At

I thought I understood c and pointers but was just debugging someone elses code that I thought should not work but did. As a (crude) example....

void clear_buffer(char* buff, int len)
{
    while(len)
    {
        *buff++ = ' ';
        len--;
    }
}

main()
{
    char buffer[10];

    clear_buffer(&buffer,10);   // 1. what I found, it still works...
    clear_buffer(buffer,10);    // 2. what I would have wrote
}

What suprised me was that both calls above do work exactly the same way. The first one gives a compiler warning (incompatible pointer types) but it still builds and runs correctly. So my question is: is this the expected behaviour in C or is it just the compiler I am using being clever and fixing a bug? fwiw, this is using the microchip xc16 compiler.

2

There are 2 best solutions below

1
On

This call

clear_buffer(&buffer,10);

is incorrect and the compiler shall issue an error message.

The type of the expression &buffer is char ( * )[10] while the type of the corresponding function parameter is char * and there is no implicit conversion from one type to another.

The program works as expected because the values of the expressions &buffer and buffer are the same: it is the address of the extent of memory occupied by the array though types of the expressions are different.

Consider another example. Here is a demonstrative program

#include <stdio.h>

int main(void) 
{
    struct A
    {
        int x;
    } a = { 10 };
    
    printf( "&a   = %p\n", ( void * )&a );
    printf( "&a.x = %p\n", ( void * )&a.x );

    return 0;
}

The program output is

&a   = 0x7ffef64abb84
&a.x = 0x7ffef64abb84

as you can see the program outputs equal addresses though the types of the expressions &a and &a.x are different.

The same takes place in your program. The address of a whole array equal to the address of its first element though the types of the whole array and its element are different.

In fact in your function you are reinterpreting the pointer to the whole array of the type char ( * )[10] as a pointer to the first array element of the type char *.

1
On

In the expression clear_buffer(buffer, 10), buffer is converted to a pointer to its first element, so is equivalent to &buffer[0]. In the expression clear_buffer(&buffer, 10), buffer is not converted to a pointer to its first element because it is the operand of the & address operator. That is one of the exceptions to the rule of arrays decaying to pointers in expressions. (The other exception to the rule is the sizeof operator.)

The first element of an array is at the same address as the array itself, so &buffer and &buffer[0] have the same address, but different types. &buffer has type char (*)[10] (pointer to array [10] of char), and &buffer[0] has type char *.

The warning is due to the pointer type mismatch in the call clear_buffer(&buffer, 10).