Array passed as function parameters

W

Why Tea

Could anyone please explain the differences between
the following array passing? Thanks!

1) int get_data(char d[100]) {...}

2) int get_data(char *d) {...}

/WT
 
M

Mark Bluemel

Could anyone please explain the differences between
the following array passing? Thanks!

1) int get_data(char d[100]) {...}

2) int get_data(char *d) {...}

In (1), the function gets passed a pointer to an array of 100 chars. In
(2), the function gets passed a "generic" pointer to char.

Not quite. In 1) the function is passed a pointer to the first char of
an array of 100 chars which is not the same as a pointer to an array of
100 chars.

FAQ 6.4 is probably a good start point for Why Tea... The FAQs are at
c-faq.com.
 
E

Eric Sosman

Could anyone please explain the differences between
the following array passing? Thanks!

1) int get_data(char d[100]) {...}

2) int get_data(char *d) {...}

In (1), the function gets passed a pointer to an array of 100 chars. In
(2), the function gets passed a "generic" pointer to char.

(Counter-trolling, Kenneth? If so, I apoligize for spoiling
the fun -- But there's enough confusion on this point that it
seems dangerous to leave things alone.)

There's no difference. See Question 6.21 in the comp.lang.c
Frequently Asked Questions (FAQ) page, <http://www.c-faq.com/>.
 
J

John Bode

Could anyone please explain the differences between

the following array passing? Thanks!



1) int get_data(char d[100]) {...}



2) int get_data(char *d) {...}



/WT

Both are treated the same; in the context of an array parameter declaration, "T a[N]" and "T a[]" are both interpreted as "T *a"; all three declare "a" as a pointer to "T" (this is *only* true for function parameter declarations, though).

Except when it is the operand of the sizeof or unary "&" operators, or is astring literal being used to initialize another array in a declaration, anexpression of type "N-element array of T" will be converted or "decay" to an expression of type "pointer to T", and the value of the converted expression will be the address of the first element in the array.

So, assuming code like

int arr[20];
foo(arr);

the expression "arr" in the call to "foo" will be converted from type "20-element array of int" to "pointer to int", and the value will be the same as"&arr[0]"; thus, "foo" receives a pointer value as its argument, not an array.

You can declare "foo" as either

void foo(int a[20])

or

void foo (int a[])

or

void foo (int *a)

and all will be interpreted the same way.
 
V

Varun Tewari

In 1, you actually duplicating the array in the funciton.
in 2, rather you are happy using a reference to the array, hence no duplication.
 
K

Keith Thompson

Why Tea said:
Could anyone please explain the differences between
the following array passing? Thanks!

1) int get_data(char d[100]) {...}

2) int get_data(char *d) {...}

There is no difference in meaning; they're effectively different
spellings of the same thing.

See http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
6.7.6.3p7, or the corresponding paragraph in the section on "Function
declarators" in earlier versions of the standard.

And yes, that means the "100" in the first example is silently ignored
(unless the compiler chooses to warn about it, but I know of none that
do).
 
E

Edward Rutherford

Keith said:
Why Tea said:
Could anyone please explain the differences between the following array
passing? Thanks!

1) int get_data(char d[100]) {...}

2) int get_data(char *d) {...}

There is no difference in meaning; they're effectively different
spellings of the same thing.

See http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf 6.7.6.3p7,
or the corresponding paragraph in the section on "Function declarators"
in earlier versions of the standard.

And yes, that means the "100" in the first example is silently ignored
(unless the compiler chooses to warn about it, but I know of none that
do).

Yes, however you can get around this by using the static keyword.

~Edward
 
J

James Kuyper

In 1, you actually duplicating the array in the funciton.
in 2, rather you are happy using a reference to the array, hence no duplication.

Both declarations declare a pointer which provides a reference to the
array (or more precisely, the first element of the array. Neither
declaration involves duplication of the array.
 
E

Eric Sosman

Both declarations declare a pointer which provides a reference to the
array (or more precisely, the first element of the array. Neither
declaration involves duplication of the array.

Still more precisely: To any element of any array, or even to a
free-standing object. (For purposes of pointer arithmetic, single
objects are treated as one-element arrays.)

void f(int array[42]) {
printf("*(%p) = %d\n", (void*)array, *array);
}
...
int alone = 66;
f(&alone); // OK
...
int small[] = { 1, 2, 3 };
f(small); // OK
f(small + 1); // OK
f(&small[2]); // OK
...
int array[99] = { 3, 1, 4, 1, 5, 9, /* rest zero */ };
f(array); // OK
f(&array[12]); // OK
f(array + 97); // OK
 
K

Keith Thompson

Varun Tewari said:
In 1, you actually duplicating the array in the funciton.
in 2, rather you are happy using a reference to the array, hence no duplication.

No, they are semantically identical.

Please read the other answers before posting your own.
 
K

Keith Thompson

Edward Rutherford said:
Keith said:
Why Tea said:
Could anyone please explain the differences between the following array
passing? Thanks!

1) int get_data(char d[100]) {...}

2) int get_data(char *d) {...}

