gcc: pointer to array

A

Alexei A. Frounze

Alexei said:
I have a question regarding the gcc behavior (gcc version 3.3.4).

On the following test program it emits a warning:
#include <stdio.h>

int aInt3[5] = {0,1,2,4,9};

void print2 (const int (*p)[5])
{
}

int main()
{
print2 (&aInt3); // <-- warns here
return 0;
}
The warning is:
MOD.c: In function `main':
MOD.c:: warning: passing arg 1 of `print2' from incompatible pointer
type

The compiler is correct. The pointers point to incompatible types;
the element type of one array is const-qualified, and it isn't in the
other. Type compatibility is recursive, and types with different
qualifiers are not compatible.

Either the function needs to lose the const qualifier, or you need to
add it to your array.
There's another thing about the pointer to the array is... The compiler
doesn't generate a warning if I change in print2()
for (cnt=0; cnt<5; cnt++)
to
for (cnt=0; cnt<6; cnt++)
and lets me access (*p)[5], though I think at least a warning should be
generated here.

That's hard as it has to follow what your program is doing, not just
the syntax. It's certainly possible to warn, though; some lint
programs would.

I don't think its hard to follow what it is doing. At least, the type is
pointer to the array of 5 integers, not 6 or more. A warning IMO is due in
this case too, not only when I use the array of 5 integers directly (w/o a
pointer to it).
It doesn't warn me if I put
aInt3[6] = 0;
into main(). But in both cases the compiler "knows" the real size of the
array, still no warning...

That's easy to warn about and GCC should do it. I suggest you file an
enhancement request.

I guess this enhancement request will be ignored or flamed or something...
The world is envaded by the code like this:
typedef struct tMessage {
long Type;
size_t AmountOfAttachedData;
char aAttachedData[1];
} tMessage;
tMessage* pMsg;
pMsg = GetMyMessage();
Which assumes reading and writing to pMsg->aAttachedData[] at indices
greater than 0. :(

Alex
 
A

Alexei A. Frounze

Old Wolf said:
Alexei said:
I have a question regarding the gcc behavior (gcc version 3.3.4).

You got an unusually high number of garbage responses :)
On the following test program it emits a warning:
#include <stdio.h>

int aInt3[5] = {0,1,2,4,9};

void print2 (const int (*p)[5])
{
size_t cnt;
for (cnt=0; cnt<5; cnt++)
printf ("%d\n", (*p)[cnt]);
}

int main()
{
print2 (&aInt3); // <-- warns here
return 0;
}

