473,503 Members | 11,735 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

gcc: pointer to array

Hi all,

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 aInt2[6] = {0,1,2,4,9,16};
int aInt3[5] = {0,1,2,4,9};

void print1 (const int* p, size_t cnt)
{
while (cnt--)
printf ("%d\n", *p++);
}

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

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

print1 (aInt2, sizeof(aInt2)/sizeof(aInt2[0]));
print2 (&aInt3); // <-- warns here

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

The warning is:
MOD.c: In function `main':
MOD.c:: warning: passing arg 1 of `print2' from incompatible pointer type

Why is that? How is this different from using print1 (aInt2, ...)? All I
want to do is to explicitly show that the pointer is to an array of 5
entries and ensure that it's not modified in anyway inside print2(). However
the #if 0'd assignment operator inside print2() is correctly handled by
gcc -- an error is generated:
MOD.c: In function `print2':
MOD.c:: error: assignment of read-only location
What's wrong with gcc?

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.
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...
Is this OK???

Thanks,
Alex
P.S. I compile it as gcc MOD.c -Wall -oMOD.exe
Nov 15 '05
204 12889
On Wed, 13 Jul 2005 05:44:20 +1000, Netocrat wrote:
On Mon, 11 Jul 2005 21:33:32 +0400, Maxim S. Shatskih wrote:
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.


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?
absurd - a pointer to an array is much more than just an address.


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.
doubt that you mean that. Generally a pointer is a variable...


Pointer is a value. Value != variable.


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.
You still haven't explained why you disagree with my statement that a
pointer to an array is double indirection.


Nov 15 '05 #51
Maxim S. Shatskih wrote:
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.

--
Joe Wright
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---
Nov 15 '05 #52
> > 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.

--
Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
ma***@storagecraft.com
http://www.storagecraft.com
Nov 15 '05 #53
On Tue, 12 Jul 2005 18:52:56 -0400, Joe Wright wrote:
Maxim S. Shatskih wrote:
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".

Nov 15 '05 #54
On Wed, 13 Jul 2005 04:04:50 +0400, Maxim S. Shatskih wrote:
> 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. :)


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.

Nov 15 '05 #55
> 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.

--
Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
ma***@storagecraft.com
http://www.storagecraft.com
Nov 15 '05 #56
On Wed, 13 Jul 2005 05:22:06 +0400, Maxim S. Shatskih wrote:
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.


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.

Nov 15 '05 #57
Joe Wright wrote:
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.


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

Nov 15 '05 #58
On Mon, 11 Jul 2005 23:33:05 +0300, Tommi Johnsson wrote:
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
Nov 15 '05 #59
On Mon, 11 Jul 2005 19:37:33 +0100, Chris Croughton wrote:
On 11 Jul 2005 17:35:54 GMT, Chris Torek
<no****@torek.net> wrote:
[Given "int arr[N];" and considering "&arr" vs "&arr[0]")
It is important to be clear that &arr and &arr[0] are fundamentally
different things. The only sense in which they are equal is that they
point to (different) objects that share the same starting byte, i.e.
(char *)&arr == (char *)&arr[0]. One points at an int, another points at
an array, so saying they are the same makes as much sense as given:

struct {
int a;
long b;
double c;
} s;

saying that &s is the same as &s.a. And before you say anything, it isn't.
:-) One is a pointer to an int, the other is a pointer to a struct. That
makes them very different.
I think the real question boils down to whether &arr and &arr[0]
will compare equal under *all* "well-defined" conversions
The point is that they can't be compared directly. Pointer conversions are
a nasty business, once you've converted to a different pointer type you
can't really say that you're comparing the original value.
-- 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.

If you want to say that they point to objects sharing the same starting
byte address then say that, don't say that the pointers are the same. One
property of a pointer doesn't define the whole thing.
Is that actually defined by the standard? I remember that in some
pre-standard C compilers arrays were actually implemented as pointers,
so int arr[5]; would actually expand to the equivalent in
pseudo-assember:

arr: dw &_arr
_arr: dw ?[5]

(The array pointer itself might be declared in a read-only segment.)

Is this sort of expansion actually banned by the standard, or is it
"just not the done thing"?
The compiler can do whatever magic it likes so long as the program behaves
correctly. In standard C a array doesn't define a separate pointer object
so they must behave as if they don't. That goes for dynamically allocated
arrays and arrays of arrays too.
In those compilers the effect would be the same as happens with "array
parameters", taking &arr would get you the address of the pointer.


There is no such pointer object in standard C so that is not a valid
implementation. &arr gives a result of type pointer to array, not pointer
to pointer.

Lawrence
Nov 15 '05 #60
Maxim S. Shatskih wrote:
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[i]' 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.

--
Best regards,
Andrey Tarasevich
Nov 15 '05 #61
> 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.


int Array[10][5];
int** Ptr;

Array[2][3] is evaluated as *( Array + 2 * 5 + 3 )
Ptr[2][3] is evaluated as *( *( Ptr + 2 ) + 3 ) - double indirection

So, a[i][j] is evaluated differently, depending on whether a is a pointer or an
array.

--
Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
ma***@storagecraft.com
http://www.storagecraft.com
Nov 15 '05 #62
Maxim S. Shatskih wrote:
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.


int Array[10][5];
int** Ptr;

Array[2][3] is evaluated as *( Array + 2 * 5 + 3 )
Ptr[2][3] is evaluated as *( *( Ptr + 2 ) + 3 ) - double indirection

So, a[i][j] is evaluated differently, depending on whether a is a pointer or an
array.


Well, strictly speaking, the former is also evaluated as

*( *( Array + 2 ) + 3 )

At purely syntactical level, the similarity between the two is still there.

The difference in terms of the "total number of indirections" exists for a
completely different reason. Take, for example, just the inner part - '*(Array +
2)'. There appears to be an indirection here. However, consider how this
expression is really interpreted: 'Array' decays from 'int[10][5]' to 'int
(*)[5]' (i.e. an implicit pointer is introduced), then 2 is added to that
pointer and then the pointer is dereferenced by '*' operator. In practice this
indirection is purely conceptual - we create a temporary pointer and then
almost immediately dereference it. For this reason, there's no need to generate
any code that will implement any actual indirection here.

In case of 'Ptr' the situation is substantially different. The same inner
subexpression - '*(Ptr + 2)' - has a different meaning in this case. It does
indeed require an "explicit" indirection, i.e. the compiler is required to
generate code that will retrieve the pointer value stored in memory location
pointed by 'Ptr + 2'.

--
Best regards,
Andrey Tarasevich
Nov 15 '05 #63
Alexei A. Frounze wrote:

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.
...


Which means C's types are wrong since the T that is an array is treated
differently from T that is not.


Yes, it is indeed treated differently.
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.


That's true. "Hiding" an array type behind a typedef-name does not make it to
loose its second-class-citizen properties. It doesn't become assignable, it
doesn't become const-qualifyable as a whole. That's just the way it is in C.

--
Best regards,
Andrey Tarasevich
Nov 15 '05 #64
On Thu, 14 Jul 2005 01:30:41 +0400, Maxim S. Shatskih wrote:
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.


int Array[10][5];
int** Ptr;

Array[2][3] is evaluated as *( Array + 2 * 5 + 3 ) Ptr[2][3] is evaluated
as *( *( Ptr + 2 ) + 3 ) - double indirection

So, a[i][j] is evaluated differently, depending on whether a is a pointer
or an array.


Agreed, but your wording implied 1-dimensional arrays, not 2-dimensional
arrays.
Nov 15 '05 #65
"Netocrat" <ne******@dodo.com.au> wrote in message
news:pa****************************@dodo.com.au...
On Tue, 12 Jul 2005 10:32:10 +0400, Alexei A. Frounze wrote:
"Netocrat" <ne******@dodo.com.au> wrote in message
news:pa****************************@dodo.com.au...
On Mon, 11 Jul 2005 09:29:27 +1000, Netocrat wrote:

> [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.


The thing about the base address is that I can use any index/offset to get
outside the allowed memory region, be it array or a pointer, I can simply
write:
ptr[123456] = 0; or
arr[-987654] = 1;
whatever. C will let me shoot in the foot :) As I showed, gcc doesn't warn
about writing past the array's last element. At least, it did not do so with
the -Wall option, which I normally use.
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].


Yep.
Nevertheless in C it is prohibited. C'est la vie.
Sh!t.
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.
Well, there used to be a lot of nonstandard (not yet standardized) features,
among which // is more or less harmless. I do not know many good compilers
that do not support // but nevertheless are of some good value to the
developers.
But let's not get away from the topic for now.
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.


Well, I may not be expressing myself well in terms of C's jargon, but I hope
I write clearly enough to be understood even though I'm not speaking English
natively :)
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.


OK, how about:
const char* * const p
?
Would it be better than simply
const char** p
?

Sorry, I maybe talking nonsense at the moment... But if the dereferenced
character is protected by const (or is it not?), then I'm not sure of the
problem, the write/assignment should be prohibited.
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.


I cannot with arrays. :)

.... Now to respond to the message you posted elsewhere:

On Tue, 12 Jul 2005 11:06:33 +0400, Alexei A. Frounze wrote:
"Netocrat" <ne******@dodo.com.au> wrote in message
news:pa****************************@dodo.com.au... ...
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.


Doesn't matter whether you say pointer or array. We both see the same
problem with [const]char** and [const]int(*)[]. So, yes, we do have
different semantics... To me its more of an inconsistency. C is a great
language, but it really does have some problems and peculiarities someone
should be aware of (say, two ints are multipled, and the product is assigned
to a long. what a normal human being expects to get isn't something the
experienced programmer knows to get in reality).
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 */
Sure. Now I think what if I typdef or union the array with something else to
hide the array type... Would I still get the warning? Or would I get a
different one? Sure this is something stupid to do, but what the heck, since
we're into, there are maybe some posibilities :)
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.


Can you show *the bad* code, where this automatic pointer type conversion
(if considered to be fully allowed) yields something real nasty? I'm getting
lost...
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.


Maybe...
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.


I'm lost. That's it. :)
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."
I might missed that "Me" example you're referring to...
Wait! This one:
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 */
Shoot. I didn't read it with enough attention. I see it now.
But ... what a perverted mind one must have to do something like that!
Cetainly, that wasn't something I expected to see nor do myself!!! At least,
not now, having programmed in C for quite some years.
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.


A big thanks,
Alex
P.S. where was I when I saw that weird example, huh? :)
Nov 15 '05 #66
On Wed, 13 Jul 2005 17:03:40 +0100, Lawrence Kirby wrote:
On Mon, 11 Jul 2005 19:37:33 +0100, Chris Croughton wrote:
On 11 Jul 2005 17:35:54 GMT, Chris Torek
<no****@torek.net> wrote:
[Given "int arr[N];" and considering "&arr" vs "&arr[0]")
It is important to be clear that &arr and &arr[0] are fundamentally
different things. The only sense in which they are equal is that they
point to (different) objects that share the same starting byte, i.e. (char
*)&arr == (char *)&arr[0].
<snip further explanation>

Perhaps you missed Chris Torek's full post; because he made an identical
point to yours which the abbreviation quoted above omits.
I think the real question boils down to whether &arr and &arr[0] will
compare equal under *all* "well-defined" conversions


<snip>
If you want to say that they point to objects sharing the same starting
byte address then say that, don't say that the pointers are the same.
One property of a pointer doesn't define the whole thing.
<snip>
The compiler can do whatever magic it likes so long as the program
behaves correctly. In standard C a array doesn't define a separate
pointer object so they must behave as if they don't. That goes for
dynamically allocated arrays and arrays of arrays too.


So to clarify, would you agree with the assertions that given the
declaration int arr[10];

a) &arr and &arr[0] are required by the standard to always point to
objects sharing the same starting byte address

b) the values of &arr and &arr[0], provided that they can be cast to
equivalent pointer types with no loss of information, are required by the
standard to always be equal?

Nov 15 '05 #67
On Thu, 14 Jul 2005 04:48:24 +0400, Alexei A. Frounze wrote:

<snip>
The thing about the base address is that I can use any index/offset to get
outside the allowed memory region, be it array or a pointer, I can simply
write:
ptr[123456] = 0; or
arr[-987654] = 1;
whatever. C will let me shoot in the foot :) As I showed, gcc doesn't warn
about writing past the array's last element. At least, it did not do so
with the -Wall option, which I normally use.
I agree that it is reasonable to expect that the -Wall option of gcc
should warn about obvious cases where a constant index exceeds the array
bounds. In the case where you have assigned the array to a pointer it
isn't so obvious and I wouldn't expect it, but it would be a nice bonus.
Probably a tool such as lint would provide this capability.

<snip>
C is a great
language, but it really does have some problems and peculiarities
someone should be aware of (say, two ints are multipled, and the product
is assigned to a long. what a normal human being expects to get isn't
something the experienced programmer knows to get in reality).
Agreed - casting requirements aren't immediately obvious as a C beginner.
Once you understand the paradigm they are - except for a few intricacies
like the case in point, which are not straightforward.

<snip>
Sure. Now I think what if I typdef or union the array with something
else to hide the array type... Would I still get the warning? Or would I
get a different one? Sure this is something stupid to do, but what the
heck, since we're into, there are maybe some posibilities :)
You could place it as the only element of a struct. I don't see any
advantage of a union over a struct. Then if you wanated to you could
typedef the struct so that declaring the array is simpler (many frown on
hiding structs with typedef when it's not strictly necessary with good
reason, but it's personal preference in the end). It's a workaround but
it will achieve what you want; with the proviso that your array must be of
constant size unless you use C99 - otherwise you will need a separate
structure type for each array size.

<snip>
I might missed that "Me" example you're referring to... Wait! This one:
[...] Shoot. I didn't read it with enough attention. I see it now. But
... what a perverted mind one must have to do something like that!
Cetainly, that wasn't something I expected to see nor do myself!!! At
least, not now, having programmed in C for quite some years.
Yes it's subtle - creatively perverted.

<snip>
where was I when I saw that weird example, huh? :)


In the same place we go when we read several pages of a novel that
directly afterwards we can't remember anything from.

Nov 15 '05 #68
> Agreed - casting requirements aren't immediately obvious as a C beginner.

With "const", all is clear. The "const" attribute of the lvalue cannot be
removed without the explicit cast - neither in C nor on C++.

--
Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
ma***@storagecraft.com
http://www.storagecraft.com
Nov 15 '05 #69
"Maxim S. Shatskih" <ma***@storagecraft.com> writes:
With "const", all is clear. The "const" attribute of the lvalue cannot be
removed without the explicit cast - neither in C nor on C++.


Sure it can--try calling a function like strchr().
--
int main(void){char p[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv wxyz.\
\n",*q="kl BIcNBFr.NKEzjwCIxNJC";int i=sizeof p/2;char *strchr();int putchar(\
);while(*q){i+=strchr(p,*q++)-p;if(i>=(int)sizeof p)i-=sizeof p-1;putchar(p[i]\
);}return 0;}
Nov 15 '05 #70
Ben Pfaff wrote:
"Maxim S. Shatskih" <ma***@storagecraft.com> writes:
With "const", all is clear. The "const" attribute of the lvalue cannot be
removed without the explicit cast - neither in C nor on C++.


Sure it can--try calling a function like strchr().


Or just...

char *foo();

void bah(const char *x)
{
char *y = foo(x);
...
}

char *foo(char *x)
{
return x;
}

--
Peter

Nov 15 '05 #71
On Wed, 13 Jul 2005 23:17:57 -0700, Peter Nilsson wrote:
Ben Pfaff wrote:
"Maxim S. Shatskih" <ma***@storagecraft.com> writes:
> With "const", all is clear. The "const" attribute of the lvalue cannot
> be removed without the explicit cast - neither in C nor on C++.


Sure it can--try calling a function like strchr().


Or just...

char *foo();

void bah(const char *x)
{
char *y = foo(x);
...
}
}
char *foo(char *x)
{
return x;
}


Neither of these examples removes a const attribute from an lvalue, which
is impossible by definition. An lvalue can be assigned to. If it had a
const attribute that was to be removed, you couldn't assign to it and it
wouldn't be an lvalue in the first place.

I believe though that you've correctly interpreted what Maxim meant as
opposed to what actually said.

Nov 15 '05 #72
> > char *foo();

Oh, sorry. The only language for which I've read the formal description was C++
(old one - circa 1993) and not C. In C++, such things are impossible.

--
Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
ma***@storagecraft.com
http://www.storagecraft.com
Nov 15 '05 #73
Andrey Tarasevich wrote:
It is not "indexed in a different way". All arrays, single- or
multi-dimensional, are indexed in exactly the same way.


Nope, they're not. The equivalence stops at one-dimensional arrays.
Multidimensional arrays aren't addressed the same way as
multi-indirectioned (sp?) pointers.

That is to say, int foo[10][20] doesn't decay to int **.

Multi-dimensional arrays store all of their elements consecutively, the
single elements are accessed by means of pointer math on the dimensions
and size of the elements, whilst multi-indirectioned pointers are simply
pointers (to pointers... to pointers) to the elements:
int foo[3][3] :

+--+--+--+
| | | |
+--+--+--+
| | | |
+--+--+--+
| | | |
+--+--+--+

int **baz :

+--+--+--+ ...
| | | | ...
+--+--+--+ ...
|| || ||
\/ \/ \/
+--+--+--+
| + + |
+--+--+--+
| + + |
+--+--+--+
| + + |
+--+--+--+
...........
...........
...........
--
Fabio Alemagna
Nov 15 '05 #74
On Thu, 14 Jul 2005 10:40:50 +0400, Maxim S. Shatskih wrote:
> char *foo();


Oh, sorry. The only language for which I've read the formal description
was C++ (old one - circa 1993) and not C. In C++, such things are
impossible.


Actually assuming you that by "lvalue" you meant "expression" what you
said was correct anyway. You said that the const attribute cannot be
removed from an expression without an explicit cast, which is true.

Looking again at the examples given by Ben Pfaff and Peter Nilsson,
they're showing the const attribute being added, rather than removed,
without an explicit cast.
Nov 15 '05 #75
Fabio Alemagna wrote:
It is not "indexed in a different way". All arrays, single- or
multi-dimensional, are indexed in exactly the same way.
Nope, they're not.


Yes, they are.
The equivalence stops at one-dimensional arrays.
Multidimensional arrays aren't addressed the same way as
multi-indirectioned (sp?) pointers.
That's true. But in my message I'm talking about the difference between
the way single- and multi-dimensional arrays are addressed. No pointers
involved (multi-indirectioned or not). You for some reason start talking
about pointers. Why?
That is to say, int foo[10][20] doesn't decay to int **.
That's true. But, once again, how is this relevant?
[skipped]


Once again, true. But I still don't see how all this applies to what I
said in my message.

--
Best regards,
Andrey Tarasevich

Nov 15 '05 #76
Netocrat wrote:
...
Neither of these examples removes a const attribute from an lvalue, which
is impossible by definition. An lvalue can be assigned to.
Huh? No. By definition, lvalue is something that has address in storage. In
general case lvalue cannot be assigned to. Only _modifyable_ lvalue can be
assigned to, but there are also non-modifyable lvalues.
If it had a
const attribute that was to be removed, you couldn't assign to it and it
wouldn't be an lvalue in the first place.


Not true. You seem to assume that assignability is a defining property of
"lvalueness". That's simply not true.

--
Best regards,
Andrey Tarasevich
Nov 15 '05 #77
On Thu, 14 Jul 2005 02:47:13 -0700, Andrey Tarasevich wrote:
Netocrat wrote:
...
Neither of these examples removes a const attribute from an lvalue, which
is impossible by definition. An lvalue can be assigned to.
Huh? No. By definition, lvalue is something that has address in storage. In
general case lvalue cannot be assigned to. Only _modifyable_ lvalue can be
assigned to, but there are also non-modifyable lvalues.


Right, my concept of lvalue was slightly out. Non-modifiable being for
example arrays and structs.

Maxim's original statement then is accurate:
With "const", all is clear. The "const" attribute of the lvalue cannot
be removed without the explicit cast - neither in C nor on C++.

If it had a
const attribute that was to be removed, you couldn't assign to it and it
wouldn't be an lvalue in the first place.


Not true. You seem to assume that assignability is a defining property of
"lvalueness". That's simply not true.


On reading the standard I see that you are correct.

Nov 15 '05 #78
Fabio Alemagna wrote:
Andrey Tarasevich wrote:
It is not "indexed in a different way". All arrays, single- or
multi-dimensional, are indexed in exactly the same way.


Nope, they're not. The equivalence stops at one-dimensional arrays.
Multidimensional arrays aren't addressed the same way as
multi-indirectioned (sp?) pointers.

That is to say, int foo[10][20] doesn't decay to int **.


Which is because there are no multi-dimensioned arrays in C, there
are just arrays of arrays. An array of pointers is not a
multidimensioned array, or even a fake of one linearized.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson

Nov 15 '05 #79
In comp.lang.c Peter Nilsson <ai***@acay.com.au> wrote:
char *foo();

void bah(const char *x)
{
char *y = foo(x);
You raise UB here: (const char*) and (char*) types are
not compatible - you cannot pass incompatible arguments
to a function call (cf. 6.5.2.2#6).
...
}

char *foo(char *x)
{
return x;
}


--
Stan Tobias
mailx `echo si***@FamOuS.BedBuG.pAlS.INVALID | sed s/[[:upper:]]//g`
Nov 15 '05 #80
In comp.lang.c Netocrat <ne******@dodo.com.au> wrote:
On Thu, 14 Jul 2005 02:47:13 -0700, Andrey Tarasevich wrote:
Netocrat wrote:
...
Neither of these examples removes a const attribute from an lvalue, which
is impossible by definition. An lvalue can be assigned to.