There is no difference in meaning; they're effectively different
spellings of the same thing.

See http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf 6.7.6.3p7,
or the corresponding paragraph in the section on "Function declarators"
in earlier versions of the standard.

And yes, that means the "100" in the first example is silently ignored
(unless the compiler chooses to warn about it, but I know of none that
do).

Yes, however you can get around this by using the static keyword.

Not really. Even if you write:

int get_data(char d[static 100]) { ... }

the compiler is free to silently ignore both the "static" and the "100".

The "static 100" means that "the value of the corresponding
actual argument shall provide access to the first element of an
array with at least as many elements as specified by the size
expression" (N1370 6.7.6.3p7). But since the "shall" is not
part of a constraint, it just means that violating it causes the
behavior to be undefined. Compilers may use the information for
diagnostics and/or optimizations, but they're not required to.
And "d" is still a pointer, not an array.

gcc 4.7, for example, produces no warnings for this program:

#include <stdio.h>

int get_data(char d[static 100])
{
printf("sizeof d = %zu\n", sizeof d);
return sizeof d;
}

int main(void) {
char tiny[10];
char huge[1000];
get_data(tiny);
get_data(huge);
return 0;
}

The output is:

sizeof d = 4
sizeof d = 4
 
E

Edward Rutherford

Keith said:
gcc 4.7, for example, produces no warnings for this program:

#include <stdio.h>

int get_data(char d[static 100])
{
printf("sizeof d = %zu\n", sizeof d); return sizeof d;
}

int main(void) {
char tiny[10];
char huge[1000];
get_data(tiny);
get_data(huge);
return 0;
}

The output is:

sizeof d = 4
sizeof d = 4

However as this code produces undefined behavior, isn't it difficult to
read anything much into what it outputs?
 
J

James Kuyper

Keith said:
gcc 4.7, for example, produces no warnings for this program:

#include <stdio.h>

int get_data(char d[static 100])
{
printf("sizeof d = %zu\n", sizeof d); return sizeof d;
}

int main(void) {
char tiny[10];
char huge[1000];
get_data(tiny);
get_data(huge);
return 0;
}

The output is:

sizeof d = 4
sizeof d = 4

However as this code produces undefined behavior, isn't it difficult to
read anything much into what it outputs?

True - the relevant information was "no warnings" - which implies that
gcc (correctly, IMO) does not think that a diagnostic is required by
this code. Diagnosis of such cases would have to be mandatory for this
feature to be of much use.
 
K

Keith Thompson

Vincenzo Mercuri said:
Il 16/08/2012 20:10, Varun Tewari ha scritto:

Wrong, AFAIK the only way to "pass an array by value" is by using a common
"trick": declare an array inside a struc and pass that struct as argument
to a function:
[snip]

Yes, but you can only do that with arrays whose size is known at
compile time (you can't have a VLA as a struct member), which limits
its usefulness.
 
8

88888 Dihedral

Kenneth Brodyæ–¼ 2012å¹´8月16日星期四UTC+8下åˆ11時02分26秒寫é“:
Could anyone please explain the differences between
the following array passing? Thanks!
1) int get_data(char d[100]) {...}
2) int get_data(char *d) {...}



In (1), the function gets passed a pointer to an array of 100 chars. In

(2), the function gets passed a "generic" pointer to char.



I expected some differences in the compiler's treatment of the code, but a

test here shows none.

This is the famous and notorious rule in C for arrays.

It is assumed that the caller is responsible.

No boundary checking for allocated arrays or pointers is the default in C.
Which brings me to a related question... The following gives me no errorsor

warnings, even with warnings set to max. Shouldn't it at least warn me, if

not downright fail?



extern void foo(char array[100]);



void bar(void)

{

char array[50];

foo(array);

}



Also, this gives no warnings:



void foo(char array[100])

{

array++;

}



(Note that "array" is incremented by 1, not 100.)