MOD.c:: warning: passing arg 1 of `print2' from incompatible pointer
type

print2 is expecting a pointer to an array of constant ints.

Note, you can't have a "const array" in C -- you can
only have an array whose members are all const.

aInt3 is an array of ints, and there is no implicit conversion
in C from pointer-to-array-of-T to pointer-to-array-of-const-T
(or an array of anything else, for that matter). This could be
considered a language defect.

But, this does work:
typedef int (*P5INT)[5];
void print2(const P5INT p)
{

AFAIK it's not possible to do this without a typedef.

I presume you wanted to write something like this:

typedef int(tArrayType)[5];
tArrayType arr = {0,1,2,3,4};

void print3 (const tArrayType* p)
{
int i;
for (i=0; i<5; i++)
printf ("%d\n", (*p));
}

int main()
{
print3 (&arr);
return 0;
}

But this too issues a warning unless I have arr being const or remove const
from print3().
Same thing, same warning.

Alex
 
A

Alexei A. Frounze

....
That's true, but a pointer to an object can be treated as an array of
those objects and this is no less true for pointers to arrays - which can
be treated as arrays of arrays. So for index other than 0

ap[index] != (*ap)[index]

In fact accessing ap[1] in this instance is illegal but conceptually it is
an access of the second "5 element integer array" element of ap.

OK, I agree with this kind of double indirection.

The prob is though that we have different semantics for pointer to some
object being not an array and for pointer to some object being an array in
the sense that these two objects are treated differently. If this is because
the 2nd pointer is seen as a pointer to pointer (simply because it
unfortunately points to an array) and we have such restrictions on pointers
to pointers, then something is wrong in C or gcc. Like I say in the other
today's post, I don't see a good reason why an attempt to enforce treatment
of some object as being constant (throught the use of a pointer to constant)
is considered bad.
Let's then forget about the array and indeed switch to a pointer to pointer:
char c = 'A';
char *p = &c;
char **pp = &p; // OK
const char **pp_ = &p; // warned
But all what type of pp_ means is that I cannot modify a char that is
somehow doubly dereferenced by pp_. And I think I must be allowed to have
this kind of assignment (pp_ = &p; in the above) because instead of
loosening the protection I try to enforce it. This is the point now.

Alex
 
A

Alexei A. Frounze

....
Try this one...
Array decays to pointer while array is passed to the function...

int aInt[5] = {1,2,3,4,5};

void print (const int p[5]) {
int x = 25;
if (__builtin_types_compatible_p (typeof (p), const int * ))
printf ("trallalalaa...");
printf ("%d %d %d\n", sizeof (p), sizeof (int[5]), sizeof (const
int *));
//*p[0] = 3;
printf ("%d\n", p[0]);
p = &x;
printf ("%d\n", *p);
}

int main()
{
printf ("test begin\n");

print (aInt);

printf ("test end\n");
return 0;
}


- jt

So, this way I'll pass a pointer to aInt[0], which is OK, but there would
still be no warning no nothing if I try to pass as argument some aInt_
defined as:
int aInt_[6] = {1,2,3,4,5,6};
or as:
int aInt_[4] = {1,2,3,4};
I mean, that [5] in the argument list doesn't mean anything to the compiler.
It wouldn't warn if smaller/bigger array was used. Merely a comment-like
statement :) As if you wrote an operator like this somewhere in the code:
0;
:)
Alex
 
A

Alexei A. Frounze

Maxim S. Shatskih said:
An array is one layer of indirection. Given its similarity to a pointer I
don't see much controversy in that statement. A pointer to an array is
therefore a second layer of indirection. What do you find disagreeable
about this reasoning?

The C notion of the array is another. Array is the same as pointer to its first
element (in all operations except sizeof(), and so ( p + a ) offset
operations).
What is "the pointer" to which you are referring?

MyArray and &(MyArray[0]) is the same in all contexts except sizeof().
absurd - a pointer to an array is much more than just an address.

In C and C++, it is the same.
doubt that you mean that. Generally a pointer is a variable...

Pointer is a value. Value != variable.

Any value needs storage, including the address that is stored in a special
variable called a pointer. :)

Alex
 
A

Alexei A. Frounze

Andrey Tarasevich said:
Alexei said:
...
So, I presume nobody knows what's wrong. I haven't found anything on this
particular thing in C99. Maybe it's just gcc's way to do things... I need
more statistics.
...

What's wrong in the original case is perfectly clear here. The warning is a
consequence of C language's const-correctness rules when they are applied to
arrays (and it's been mentioned here already).

Simply speaking, in accordance with C language's const correctness rules, you
can perform an implicit 'T* -> const T*' conversion. Often people assume that,
say, 'int (*)[10] -> const int (*)[10]' conversion also belongs to that category
and should be performed implicitly without any warnings (that's what you
assumed, apparently). Unfortunately, this is not the case. In C language it is
not possible to const-qualify an array type as a whole. Period. Any attempts to
const-qualify an array type will actually const-qualify the type of the array
_elements_ not the array type itself. In other words, there's no situation in C
when the 'T* -> const T*' can be applied to pointers-to-arrays, since the proper
destination type cannot ever exist in C.

Best regards,
Andrey Tarasevich

Which means C's types are wrong since the T that is an array is treated
differently from T that is not.
If we define:
typedef int(tArrayType)[5];
then still an object of type tArrayType is pretty much different from say
typedef struct tArrayType {/*some member(s)*/} tArrayType;
In the first case we'll get a warning when passing &T to a function
declaring
argument as "const* T" but we won't get the warning in the second case.

Alex
 
N

Netocrat

[Given "int arr[N];" and considering "&arr" vs "&arr[0]")

Netocrat said:
Everything else you've said is spot on, but this is slightly incorrect.

Actually, it is completely correct. :) But it does not tell you all that
much by itself: as I have shown before, the values of 3 and 3.14 are
identical too:

int i = 3;
double d = 3.14;

if ((char)i == (char)d)
puts("3 and 3.14 are identical");
else
puts("3 and 3.14 are different");

Obviously they are only "identical" after conversion to a common type --
in this case "char" -- and the results may (and do) change if we pick a
different common type:

if ((float)i == (float)d)
puts("3 and 3.14 are identical");
else
puts("3 and 3.14 are different");

To compare &arr against &arr[0], we have to convert to a common type; and
as with the int/double arrangement above, this may change the value(s) in
the process:

Point taken.
#include <stdio.h>
int glob_array[5];

int main(void)
{
int fn_array[5];

if ((&glob_array != glob_array) || (&fn_array != fn_array))
printf("I haven't seen a situation like this before.\n");
}
}
If you actually compile this,

Which I didn't (obviously).
you get the required diagnostic, and in this
particular case, two more diagnostics:

% cc -O2 -W -Wall -ansi -pedantic -o t t.c t.c: In function `main':
t.c:8: warning: comparison of distinct pointer types lacks a cast
t.c:8: warning: comparison of distinct pointer types lacks a cast
t.c:10: warning: control reaches end of non-void function