Huh? No. By definition, lvalue is something that has address in storage. In
general case lvalue cannot be assigned to. Only _modifyable_ lvalue can be
assigned to, but there are also non-modifyable lvalues.


Right, my concept of lvalue was slightly out. Non-modifiable being for
example arrays and structs.


I'm not sure it's that simple with storage for lvalues. Take `register'
variables for an example, or pointers to objects whose lifetime has
finished (dereferencing such a pointer is an lvalue, whether
the object exists or not).

Consider also this example:

struct s { int a[1]; };
struct s f(void);

f().a[0] = 7; //UB

The expression on the left is clearly a modifiable lvalue.
But does it take any storage? I think C++ is more verbose about
temporaries; they can be optimized out, which is unspecified.
I don't think C even has an idea of a temporary.

OTOH, f().a decays into a pointer to its first element, therefore
the array the pointer points to must be an object, therefore it
must (temporarily) take some storage. Is that a right conclusion?

--
Stan Tobias
mailx `echo si***@FamOuS.BedBuG.pAlS.INVALID | sed s/[[:upper:]]//g`
Nov 15 '05 #81
Netocrat <ne******@dodo.com.au> wrote:
On Thu, 14 Jul 2005 02:47:13 -0700, Andrey Tarasevich wrote:
Netocrat wrote:
...
Neither of these examples removes a const attribute from an lvalue, which
is impossible by definition. An lvalue can be assigned to.


