Martin Jørgensen said:
Keith said:
The declaration
int ar2[3][2];
declares ar2 as an array[3] of array[2] of int. The memory allocated
for it is enough to hold 3*2 int objects (6 * sizeof(int)). The name
ar2, in most contexts, decays to a pointer to array[2] of int; this
is a pointer value, not a pointer object.
Thanks a lot... I just have to make sure: What exactly do you mean by:
1) Pointer value
2) Pointer object
What's the difference? C isn't "object-oriented" as in C++ so I just
want to make sure I understand the difference...
Right, the term "object" in C has nothing to do with "object-oriented"
anything. The standard's definition of "object" is a "region of data
storage in the execution environment, the contents of which can
represent values" (C99 3.14).
Loosely speaking, it's nearly the same thing as a variable. An object
can also be a component of another object, or the chunk of memory
allocated by malloc(). (The standard doesn't define the term
"variable".)
A value is the result of evaluating an expression. It isn't
necessarily stored anywhere; it's a transient thing that exists only
while the expression is being evaluated, unless it's stored in an
object.
An object name is an expression; the value of the expression is the
value that was stored in the object.
A pointer object is an object of pointer type; the value of a pointer
object is a pointer value, also known as an address.
(There's some controversy in this area. Some people feel strongly
that the unadorned word "pointer" should refer only to a pointer
object, never to a value -- but the standard, like it or not, talks
about functions returning pointers. I usually try to avoid the issue
by referring explicitly to pointer objects and pointer values.)
[...]
In
pa = ar2;
pa is of type pointer to array[3] of int, and ar2 is of type array[3]
of array[2] of int, which decays to pointer to array[2] of int.
Sounds to me like: I've read something about that there is a
similarity between declaring array[3][2] and declaring array[][2] in a
function header...
Is that what you mean by "decaying into"?
No, that's something different (but related, I suppose).
A function can't have a parameter of array type. You can declare
something that *looks* like an array parameter:
void foo(char param[]);
but, because of a special-case rule, that's exactly the same as:
void foo(char *param);
The same is true if you specify the length of the aray:
void foo(char param[42]);
The length is just quietly ignored.
The intent of the rule is to allow you to indicate that the argument
is expected to be an array (which will decay to a pointer), but in my
opinion this rule causes more problems than it solves.
Your example:
void bar(int array[3][2]);
vs.
void bar(int array[][2]);
is just a special case of this, where the array's element type happens
to be another array type.
But when I used the phrase "decaying into", I was referring to the
implicit conversion of array expressions to pointer type.
In most contexts, an expression of array type (such as the name of a
declared array object) is implicitly converted to a pointer to the
array's first element. The exceptions are: (1) the argument to the
"sizeof" operator, (2) the argument to the "&" operator, and (3) a
string literal used in an initialize an array.
It's only the column-size that must match, isn't it?
In this case, yes (of course the element type must match as well).
But a better way to think about it is that the types must match, after
any implicit conversions have been applied. A two-dimensional array
is just an array of arrays. There are no special rules for
multi-dimensional arrays; their behavior is determined entirely by the
rules for one-dimensional arrays, including implicit conversions to
pointers.