(the C standard requires only that "at least one diagnostic" come out, and
does not say whether it is a "warning", or an "error", or even a
"kumquat"). We can fix this by inserting a conversion to some common
type: for instance, we could cast both to "char *". But introducing a
conversion gets us back to that 3==3.14 problem. I think the real question
boils down to whether &arr and &arr[0] will compare equal under *all*
"well-defined" conversions -- which may even be only those to "char *" and
"void *" -- and then I think the answer is "yes", so that we can in fact
say that the converted values are always identical as long as we do a
sensible conversion.

You "think" the answer is "yes", Chris Crough in his reply asks "Is that
actually defined by the standard?" and in my original post I wrote "I
don't know however, whether this is mandated by the standard - in theory
it isn't necessary for it to be true". None of us know for sure...
But, onward:
However in the context of a function parameter, it is not true. Given
that in C parameters are passed by value, it's not possible for the
address of the array parameter to equal the address of the original
array and therefore it's not possible for the address of the array
parameter to equal the address of the first element that it points to.
i.e. we can write:

#include <stdio.h>
void somefunction(int arrayparm[5])
{
if (arrayparm == &arrayparm)
printf("Something impossible has occurred.\n");
}
}
The real problem here is "what you see, well, all of it's a lie"[%]. The
variable named "arrayparm" has type "pointer to int", not "array 5 of
int". We can expose the lie via various operators:

/* these sizes will differ (unless you get VERY unlucky) */
printf("sizeof (int [5]) = %lu\n", (unsigned long)sizeof (int [5]));
printf("sizeof arrayparm = %lu\n", (unsigned long)sizeof arrayparm);

/* cannot do this with an array */
arrayparm = NULL;

and of course, your own example, once we insert some appropriate
conversions to eliminate the need for a diagnostic (and perhaps no
executable program as a consequence of the diagnostic):

printf("%p != %p, we presume\n", (void *)arrayparm, (void
*)&arrayparm); if ((void *)arrayparm != (void *)&arrayparm)
puts("we presumed correctly");
else
puts("uh oh");

[% "Wine from the Water", from Try Anything Once]

Right, right, of course... an array decays into a pointer when passed as
a parameter to a function. I had forgotten that. So I was treating a
pointer as an array and making the wrong deductions. It does seem then
that there is no case where (void*)&array is necessarily different to
(void*)array... leaving the question, as Chris Crough puts it, of whether
'pre-standard C compilers [implementing] arrays ... as pointers ... [is a
type of] expansion actually banned by the standard, or [whether it is]
"just not the done thing"?'
 
N

Netocrat

The C notion of the array is another.