Kenneth Brodyæ–¼ 2012å¹´8月16日星期四UTC+8下åˆ11時02分26秒寫é“:
Could anyone please explain the differences between
the following array passing? Thanks!
1) int get_data(char d[100]) {...}
2) int get_data(char *d) {...}



In (1), the function gets passed a pointer to an array of 100 chars. In

(2), the function gets passed a "generic" pointer to char.



I expected some differences in the compiler's treatment of the code, but a

test here shows none.



Which brings me to a related question... The following gives me no errorsor

warnings, even with warnings set to max. Shouldn't it at least warn me, if

not downright fail?



extern void foo(char array[100]);



void bar(void)

{

char array[50];

foo(array);

}



Also, this gives no warnings:



void foo(char array[100])

{

array++;

}



(Note that "array" is incremented by 1, not 100.)

Of course, there are programming languages do check arrays in both
the caller part and the callee part to be easy to be tracked by
novices in debugging programs with the prices of slower execution speeds.
 
V

Vincenzo Mercuri

Il 17/08/2012 01:10, Keith Thompson ha scritto:
Vincenzo Mercuri said:
Il 16/08/2012 20:10, Varun Tewari ha scritto:

Wrong, AFAIK the only way to "pass an array by value" is by using a common
"trick": declare an array inside a struc and pass that struct as argument
to a function:
[snip]

Yes, but you can only do that with arrays whose size is known at
compile time (you can't have a VLA as a struct member), which limits
its usefulness.

True. I've never used that trick so far. I didn't think about
a VLA, thanks for the heads-up!
 
J

Jens Gustedt

Am 16.08.2012 18:43, schrieb John Bode:
You can declare "foo" as either

void foo(int a[20])

or

void foo (int a[])

or

void foo (int *a)

and all will be interpreted the same way.

There is a fourth way that is valid since C99

void foo(int a[static 20])

which still is compatible with the above declarations, but in addition
reclaims that the pointer passed to the function has at least 20
elements. In particular in implies that foo shouldn't be called with a
null pointer. If a caller does not respect that semantics, the
behavior is undefined.

So this is still the same ABI and still the caller is responsible for
the check. And if on the calling side the actual argument is an array
and not a plain pointer that check should almost be trivial to
implement.

Unfortunately, there doesn't seem to be compilers that implement
it. Or does anybody know of such a compiler?

Jens
 
P

pvolkovskiy

Sometimes they differ, in your particular case - they don't.
#include <iostream>

void f(int (*p)[3])
// void f(int (*p)[5]) // error: cannot convert ‘int (*)[3]’ to ‘int (*)[5]’ for argument ‘1’ to ‘void f(int (*)[5])’
// void f(int **p) // error: cannot convert ‘int (*)[3]’ to ‘int**’for argument ‘1’ to ‘void f(int**)
{
std::cout << (*p)[1];
}

int main(int argc, char* argv[])
{
int a[3] = {1, 2, 3};
f(&a);
}
 
K

Keith Thompson

Sometimes they differ, in your particular case - they don't.
#include <iostream>

void f(int (*p)[3])
// void f(int (*p)[5]) // error: cannot convert ‘int (*)[3]’ to ‘int (*)[5]’ for argument ‘1’ to ‘void f(int (*)[5])’
// void f(int **p) // error: cannot convert ‘int (*)[3]’ to ‘int**’ for argument ‘1’ to ‘void f(int**)
{
std::cout << (*p)[1];
}

int main(int argc, char* argv[])
{
int a[3] = {1, 2, 3};
f(&a);
}

The question was about the difference between
int get_data(char d[100]) {...}
and
int get_data(char *d) {...}

i.e., between a parameter defined as "array of foo" and one defined as
"pointer to foo".

Your examples involve pointers of different types, namely

pointer to array 3 of int
pointer to array 5 of int
pointer to pointer to int

Your examples are not relevant to the question.

Oh, and your sample code is C++, not C.
 
A

ais523

Keith said:
Vincenzo Mercuri said:
Il 16/08/2012 20:10, Varun Tewari ha scritto:

Wrong, AFAIK the only way to "pass an array by value" is by using a common
"trick": declare an array inside a struc and pass that struct as argument
to a function:
[snip]

Yes, but you can only do that with arrays whose size is known at
compile time (you can't have a VLA as a struct member), which limits
its usefulness.

You could use a flexible array member instead, which would come to much
the same thing. (Or the infamous C89 "struct hack", which as far as I
know was never guaranteed to work, but which does in every C compiler
anyone's tested.)
 

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,769
Messages
2,569,576
Members
45,054
Latest member
LucyCarper

Latest Threads

Top