2

Why does the following code produce the correct output. Ideally we should pass a instead of &a. But I have found that passing &a also produces the same result. But this does not work for integer variables, it works only for arrays. Can somebody explain the logic behind it. Thanks in advance.

#include <stdio.h>
void m(int *p)
{
    int i = 0;
    for(i = 0;i < 3; i++)
    printf("%d\t", p[i]);
}
void main()
{
    int a[3] = {6, 5, 3};
    m(&a);
}
vusan
  • 5,221
  • 4
  • 46
  • 81
varunkr
  • 5,364
  • 11
  • 50
  • 99
  • See http://stackoverflow.com/questions/2528318/how-come-an-arrays-address-is-equal-to-its-value-in-c – irrelephant Nov 02 '14 at 06:23
  • Read this: [What exactly is the array name in c?](http://stackoverflow.com/a/24468853/2455888) – haccks Nov 02 '14 at 06:25
  • You should enable warnings, `-Wall -Wextra` for gcc/clang. Then `&a` version should give you a compiler warning about argument type. Study it for extra insight. – hyde Nov 02 '14 at 06:41
  • This does not work. This only appears to work. The code contains a constraint violation (passing a pointer argument to a pointer to incompatible type) and it violates strict aliasing as well (it is accessing an object through an lvalue of incompatible type). Hence, it has undefined behavior and any and all behavior is expected from the program. – The Paramagnetic Croissant Nov 02 '14 at 06:45
  • @TheParamagneticCroissant Are you sure it violates strict aliasing? The array is not modified anywhere after its address is taken, so what kind of aliasing problem can arise? – hyde Nov 02 '14 at 06:57
  • @hyde modification is not required for the violation of strict aliasing, merely the act of *acessing* the object of the wrong type *in any way* is enough. – The Paramagnetic Croissant Nov 02 '14 at 09:05
  • @TheParamagneticCroissant but an object is not accessed via wrong type. `int` in array is accessed via `int *p`. Pointer `&a` of right value (AFAIK) but wrong type is is taken and implicitly cast to correct type. Does that pointer casting break strict aliasing? – hyde Nov 02 '14 at 11:00
  • @hyde `&a` is an `int (*)[3]`. If you access it by dereferencing an `int *`, that's wrong no matter what. Even if `&a == &a[0]` (which is actually expected). (and yes, it's almost always pointer casting that breaking strict aliasing is achieved through.) – The Paramagnetic Croissant Nov 02 '14 at 11:11

3 Answers3

1

To answer the actual question, "why does it work", here is a short lay-man answer. First you need to review the linked questions to understand what int *p, int a[3] and &a are and why they are wrong. Then the reason they work:

Legacy reasons!

Prior to standardization, in the '70s and '80s, a lot of old compilers didn't care about that kind of code. Address is an address, who cares if type is slightly wrong, right? So a lot of code got written, which has code like this, which is wrong by current standards, but "logically" (by human thinking) should work.

So, instead of making that kind of code non-compilable, when C was standardized, this kind of code was just defined to have Undefined Behavior. Problem solved.

So, always enable warnings when building modern code, and fix them. That will not catch all C Undefined Behaviour, but it will catch many, including this one.

hyde
  • 60,639
  • 21
  • 115
  • 176
1

I'm pretty certain this is undefined behavior. First, an example of the warnings you may get on your compiler:

main.cpp: In function 'main':
main.cpp:11:5: warning: passing argument 1 of 'm' from incompatible pointer type
     m(&a);
     ^
main.cpp:2:6: note: expected 'int *' but argument is of type 'int (*)[3]'
 void m(int *p)

The C11 standard (n1570) says:

§6.7.6.2/2 For two pointer types to be compatible, both shall be identically qualified and both shall be pointers to compatible types.

§J.2/1 The behavior is undefined in the following circumstances:

— A "shall" or "shall not" requirement that appears outside of a constraint is violated (clause 4).

[..]

— Two pointer types that are required to be compatible are not identically qualified, or are not pointers to compatible types (6.7.6.1).

0

a is the start address of the array. So you don't need to deference the address of a.

Replace you line:

m(&a);

with

m(a);
Kaizhe Huang
  • 990
  • 5
  • 11