tags:

views:

171

answers:

6
void test(int p1[10], int p2) {
    int l1;
    int l2[10];

    printf("params are at %d and %d\n", &p1, &p2);
    printf("locals are at %d and %d\n", &l1, &l2[0]);
}


int main(void) {
    test(5, 10);
}

I'm a bit confused by the code above... how can we supply an argument of 5 to the test function when the function has already specified an array of p[10]. The output address is also very strange, the p1 and p2 should have been 40 addresses apart (array of 10 elements times 4 bytes per int). But the console shows that they're only 4 units apart....

+4  A: 
  1. 5 is implicitly converted to a pointer to int (i.e. 0x00000005).
  2. First array argument is actually equivalent to a pointer to int, because you can't pass arrays by value in C. Therefore you are taking addresses of two local variables on the stack (a pointer to int and an int). Each one is 4 bytes, hence 4 byte difference between their addresses.
Alex B
Elaborating slightly (because it doesn't merit another answer, as this one is correct) on 1.) when you supply "5" to test(), the compiler takes 5 as an address (0x00000005 on a 32 bit machine) to the "array". If you were to operate on 0x00000005, depending on the machine and OS (but likely regardless of machine), you could potentially cause some major issues. Be careful!
Isaac Hodes
Not to nitpick further, but in 2009, the overwhelmingly likely outcome of major issues would be a segfault, possibly sigbus.
Marc Bollinger
A: 

You are not passing in an array as a value, you are just passing an int, 0x0000005 or whatever.

You are passing two variables which you have just allocated, i.e. on the stack. So you have allocated room for two integers, each 4 bytes. Thus when you find their addresses, they should be 4 apart.

DevDevDev
+3  A: 

GCC sayeth (with no arguments to encourage error reporting):

$ gcc -c z.c
z.c: In function ‘main’:
z.c:13: warning: passing argument 1 of ‘test’ makes pointer from integer
without a cast
$

The code in z.c is the code in the question preceded by '#include <stdio.h>' and a blank line.

GCC is telling truth - the code is bust on C - indulging in undefined behaviour (converting an integer, 5, into a pointer to integer, without a cast to tell the compiler that the programmer has any clue what they are up to).

Because p1 is equivalent to 'int *p1', the distance apart of p1 and p2 (4) is correct for a 32-bit compilation.

Jonathan Leffler
Good point – I just threw it into GCC curious as to how it was compiling correctly, and GCC would have none of that! Begs the question, which compiler is our questioner using?
Isaac Hodes
Agreed - or which warnings are they not telling us that they are ignoring. I think that any compiler that accepts prototypes should be generating a warning; I suppose there might be some antiques out there that do not.
Jonathan Leffler
+1  A: 

The test() function has two parameters: a pointer p1 (point to an array of 10 integers) and an integer p2. On the stack p2 is on a higher address and p1 is on a lower. The difference between the starting addresses of p2 and p1 is the size of p2 (==4).

The function has two local variables on the stack: an integer l1 on a higher address, and an array l2 (of 10 integers) on a lower address. The difference between the starting addresses of l1 and l2 is the size of the l2 array (==4*10).

When You call 'test(5, 10)' in main(), the literal '5' will not be interpreted inside the test() function as an integer but as a pointer (so the compiler sad: "makes pointer from integer without a cast").

sambowry
A: 

Welcome to a world where the code is not type-safe and not memory-safe


And remember what they say about "where angels fear to tread". Array parameters in C are rewritten automatically to be "pointer to array". The pointer of 5 is certainly incorrect but C will run with it**...**for a while.

You can't get a program like this through MS C++, as I recall, so I'm thinking you are using gnu. I would recommend -Wall -Werror in that case.

DigitalRoss
A: 

As others have noted you are passing a literal int (5) which is being converted to a pointer type on being passed to the test function. In function parameters, all top level array declarations are converted to pointers, so test can be equivalently written

void test( int* p1, int p2 )

There are issues with your printf calls. %d is the format specifier for an int and not a pointer type. To correctly pass a pointer to printf you should explicitly cast to a void* and use the %p format specifier.

printf("params are at %p and %p\n", (void*)&p1, (void*)&p2);
printf("locals are at %p and %p\n", (void*)&l1, (void*)&l2[0]);

You need to do this before you can make a call about whether the displayed addresses look 'strange'.

Charles Bailey