You are just repeating my first statement, because by "array" of course I
meant "the C notion of the array" - we are talking in a C newsgroup after
all. You seem to be implying that there is a third layer of indirection
different from the two I described... I just don't understand your point.
Array is the same as pointer to its
first element (in all operations except sizeof(), and so ( p + a )
offset operations).

True, but of what relevance is that statement? You are supposedly, after
all, disagreeing with my statement that "A pointer to an array *is* double
indirection." How does this support your case?
What is "the pointer" to which you are referring?

MyArray and &(MyArray[0]) is the same in all contexts except sizeof().

As Chris Torek pointed out in another part of this thread, that statement
is not actually correct. They are different types. But yes, we all
seem to agree that the values will be the same for sensible conversions.

That statement does not, however, answer my question, which was which
pointer you are referring to.
In C and C++, it is the same.

No, it is not the same. A pointer is not an address. It is a type
whose value represents an address.
Pointer is a value. Value != variable.

A pointer is a type containing a value. Container of value != value.

You still haven't explained why you disagree with my statement that a
pointer to an array is double indirection.
 
N

Netocrat

The C notion of the array is another.

You are just repeating my first statement, because by "array" of course I
meant "the C notion of the array" - we are talking in a C newsgroup after
all. You seem to be implying that there is a third layer of indirection
different from the two I described... I just don't understand your point.
Array is the same as pointer to its
first element (in all operations except sizeof(), and so ( p + a )
offset operations).

True, but of what relevance is that statement? You are supposedly, after
all, disagreeing with my statement that "A pointer to an array *is* double
indirection." How does this support your case?
What is "the pointer" to which you are referring?

MyArray and &(MyArray[0]) is the same in all contexts except sizeof().

As Chris Torek pointed out in another part of this thread, that statement
is not actually correct. They are different types. But yes, we all
seem to agree that the values will be the same for sensible conversions.

Ack, having just responded to Chris' post I was quick to misread your
statement as comparing MyArray with &MyArray which it obviously isn't. So
they are compatible types after all. They aren't identical types though
because assuming that MyArray is declared something like char MyArray[10],
then MyArray is of type "array 10 of char" whereas &(MyArray[0]) is of
type "pointer to char". Not the same but interchangeable in most
expressions, with some exceptions such as the one you gave - sizeof().
That statement does not, however, answer my question, which was which
pointer you are referring to.

I'll cut you some slack here because after re-reading I see that you
intended "the pointer" to refer to the pointer to the array's first
element. But your meaning is still unclear because as I originally
explained, a pointer to an array can itself be indexed and treated as
though it were an array. So now rather than being unclear about what you
mean by "the pointer" I am confused about which "array" you are talking
about - the "pointer to array" array or the array that that "pointer to
array" points to?

I'll add that whilst you haven't specified the type of your variable
MyArray, its name suggests that it is intended to be an array, whereas
what you actually objected to was my characterisation of a type that was
a pointer to an array. So why don't you use such a type in your
explanation?
No, it is not the same. A pointer is not an address. It is a type
whose value represents an address.

I want to add that I wasn't contending that a pointer is always a
variable, just that generally it is. It is a type, and obviously it
occurs in contexts other than variables, such as taking the address of an
object, and casting.
A pointer is a type containing a value. Container of value != value.

This is a clearer and more accurate wording:

A pointer is a type, not a value.

A pointer is a type whose value represents the address of an object.

Your statement that a pointer is a value is as wrong as saying that an int
is a value. An int has a value, but it is a type, not a value. In the
same way, a pointer has a value, but it is a type, not a value.
 
N

Netocrat

Netocrat said:
[D]ouble indirection can easily be used to gain access to the
supposedly protected const type by assigning the middle pointer to a
non-const pointer. There's no way the compiler can detect this, so
disallowing automatic const-conversion for double-indirection
parameters makes sense.

I'm talking nonsense. You can't assign the middle pointer to a
non-const pointer without a cast. But you can use the automatic
conversion to violate the const protection: quoting "Me" in another
thread:

const char c = 'c';
char * pc;
const char ** pcc = & pc ; /* not allowed */
*pcc = & c;
*pc = 'C'; /* would modify a const object if the conversion above were
* allowed */

