scope of function parameters

B

BartC

Ben Bacarisse said:
void iadd(int a[],int b) {

There's no array here. I agree that it's confusing to people learning
C, but the confusing thing is that 'a' is not an array. It's the fact
that an array is *not* involved that is confusing.

What gets passed is a pointer to an int; you're right there's no array
involved. But in that case, what's going on here:

Is this array subscripting, or just updating a pointer target?

How about this example:

int main(int argc, char *argv[]) ...

Here, argv is presumably a pointer to pointer to char; no array in sight
here either (other than the suspiciously array-like "[]" syntax!).

Yet a few lines further on in my C standard, it talks about "...the array
members argv[0] through argv[argc-1]..." (5.1.2.2.2). What array?!
 
J

James Kuyper

Ben Bacarisse said:
void iadd(int a[],int b) {

There's no array here. I agree that it's confusing to people learning
C, but the confusing thing is that 'a' is not an array. It's the fact
that an array is *not* involved that is confusing.

What gets passed is a pointer to an int; you're right there's no array
involved. But in that case, what's going on here:

Is this array subscripting, or just updating a pointer target?

The latter; a[0] += b is, by definition, equivalent to

*(a+0) = *(a+0) + b;
How about this example:

int main(int argc, char *argv[]) ...

Here, argv is presumably a pointer to pointer to char; no array in sight
here either (other than the suspiciously array-like "[]" syntax!).

Yet a few lines further on in my C standard, it talks about "...the array
members argv[0] through argv[argc-1]..." (5.1.2.2.2). What array?!

The array whose first member is pointed at by argv. argv is not an
array, but there is one that it points into.

An lvalue of array type is, in most contexts, automatically converted to
a pointer to the first element of an array (sizeof and & are the two
relevant exceptions). As as a result, in precisely those same contexts,
a pointer to the first element of an array can be used just as if it
were an array.
 
B

BartC

James Kuyper said:
On 02/07/2013 05:37 PM, BartC wrote:
int main(int argc, char *argv[]) ...

Here, argv is presumably a pointer to pointer to char; no array in sight
here either (other than the suspiciously array-like "[]" syntax!).

Yet a few lines further on in my C standard, it talks about "...the array
members argv[0] through argv[argc-1]..." (5.1.2.2.2). What array?!

The array whose first member is pointed at by argv. argv is not an
array, but there is one that it points into.

It that just an *assumption* (that argv does in fact point to an array, and
not perhaps a struct with argc members), or is main() a special case, where
it is *known* that argv points to the start of an array? (Despite being
pretty much the only function where you can't know!)

If any pointer passed to a function might be assumed to point to the start
of an array, then it seems to me that you can also assume that a reference
to that array has been passed.
 
S

Shao Miller

Shao Miller said:
On 2/5/2013 04:09, Esash wrote:
The two are _separate_. The called function can modify its parameters
and those modifications _do_not_ modify the caller's arguments.
... As another example:

void bar(void) {
int i = 21;
int j = 21;
int x = add(i, j);
}

Your 'add' function above cannot modify the arguments 'i' and 'j'. It
can only modify its parameters 'a' and 'b'.

It gets a bit more confusing when arrays are involved:

void iadd(int a[],int b) {
a[0]+=b;
}

I think you meant "It gets a bit more confusing when parameter
declarations appear to declare arrays". For a beginner, one of the
hurdles in C is that array declarators for function parameters actually
declare pointers. For this reason, I recommend avoiding array
declarators in function parameters altogether, unless one requires the
= C99 conveniences (like 'static'), in which case one is probably not
a beginner to C.
int main (void) {
int x[]={10,20,30};

iadd (x,1);
}

Here, the caller's 'x' argument *is* apparently modified. In fact, an
array can *only* be passed by reference.

Well that might add to the confusion. In 'main', the 'x' array object
isn't an argument, and 'iadd' doesn't modify its arguments (nor does any
C function access its caller's arguments). One thing that can be said
is that the 'x' lvalue is not the same as the value of the expression
'x'. Lvalue conversion and "array decay" are side-by-side concepts that
can be challenging for a beginner to grasp, but the sooner done, the better.

I like to imagine an "evaluation pass". Given (in a function):

int x[] = { 10, 20, 30 };
int y = 13;
int z = 42;

foo(x, y, z, bar());

I imagine an "evaluation pass" resulting in:

foo(pointer to first element of x, 13, 42, result of call to bar);

These more accurately describe the arguments to 'foo'. We can see that
all of the originals are, after some evaluation has happened, _not_
arguments to 'foo'. In normal discussion, we might say that they are,
but this can contribute to beginners' confusion.

There is another confusing case that's similar to "array decay", and
that's "function decay", which explains the difference between these two
lines:

int sz = sizeof main;
int sz = sizeof (0, main);

In the latter, 'main' "decays" to a function pointer, just as array
expressions decay to object pointers. And, just like array expressions,
this same decay happens when 'main' appears to be an argument in a
function call. There is again a similar relationship to arrays for
function parameters: A function parameter declarator that itself appears
to declare a function actually declares a function pointer parameter.

I seem to recall another comp.lang.c post referencing "Haddocks' Eyes":

http://en.wikipedia.org/wiki/Haddocks'_Eyes#Naming

The argument is called 'x', but the argument is a pointer to the first
element of 'x'. :)
 
J

James Kuyper

James Kuyper said:
On 02/07/2013 05:37 PM, BartC wrote:
int main(int argc, char *argv[]) ...

Here, argv is presumably a pointer to pointer to char; no array in sight
here either (other than the suspiciously array-like "[]" syntax!).

Yet a few lines further on in my C standard, it talks about "...the array
members argv[0] through argv[argc-1]..." (5.1.2.2.2). What array?!

The array whose first member is pointed at by argv. argv is not an
array, but there is one that it points into.

It that just an *assumption* (that argv does in fact point to an array, and
not perhaps a struct with argc members), or is main() a special case, where
it is *known* that argv points to the start of an array?

The standard requires that the implementation do whatever it needs to do
to make argv work, as described by the standard, for any value of i
from 0 to argc, inclusive. If the code that calls main() were strictly
conforming C code, that would be pretty closely equivalent to requiring
that argv point into an array - though it need not point to the first
element of that array, and argv+argc need not point at the last element
of that array. In that case, if argc == 0, then argv could point at a
single char* object, which the standard allows to be treated as an array
of length one. I can't come up with any plausible reason for an
implementation to do that, but it would be permitted.

However, the standard doesn't even require that the caller of main be
written in C code, much less strictly conforming C code, so there's no
way to even make the question meaningful. However, what it does say is,
for all practical purposes (such as understanding how to use argv, or
how to write recursive calls to main()), equivalent to requiring that
argv point into an array.

....
If any pointer passed to a function might be assumed to point to the start
of an array, then it seems to me that you can also assume that a reference
to that array has been passed.

Since C doesn't define any mechanism whereby a reference to an array
could be passed to a function, that assumption would lead to the
conclusion that the program has undefined behavior. That doesn't seem
like a useful assumption to make.
 
S

Shao Miller

James Kuyper said:
On 02/07/2013 05:37 PM, BartC wrote:
int main(int argc, char *argv[]) ...

I'd suggest avoiding that and using:

int main(int argc, char ** argv)
Here, argv is presumably a pointer to pointer to char; no array in sight
here either (other than the suspiciously array-like "[]" syntax!).

Yet a few lines further on in my C standard, it talks about "...the
array
members argv[0] through argv[argc-1]..." (5.1.2.2.2). What array?!

The array whose first member is pointed at by argv. argv is not an
array, but there is one that it points into.

It that just an *assumption* (that argv does in fact point to an array,
and not perhaps a struct with argc members), or is main() a special
case, where it is *known* that argv points to the start of an array?
(Despite being pretty much the only function where you can't know!)

In a hosted environment, the 'main' parameter 'argv' has to point into
an array. Why? Because of the second bullet of 5.1.2.2.1p2.
If any pointer passed to a function might be assumed to point to the
start of an array, then it seems to me that you can also assume that a
reference to that array has been passed.

1. Pointers can point to functions, to no object, or to an incomplete
object type, besides arrays.

2. If you pass an 'int *', it is not a reference to an array. Why?
Because you cannot determine the array's size in any standard way,
whereas with an 'int (*)[10]', you can, and it _does_ provide a
reference to an array.
 
K

Keith Thompson

BartC said:
Ben Bacarisse said:
BartC said:
void iadd(int a[],int b) {

There's no array here. I agree that it's confusing to people learning
C, but the confusing thing is that 'a' is not an array. It's the fact
that an array is *not* involved that is confusing.

What gets passed is a pointer to an int; you're right there's no array
involved. But in that case, what's going on here:

Is this array subscripting, or just updating a pointer target?

The subscript operator [] takes two operands, one of integer type and
one of pointer type. For the evaluation to be defined, the pointer
operand must point to an element of an array object. (A singleton
object is treated as a one-element array for this purpose).
How about this example:

int main(int argc, char *argv[]) ...

Here, argv is presumably a pointer to pointer to char; no array in sight
here either (other than the suspiciously array-like "[]" syntax!).

Yes, as a parameter declaration "char *argv[]" is exactly equivalent to
"char **argv" (and I personally prefer the latter).
Yet a few lines further on in my C standard, it talks about "...the array
members argv[0] through argv[argc-1]..." (5.1.2.2.2). What array?!

The anonymous array *object* created by the runtime environment before
invoking your main function. The implementation arranges for argv to
point to the first element of that array object.
 
B

Ben Bacarisse

BartC said:
Ben Bacarisse said:
void iadd(int a[],int b) {

There's no array here. I agree that it's confusing to people learning
C, but the confusing thing is that 'a' is not an array. It's the fact
that an array is *not* involved that is confusing.

What gets passed is a pointer to an int; you're right there's no array
involved. But in that case, what's going on here:

Is this array subscripting, or just updating a pointer target?

Whatever you decide to call it, an array need not be involved. I can
call iadd like this:

int x;
iadd(&x, 42);

and a[0] += b; workds just fine. No array in sight.
How about this example:

int main(int argc, char *argv[]) ...

Here, argv is presumably a pointer to pointer to char; no array in
sight here either (other than the suspiciously array-like "[]"
syntax!).

Yet a few lines further on in my C standard, it talks about "...the
array members argv[0] through argv[argc-1]..." (5.1.2.2.2). What
array?!

There is an array involved here -- the standard says so. It may have
only one element (and therefore be very like a single object) but there
is an array of char pointers.

When you see only the parameter declared like this: T p[], you don't
know if there is an array anywhere in the program so you can't tell from
looking at the declaration of main alone if there is one or not, but the
standard clears it by telling you that what will be passed is a pointer
to the first element of an array.

Obviously, the pointer that is assigned to a parameter declared with the
[] syntax will often be to the start of an array, and it is perfectly
reasonable to talk, in general, about indexing (the other []s) as being
"an array access", but saying that arrays "are passed by reference" is
just wrong and confusing. The treatment of arrays is special in far
more situations that simple parameter passing, and C does not have "pass
by reference" for any types.
 
E

Eric Sosman

The subscript operator [] takes two operands, one of integer type and
one of pointer type. For the evaluation to be defined, the pointer
operand must point to an element of an array object. [...]

Nitpick: "... or must point one element-worth beyond the
last element of an array object." (In this case, the integer
operand would necessarily be negative.)
 

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
474,077
Messages
2,570,566
Members
47,202
Latest member
misc.

Latest Threads

Top