Huh? No. By definition, lvalue is something that has address in storage. In
general case lvalue cannot be assigned to. Only _modifyable_ lvalue can be
assigned to, but there are also non-modifyable lvalues.


Right, my concept of lvalue was slightly out. Non-modifiable being for
example arrays and structs.


Nope, only arrays, not structs. Structs can be assigned to. (You might
be confusing this with the lack of struct constants in C89. This lack
means that, if you want to assign something to a struct, in must be
another struct; there's no such thing as i=4 for structs, only i=j. Or
perhaps by the possibility of structs being incomplete (see below); but
this isn't true for structs in general.)
Other non-modifiable lvalues are incomplete types (unfinished
variable-length arrays, declared but not yet defined structs, etc.),
const objects (no surprise there), or structs or unions with
non-modifiable members.

Richard
Nov 15 '05 #82
CBFalconer wrote:
That is to say, int foo[10][20] doesn't decay to int **.

Which is because there are no multi-dimensioned arrays in C,


Of course there are, you quoted one above.

--
Fabio Alemagna

http://xoomer.virgilio.it/scene_di_ordinaria_follia/
Nov 15 '05 #83
Andrey Tarasevich wrote:
The equivalence stops at one-dimensional arrays.
Multidimensional arrays aren't addressed the same way as
multi-indirectioned (sp?) pointers.

That's true. But in my message I'm talking about the difference between
the way single- and multi-dimensional arrays are addressed. No pointers
involved (multi-indirectioned or not). You for some reason start talking
about pointers. Why?


Want an honest answer? I have no idea, sorry :-| Dunno what the heck I
was thinking about :-)