Correct, but I don't think it's a good example.

I think it's a great example for what it's intended to show. What it
shows is that the const protection you are giving your c variable is
useless if a char ** variable can be automatically cast to const char **.
So really it's showing: if you want to be able to trust that the const
qualifier actually does what it's supposed to do, then automatic
conversions from char ** to const char ** _cannot_ be allowed.

It may not be as useful in explaining how this relates to your case. You
seem to be arguing that an array should be treated as though it were a
simple type, rather than as an indirected type, in this case. Actually I
don't see any problems with doing that. The trick above can't be used
when pc is declared as a char array rather than char pointer, since then
we can't change its base address. So perhaps you could argue something
like this:

Since the type char [] is fundamentally different from char * in that the
base address of the variable it defines cannot be modified, the automatic
conversion from char (*)[] to const char (*)[] is not unsafe, as the
automatic conversion from char ** to const char ** is, and should be
allowed.

I don't see any problems with this statement (others may...). But the
point is, regardless of whether this statement is true or not, it seems to
me (and again I must reiterate that I don't know what the standard says on
this) that C does treat these types equivalently for const-casting
purposes.
Simply being able to
modify something by pc and being unable to modify it by ppc is just fine,
so is in the simpler example:
char c = 'A';
char *pc = &c;
const char *pc_ = &c;
*pc = 'B'; // OK
*pc_ = 'B'; // prohibited

Yes this is all OK because the automatic conversion of &c from type
char* to type const char* can not be used in any way to surreptitiously
write to any const-protected values.

This "simpler" example is indeed just that - because it doesn't deal with
double indirection or pointers to array at all - which is the case in
point. If you really want to use a simple example that applies to our
discussion, we could change the character types to character array types
and extend it thus:

char c[5] = "abcde";
char (*pc)[5] = &c;
const char (*pc_)[5] = &c; /* warning - prohibited */
(*pc)[1] = 'B'; /* OK */
(*pc_)[1] = 'B'; /* prohibited */

This illustrates your case better. As I have argued above - to echo
what I understand to be your fundamental argument - there is no semantic
reason for prohibiting the automatic casting of &c from char (*)[5] to
const char (*)[5]. Nevertheless in C it is prohibited. C'est la vie.
Apparently the casting rules are the same as for char ** to const char **
- for which there _is_ a good reason for prohibition. We might not think
it necessary or appropriate, but that's just the way C works in this case.

Another note - // comments are only allowed by the standard in C99, and
since you didn't specifically mention using C99 I presume you are not
using switches on gcc to invoke standards-compliant behaviour at all,
which you really should. Using -ansi -pedantic makes it reject non-C90
compliant code and using -std=C99 -pedantic does same for C99. -W and
-Wall are good for additional non-standard-specific warnings.
This is how most of libc's functions are declared -- their arguments are
of type of a pointer to a constant value.

I think you mean "const-qualifed type" rather than "constant value", but I
understand you.
This is what I'd like to have
with the array too. I'm not really sure why enforcing protection in this
simple case above is OK (i.e. pc=&c;) but not OK in case of using the
array as an object to be passed by reference/pointer.

Neither am I because it doesn't seem to serve any protective purpose,
but as I've tried to explain it seems to be because the array is being
treated equivalently to the case of a pointer, where a protective purpose
_is_ served.
I'm fine with
warnings and errors caused by the improper use of a pointer to a
constant object, e.g. attempt to modify the constant object. That's
perfectly understandable. Why cannot I enforce such a protection by
treating some object (not necessarily one defined as constant) as a
constant one

You can in some simple cases as your example shows, so I don't know why
you're arguing here that you cannot.
-- that's something I don't get, no matter if there's
double indirection or not.

Double indirection in the sense of char ** (but not in the sense of
char(*)[]) _does_ matter though, as the example I quoted shows.
I'm puzzled. What else am I missing?

You're totally missing the point of the example I quoted if you want to
maintain that double indirection of the form char ** should not be taken
into account when performing automatic const conversions. Double
indirection in the form char (*)[] of course is different in semantics but
apparently treated by C in the same way as char **.