--
Fabio Alemagna

http://xoomer.virgilio.it/scene_di_ordinaria_follia/
Nov 15 '05 #84
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Fabio Alemagna wrote:
CBFalconer wrote:
That is to say, int foo[10][20] doesn't decay to int **.


Which is because there are no multi-dimensioned arrays in C,

Of course there are, you quoted one above.


Nope. That's not a multi-dimensional array.

That's an array of 10 elements, each element being an array of 20 ints.

- --
Lew Pitcher
IT Specialist, Enterprise Data Systems,
Enterprise Technology Solutions, TD Bank Financial Group

(Opinions expressed are my own, not my employers')
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (MingW32)

iD8DBQFC1rT/agVFX4UWr64RAmMZAJ4kxJO5L13YdlEfpNylxup8GzOiAQCg0e TU
K9j0Yat8G0REQ52iU7GJ5QU=
=1ba/
-----END PGP SIGNATURE-----
Nov 15 '05 #85
Lew Pitcher wrote:

Which is because there are no multi-dimensioned arrays in C,

Of course there are, you quoted one above.


Nope. That's not a multi-dimensional array.

That's an array of 10 elements, each element being an array of 20 ints.
...


So? "Multi-dimensional array" is just a concept. There are different ways to
implement this concept. Can anyone please explain to me, why the C-language's
approach to multidimensional arrays does not qualify as a valid implementation
of that concept? I hear it again and again, but somehow nobody is ever able to
come up with a more-or-less rational basis for such statement.

--
Best regards,
Andrey Tarasevich
Nov 15 '05 #86
Lew Pitcher wrote:
That is to say, int foo[10][20] doesn't decay to int **.

Which is because there are no multi-dimensioned arrays in C,


Of course there are, you quoted one above.


Nope. That's not a multi-dimensional array.

That's an array of 10 elements, each element being an array of 20 ints.


Precisely, a multidimensional array.

--
Fabio Alemagna

http://xoomer.virgilio.it/scene_di_ordinaria_follia/
Nov 15 '05 #87
"Andrey Tarasevich" <an**************@hotmail.com> wrote in message
news:11*************@news.supernews.com...
Lew Pitcher wrote:


Guys, if there's nothing to add to my initial post (I think so as I have no
further questions on the subject), you may exclude alt.os.development from
the target.

Thanks,
Alex
Nov 15 '05 #88
Fabio Alemagna wrote:
Lew Pitcher wrote:
(and somebody foolishly stripped all the attributions)
> That is to say, int foo[10][20] doesn't decay to int **.

Which is because there are no multi-dimensioned arrays in C,

Of course there are, you quoted one above.


Nope. That's not a multi-dimensional array. That's an array of
10 elements, each element being an array of 20 ints.


Precisely, a multidimensional array.


No, it is an array of 200 ints, which can be mapped into an
array[10] of array[20] of int. It can also be mapped into an
array[20] of array[10], or array[2] of array[100], etc. The
notation is just a means of getting the compiler to do some of the
arithmetic for you, and the technique fails all too often,
especially when you don't understand what is going on.

The memory people have gone to a lot of trouble to present that
memory as a linear array. You wouldn't like it if you had to deal
with the reality, involving row and column strobes, chip selects,
etc. In the old days you also had to deal with inhibit current.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
Nov 15 '05 #89
S.Tobias wrote:
In comp.lang.c Peter Nilsson <ai***@acay.com.au> wrote:
char *foo();

void bah(const char *x)
{
char *y = foo(x);


You raise UB here: (const char*) and (char*) types are
not compatible - you cannot pass incompatible arguments
to a function call (cf. 6.5.2.2#6).


C99 has different wording from N869.

[It looks like it's not valid C90 though.]
...
}

char *foo(char *x)
{
return x;
}


--
Peter

Nov 15 '05 #90
CBFalconer wrote:
No, it is an array of 200 ints,
You can't change your definition each time you answer. Before you said
it's an array of an array, now you say it's just an array, 'cause that
suits your goal better now.
which can be mapped into an
array[10] of array[20] of int. It can also be mapped into an
array[20] of array[10], or array[2] of array[100], etc.
So what? That's an implementation detail. To make you happy the 2nd
dimension arrays should have been put where, exactly?
The
notation is just a means of getting the compiler to do some of the
arithmetic for you, and the technique fails all too often,
especially when you don't understand what is going on.
Please, can you give examples about such failures? I've never
encountered any.
The memory people have gone to a lot of trouble to present that
memory as a linear array. You wouldn't like it if you had to deal
with the reality, involving row and column strobes, chip selects,
etc. In the old days you also had to deal with inhibit current.


Hm? What's got that to do with multidimensional arrays in C?

Ok, let's do something constructive: please, explain what would be a
"real" multidimensional array.
--
Fabio Alemagna

http://xoomer.virgilio.it/scene_di_ordinaria_follia/
Nov 15 '05 #91
On Thu, 14 Jul 2005 20:07:23 +0000, Fabio Alemagna wrote:
Lew Pitcher wrote:
>That is to say, int foo[10][20] doesn't decay to int **.

Which is because there are no multi-dimensioned arrays in C,

Of course there are, you quoted one above.


Nope. That's not a multi-dimensional array.

That's an array of 10 elements, each element being an array of 20 ints.


Precisely, a multidimensional array.


This is easily settled by the standard.

N869, 6.7.5.2:

When several ``array of'' specifications are adjacent, a multidimensional
array is declared.

There's similar language in the C89 draft.

Nov 15 '05 #92
On Thu, 14 Jul 2005 13:39:16 +0000, S.Tobias wrote:
In comp.lang.c Netocrat <ne******@dodo.com.au> wrote:
On Thu, 14 Jul 2005 02:47:13 -0700, Andrey Tarasevich wrote:
Netocrat wrote: ...
Neither of these examples removes a const attribute from an lvalue, which
is impossible by definition. An lvalue can be assigned to.

Huh? No. By definition, lvalue is something that has address in storage. In
general case lvalue cannot be assigned to. Only _modifyable_ lvalue can be
assigned to, but there are also non-modifyable lvalues.
Right, my concept of lvalue was slightly out. Non-modifiable being for
example arrays and structs.


I'm not sure it's that simple with storage for lvalues. Take `register'
variables for an example, or pointers to objects whose lifetime has
finished (dereferencing such a pointer is an lvalue, whether the object
exists or not).


The C89 draft says:

"The unary * operator denotes indirection. If the operand points to ... an
object, the result is an lvalue designating the object... If an invalid
value has been assigned to the pointer, the behavior of the unary *
operator is undefined."

Since in this case the pointer has an invalid value it would be illegal to
dereference it; the question of whether or not the result would be an
lvalue is moot.
Consider also this example:

struct s { int a[1]; };
struct s f(void);

f().a[0] = 7; //UB

The expression on the left is clearly a modifiable lvalue.
Not so clearly according to gcc. I get:
"ISO C90 forbids subscripting non-lvalue array".
But does it take any storage? I think C++ is more verbose about
temporaries; they can be optimized out, which is unspecified.
I don't think C even has an idea of a temporary.
It doesn't occur in the context of variable storage in either draft.
OTOH, f().a decays into a pointer to its first element, therefore
the array the pointer points to must be an object, therefore it
must (temporarily) take some storage. Is that a right conclusion?


If f() were a modifiable lvalue which in this context it does not appear
to be, then I would see nothing wrong with your reasoning. However given
that there's no means of later reading back the assignment, it's really a
no-op and again the question is moot: nothing changes whether the
assignment occurs or not. Perhaps that's why C99 allows it.

Nov 15 '05 #93
On Thu, 14 Jul 2005 15:03:21 +0000, Richard Bos wrote:
Netocrat <ne******@dodo.com.au> wrote:
On Thu, 14 Jul 2005 02:47:13 -0700, Andrey Tarasevich wrote:
> Netocrat wrote:
>> ...
>> Neither of these examples removes a const attribute from an lvalue, which
>> is impossible by definition. An lvalue can be assigned to.
>
> Huh? No. By definition, lvalue is something that has address in storage. In
> general case lvalue cannot be assigned to. Only _modifyable_ lvalue can be
> assigned to, but there are also non-modifyable lvalues.
Right, my concept of lvalue was slightly out. Non-modifiable being for
example arrays and structs.


Nope, only arrays, not structs. Structs can be assigned to. (You might
be confusing this with the lack of struct constants in C89.


It was thoughtlessness rather than confusion, but see below.
This lack
means that, if you want to assign something to a struct, in must be
another struct; there's no such thing as i=4 for structs, only i=j.
You seem to imply that something similar to i=4 where i is a struct is
possible in C99, which I haven't come across before.
Or
perhaps by the possibility of structs being incomplete (see below); but
this isn't true for structs in general.)
Other non-modifiable lvalues are incomplete types (unfinished
variable-length arrays, declared but not yet defined structs, etc.),


I'm with you on all of those bar the last. Surely by the time you attempt
to access a struct variable as an lvalue, the struct must have been
defined?

<snip>

Nov 15 '05 #94
The problem is that array itself is a pointer to it's beginning so then
writing &aInt3 would give you pointer to pointer to an array. Solution
is to pass only aInt3 to your function.

Another thing is that const modifier. It tells you that this function
is not going to change received pointer i.e. set it to another array.
And after a function call it will point to the same thing it was
pointing befeore the call.

Nov 15 '05 #95
[Followups set to comp.lang.c]

Lukaszp wrote:
The problem is that array itself is a pointer to it's beginning so then
Not quite. The array itself is an array. The /value/ of the array, when that
array's name is used in a value context, is the address of the first
element.
writing &aInt3 would give you pointer to pointer to an array. Solution
is to pass only aInt3 to your function.


The declaration in question was:

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

When you write &aInt3, you're actually getting the address of the array (the
array is not being used in a value context here); the type is int (*)[5],
i.e. a pointer to an array, not a pointer to a pointer to an array as you
incorrectly claimed. (This is a tricky area - it's intensely logical, but
C's logic doesn't always map perfectly to programmers' first-cut instinct!)

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
mail: rjh at above domain
Nov 15 '05 #96
Ok. Thanks. did i have right with the const modifier?

Nov 15 '05 #97
Richard Heathfield wrote:
The /value/ of the array, when that
array's name is used in a value context, is the address of the first
element.


I see you have the word /value/ highlighted.

Operations which result in pointers to the operand,
don't operate on the value of the operand.

The value of &i doesn't depend on the value of i.

The value of (array + 0) doesn't depend on the contents of the array,
though I'll admit I can't recall any consensus as to what,
if anything, "value" means when applied to an array.

--
pete
Nov 15 '05 #98
Lukaszp wrote:
Ok. Thanks. did i have right with the const modifier?


Funny you should mention that. No, you didn't have it right. :-(

Sorry, but that's life. const int (*p)[5] means "pointer to array of 5 const
ints", not "const pointer to array of 5 ints".

Apologies for not noticing that in my first reply.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
mail: rjh at above domain
Nov 15 '05 #99
pete wrote:
Richard Heathfield wrote:
The /value/ of the array, when that
array's name is used in a value context, is the address of the first
element.
I see you have the word /value/ highlighted.


Correct.

Operations which result in pointers to the operand,
don't operate on the value of the operand.
Correct as far as I can see, without spilling ISO ketchup all over the
thread.

The value of &i doesn't depend on the value of i.
Correct, although of course the value of i can depend on &i in at least one
case.
The value of (array + 0) doesn't depend on the contents of the array,
though I'll admit I can't recall any consensus as to what,
if anything, "value" means when applied to an array.


It's The Rule, a la CT. In a value context, the name of an array decays to a
pointer to the first element of that array. So, effectively, the value of
an array is a pointer to its first element, n'est-ce-pas?

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
mail: rjh at above domain
Nov 15 '05 #100

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

8
4425
by: pemo | last post by:
I've just been trying out the Watcom compiler from http://www.openwatcom.org, and almost immediately compiled some working source that errored. The code is char buffer; ...
34
3608
by: thibault.langlois | last post by:
Hello, I get a warning when I compile: #include <string.h> int main (int argc, char ** argv) { char * s; s = strdup("a string"); return 0; }
7
2131
by: vippstar | last post by:
Today I got a confusing message from gcc (I'm aware, those don't break conformance ;-) In function 'main': 7: warning: format '%d' expects type 'int', but argument 2 has type 'char (*)' The...
0
7098
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
7364
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
1
7017
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
7470
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
5604
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
4696
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...
0
3174
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
751
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
0
405
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.