Note that once we get to char (**)[] then this is a double pointer and
semantically truly does require prohibition of automatic const conversion.

Now to respond to the message you posted elsewhere:

Netocrat said:
That's true, but a pointer to an object can be treated as an array of
those objects and this is no less true for pointers to arrays - which
can be treated as arrays of arrays. So for index other than 0

ap[index] != (*ap)[index]

In fact accessing ap[1] in this instance is illegal but conceptually it
is an access of the second "5 element integer array" element of ap.

OK, I agree with this kind of double indirection.

The prob is though that we have different semantics for pointer to some
object being not an array and for pointer to some object being an array in
the sense that these two objects are treated differently.

Well that's not a totally accurate statement of the problem, because in
some cases (ie when that "some object" is a pointer) there really _is_
a need for different treatment as "Me"'s example shows. But if you
rewrite that statement as "We have different semantics for pointer to
array and for pointer to any other non-pointer type", then I agree.

There doesn't seem to be a compelling argument for pointer to array being
treated any differently to other non-simple types, such as structs. To
again modify your simple example:

struct s {
int x;
int y;
};

struct s c;
struct s *pc = &c;
const struct s *pc_ = &c; /* no prohibition here as there is when c is an
* array */
pc->x = 1; /* OK */
pc_->x = 2; /* prohibited */
If this is
because the 2nd pointer is seen as a pointer to pointer (simply because
it unfortunately points to an array)

As I've explained I believe that's the cause, but I don't know the
standard well enough to confirm this.
and we have such restrictions on
pointers to pointers,

For good reason, as the example I quoted shows.
then something is wrong in C or gcc.

That's a strong statement, and clearly as it applies to char ** conversion
its inaccurate, but as it applies to treating pointers to arrays
equivalently with double pointers, in this case your opinion that
"something is wrong in C" appears to be at the least a proposition that
could reasonably be argued.
Like I say in
the other today's post, I don't see a good reason why an attempt to
enforce treatment of some object as being constant (throught the use of
a pointer to constant) is considered bad. Let's then forget about the
array and indeed switch to a pointer to pointer:
char c = 'A';
char *p = &c;
char **pp = &p; // OK
const char **pp_ = &p; // warned
But all what type of pp_ means is that I cannot modify a char that is
somehow doubly dereferenced by pp_. And I think I must be allowed to
have this kind of assignment (pp_ = &p; in the above) because instead of
loosening the protection I try to enforce it. This is the point now.

But Alex you're now ignoring the lesson of the original example I quoted.
You're effectively saying, "the automatic conversion from char ** to
const char ** may have caused problems in Me's example, but it doesn't
in this case so it should be allowed here." Well and good, but in general
the compiler can't know when such an automatic conversion would cause
problems and when it wouldn't, which is why there is a rule that applies
in _all_ cases.

So in summary:
(a) it appears that there is no way around your problem without using a
cast. The cast doesn't appear to violate any const-protection semantics
as it would in the case where aInt3 was declared int * rather than int[5].
Casts in general are unwise though because they can mask useful (or
required) warnings, so be wary before using one.
(b) the prohibition of an automatic cast in this case does seem according
to const safety semantics to be unnecessary.
 
N

Netocrat

Netocrat said:
That's true, but a pointer to an object can be treated as an array of
those objects and this is no less true for pointers to arrays - which
can be treated as arrays of arrays. So for index other than 0

ap[index] != (*ap)[index]

In fact accessing ap[1] in this instance is illegal but conceptually it
is an access of the second "5 element integer array" element of ap.

OK, I agree with this kind of double indirection.

The prob is though that ...

<snip contents>

I integrated my reply to this post of yours with my reply to another of
your posts. The message-id of that other reply is
<[email protected]>
 
J

Joe Wright

Maxim said:
An array is one layer of indirection. Given its similarity to a pointer I
don't see much controversy in that statement. A pointer to an array is
therefore a second layer of indirection. What do you find disagreeable
about this reasoning?


The C notion of the array is another. Array is the same as pointer to its first
element (in all operations except sizeof(), and so ( p + a ) offset
operations).

What is "the pointer" to which you are referring?


MyArray and &(MyArray[0]) is the same in all contexts except sizeof().

absurd - a pointer to an array is much more than just an address.


In C and C++, it is the same.

doubt that you mean that. Generally a pointer is a variable...


Pointer is a value. Value != variable.

No. A pointer is a variable which can hold the address of another
variable. You know that, right? It's in every C book you've ever read.
Really! Some people refer to the value of an address and call that value
a 'pointer' but they misuse the term.

int *p; /* p is a variable of type pointer to int */
int a = 1; /* a is a variable with type int and value 1 */
p = &a; /* the address of a is assigned to variable p */

But p is the only pointer here. &a is an address.
 
M

Maxim S. Shatskih

Pointer is a value. Value != variable.
No. A pointer is a variable which can hold the address of another
variable. You know that, right? It's in every C book you've ever read.

Well, great discussion about what "value" is. :)

For me, "value" is a thing like ( a + 1 ) or a[10]. It is not a variable, and
it is not necessary "lvalue" - a[10] is lvalue, while ( a + 1 ) or ((long)a) is
not.

Value has a strictly defined type known at compile time.
 
N

Netocrat

Maxim said:
An array is one layer of indirection. Given its similarity to a pointer
I don't see much controversy in that statement. A pointer to an array
is therefore a second layer of indirection. What do you find
disagreeable about this reasoning?


The C notion of the array is another. Array is the same as pointer to
its first element (in all operations except sizeof(), and so ( p + a )
offset operations).

What is "the pointer" to which you are referring?


MyArray and &(MyArray[0]) is the same in all contexts except sizeof().

absurd - a pointer to an array is much more than just an address.


In C and C++, it is the same.

doubt that you mean that. Generally a pointer is a variable...


Pointer is a value. Value != variable.
No. A pointer is a variable which can hold the address of another
variable. You know that, right? It's in every C book you've ever read.
Really! Some people refer to the value of an address and call that value a
'pointer' but they misuse the term.

Actually a pointer is neither a value nor a variable but a type; the word
is commonly used to refer to a variable with pointer type though, and this
is reasonable usage.

Consider these usages:

"the dereferencing of variable x yields a pointer" - what you mean is
that dereferencing x yields a value of pointer type.

"x is a pointer" - what you mean is that x is a variable with pointer
type. This is the restricted sense in which the word pointer can be used
to refer to a variable. A pedant might require this to be written as "x
is a pointer variable", but there aren't any pedants on this newsgroup.

"cast it to a pointer" - what you mean is to change the compiler's view of
the expression so that it sees a pointer type. This could be any
expression - it doesn't have to be a variable.

"take the pointer and add one to it" - again this usage could apply to
any expression which evaluates to a pointer type; the expression could be
a value or a variable or some other expression, showing clearly that a
pointer is limited neither to being solely a value nor a variable.
int *p; /* p is a variable of type pointer to int */
int a = 1; /* a is a variable with type int and value 1 */
p = &a; /* the address of a is assigned to variable p */

But p is the only pointer here. &a is an address.

p is the only pointer variable, true, but &a is more than just an address;
it has a type, and that type is pointer to int. Can we categorically
call it a pointer as we can for a variable that has pointer type? It's
probably not unreasonable, but it isn't commonly done. In certain contexts
though it can indisputably be referred to as a pointer, as in "add one to
the pointer that we get when we dereference a".
 
N

Netocrat

Well, great discussion about what "value" is. :)

Yes it's an interesting discussion, but I wouldn't have said it was about
value... it seems to me that it's more about what a pointer is.
For me, "value" is a thing like ( a + 1 ) or a[10]. It is not a variable,
and it is not necessary "lvalue" - a[10] is lvalue, while ( a + 1 ) or
((long)a) is not. Value has a strictly defined type known at compile
time.

Replace "value" with "expression" in the above quote. And of course an
expression evaluates to a value, so you ultimately get to keep your value.

So after interpreting your usage of the word "value", what you are really
saying is that a pointer is an expression. I take your point(er) - it's
true that a pointer _is_ an expression, but I do think that it is better
(because more broadly) defined as a type.
 
M

Maxim S. Shatskih

Actually a pointer is neither a value nor a variable but a type; the word
is commonly used to refer to a variable with pointer type though, and this

Yes, and the value of the pointer type is also called "pointer" usually.

BTW - arrays and pointers are different for multu-dimension arrays. Imagine:

int Array[10][5];

- and please tell me what will be the type of

Array[1]

expression? Yes, the type will be "array of 5 integers", which is different
from "int *" - it is indexed in a different way.
 
N

Netocrat

Yes, and the value of the pointer type is also called "pointer" usually.

Well I'd be more inclined to refer to the value of a pointer type as an
address, but from your other post I know that you use "value" to mean
"expression", so perhaps by the above statement you mean "...expressions
of pointer type are usually also called pointer". So you would mean that
if we have a variable "a" then we can say that &a is a pointer. I suppose
that that usage is OK - it's probably down to personal preference.
BTW - arrays and pointers are different for multu-dimension arrays.
Imagine:

int Array[10][5];

- and please tell me what will be the type of

Array[1]

expression? Yes, the type will be "array of 5 integers", which is
different from "int *" - it is indexed in a different way.

What do you mean by this? I don't know of any situation where an array of
5 integers and a pointer to int would be indexed differently.
 
C

Christian Kandeler

Joe said:
No. A pointer is a variable which can hold the address of another
variable. You know that, right? It's in every C book you've ever read.
Really! Some people refer to the value of an address and call that value
a 'pointer' but they misuse the term.

These people must have written the Standard, then. In the definition of the
address operator, it says:
"[T]he result is a pointer to the object or function designated by its
operand".
Now what?


Christian
 
L

Lawrence Kirby

Lawrence Kirby wrote:
....
But this is an important example of where that is not the case. In
const int (*p)[5] p is already a pointer, it cannot "decay" further.

in declaration like const int (*p)[5] it declares only type for p it
really doesnt decay anything

Right, any "decay" happens in usage not declaration. For example

int a[10];
int *pa;

pa = a;


Here a is an array which is concerted to a pointer to its first element
for the assignment (the "decay"). There is nothing equivalent for p since
it is already a pointer, i.e. nothing that converts int (*)[5] to int **,
which would make no sense anyway.

Lawrence
 
A

Andrey Tarasevich

Maxim said:
Actually a pointer is neither a value nor a variable but a type; the word
is commonly used to refer to a variable with pointer type though, and this

Yes, and the value of the pointer type is also called "pointer" usually.

BTW - arrays and pointers are different for multu-dimension arrays. Imagine:

int Array[10][5];

- and please tell me what will be the type of

Array[1]

expression? Yes, the type will be "array of 5 integers", which is different
from "int *" - it is indexed in a different way.

It is not "indexed in a different way". All arrays, single- or
multi-dimensional, are indexed in exactly the same way. If you have an array 'a'
of type 'T[N]', in expression 'a' array type will decay to pointer type 'T*'
and then the actual "indexing" will be applied to the resultant pointer.

For example, for an array declared as

int Array1[10];

the type of 'Array1' is 'int[10]', but in expression

Array1[5]

the type of 'Array1' will decay to 'int*' and then the usual pointer arithmetic
is applied ('*(Array1 + 5)'), giving us the 'int' we are looking for.

In your example with two-dimensional array the situation is essentially the
same. Two-dimensional array in C is noting more than just an array of arrays.
The rest just follows from that fact. The type of 'Array' is 'int[10][5]' which
decays to 'int(*)[5]' and the first index ('[1]') is applied to the resultant
pointer. The result of 'Array[1]' has type 'int[5]', as you correctly noted
above. Now, if you apply another index, 'int[5]' will decay to 'int*' and so on...

I don't see what here "is indexed in different way". Quite the opposite,
everything is indexed in exactly the same way.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,780
Messages
2,569,608
Members
45,247
Latest member
crypto tax software1

Latest Threads

Top