Passing an array to a function, do it need to use &?
In below example Case 1 or Case 2, which one is good ?
#define IP_ADDR_LEN 4
char ip[4]={192,168,205,1};
char PeerIP[4];
int main()
{
memcpy(PeerIP,ip,IP_ADDR_LEN)
testip(PeerIP); /* Case 1 */
testip(&PeerIP); /*Case 2*/
}
int testip(char *ip)
{
/* IP check */
}
The first one.
testip(PeerIP);
is the right way to do it, as an array name will decay to a pointer to the first element of the array, which matches the expected type for the called function parameter.
To elaborate, in your code, testip() expects an argument of type char * and by calling it like testip(PeerIP); you are passing a char *, so no issues.
In case you use the &PeerIP, the type will be [char (*) [4]] pointer to array, not pointer to the first element of the array [char *] and they are different type.
Quoting C11, chapter §6.3.2.1, Lvalues, arrays, and function designators, (emphasis mine)
Except when it is the operand of the sizeof operator, the _Alignof operator, or the
unary & operator, or is a string literal used to initialize an array, an expression that has
type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points
to the initial element of the array object and is not an lvalue. [...]
Related
The following C program:
int doStuff(int afm[]);
int main(){
int afm1[9] = {1,2,3,4,5,6,7,8,9}; //size=9
int afmLength = sizeof(afm1)/sizeof(int);
printf("main: Length Of Array=%d\n", afmLength); //9 OK
int k = doStuff(afm1);
system("PAUSE");
return 0;
}
int doStuff(int afm[]){
int afmLength = sizeof(afm)/sizeof(int);
printf("doStuff: Length Of Array=%d\n", afmLength); //1 WRONG
return 1;
}
produces the following output:
main: Length Of Array=9
doStuff: Length Of Array=1
Why is the array size calculated correctly in main, but is wrong inside the function?
Because in main you have an array and in the function you have a pointer to that array.
int doStuff(int afm[])
is equivalent to
int doStuff(int *afm)
Adding to David Heffernan's answer (which is correct), you should have another parameter which would be the array length passed onto your doStuff method.
From the C language standard (draft n1256):
6.3.2.1 Lvalues, arrays, and function designators
...
3 Except when it is the operand of the sizeof operator or the unary & operator, or is a
string literal used to initialize an array, an expression that has type ‘‘array of type’’ is
converted to an expression with type ‘‘pointer to type’’ that points to the initial element of
the array object and is not an lvalue. If the array object has register storage class, the
behavior is undefined.
Memorize that paragraph, since one of the biggest sources of heartburn in C programming is how C treats array expressions.
When you call doStuff(afm1);, the expression afm1 is implicitly converted from type "9-element array of int" to "pointer to int", and the expression's value is the same as &afm1[0]. So what doStuff receives is a pointer value, not an array.
In the context of a function parameter declaration, T a[] and T a[N] are both interpreted as T *a:
6.7.5.3 Function declarators (including prototypes)
...
7 A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to
type’’, where the type qualifiers (if any) are those specified within the [ and ] of the
array type derivation. If the keyword static also appears within the [ and ] of the
array type derivation, then for each call to the function, 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.
Since doStuff receives a pointer value and not an array, the sizeof trick doesn't work. In general, you have to explicitly tell a function how large of an array you're passing to it; you can't determine that from the pointer value itself.
So, when you call doStuff from main, you'll need to do something like
doStuff(afm1, sizeof afm1/sizeof *afm1);
...
int doStuff(int *afm, size_t afmsize)
{
...
}
I was wondering why in C this is possible:
int MATRICE[20][20];
int *p; p = MATRICE[19]; is equal to p = &(MATRICE[19][0]);
I tried to interpretate it in this way: I consider the label "MATRICE" as a constant pointer and like an array of pointers, so when it comes to the 20th pointer (MATRICE[19]) it points at the same thing that MATRICE[19][0] points too.
Is my idea correct?
Arrays used in expressions with rare exceptions are converted to pointers to their first elements.
From the C Standard (6.3.2.1 Lvalues, arrays, and function designators)
3 Except when it is the operand of the sizeof operator or the unary &
operator, or is a string literal used to initialize an array, an
expression that has type ‘‘array of type’’ is converted to an
expression with type ‘‘pointer to type’’ that points to the initial
element of the array object and is not an lvalue. If the array object
has register storage class, the behavior is undefined.
This expression
MATRICE[19]
yields a one-dimensional array of the type int[20] that is implicitly converted to pointer to its first element of the type int * when used as an initializer (as a right side hand expression in the assignment) in this code snippet
int *p; p = MATRICE[19];
I am currently studying C language.
I wonder what 'array decaying' means, and when it happens.
And I wonder if the two variables below are interpreted in the same way.
char(*zippo)[2] = NULL;
char zippo2[4][2];
zippo = (char(*)[2])malloc(sizeof(char[2]) * 4);
From the C Standard (6.3.2.1 Lvalues, arrays, and function designators)
3 Except when it is the operand of the sizeof operator or the unary &
operator, or is a string literal used to initialize an array, an
expression that has type ‘‘array of type’’ is converted to an
expression with type ‘‘pointer to type’’ that points to the initial
element of the array object and is not an lvalue. If the array object
has register storage class, the behavior is undefined.
The two variables below
char(*zippo)[2] = NULL;
char zippo2[4][2];
have different types. The first one is a pointer to an object of the type char[2]. The second one is a two-dimensional array with four elements of the type char[2].
When the array zippo2 is used in expression except the expressions listed in the quote (as for example using it with the sizeof operator) then its designator is implicitly converted to pointer to its first element and has the same type as the variable zippo.
I am a beginner in programming. It was taught that arrays store address of the first element. While using for loop when I input the Array elements using scanf I should not use & character right
it should be ("%d",Arr[i]) , instead of ("%d",&Arr[i]) .
but why it is showing error?
Array type has a special property, in some of the cases, a variable with type array decays to a type as pointer to the first element of the array.
Quoting C11, chapter §6.3.2.1
Except when it is the operand of the sizeof operator, the _Alignof operator, or the
unary & operator, or is a string literal used to initialize an array, an expression that has
type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points
to the initial element of the array object and is not an lvalue. [...]
However, if the type is not an array type, it does not hold.
From your description, it sounds you have the array defined as
int Arr[16]; // 16 is arbitrary, just for example
In your case, Arr is an array of integers and Arr[i] is not an array type, it's an integer. So, you have to pass the address of this integer to scanf().
The correct statement would be
("%d",&Arr[i]); // passing the address.
To compare, if you have an array defined like
char array [16];
then you can write
scanf("%15s", array); // 'array' is array type, which is same as `&array[0]` in this case
I'm going through K&R and it says array name is not a variable and it cannot be used in constructions like a=pa or a++.
Isn't s an array name here?
#include<stdio.h>
main(){
printf("%d", strlen("test"));
}
int strlen(char s[])
{
int n;
for (n = 0; *s!= '\0';s++) // why is s++ valid even though it is declared as an array
n++;
return n;
}
No, in this context it's a pointer to a char. Your function declaration is completely equivalent to:
int strlen(char *s)
As you'll see, it's actually impossible to pass an array to a function: a pointer to the first element is what is actually passed.
Thus, since s is actually a pointer and not an array, you're free to modify it as you please.
From the horse's mouth:
6.3.2.1 Lvalues, arrays, and function designators
...
3 Except when it is the operand of the sizeof operator, the _Alignof operator, or the
unary & operator, or is a string literal used to initialize an array, an expression that has
type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points
to the initial element of the array object and is not an lvalue. If the array object has
register storage class, the behavior is undefined.
The expression "test" is a string literal, which has type "5-element array of char". When you pass "test" as a parameter of strlen, by the rule above, what actually gets passed is a pointer whose value is the address of the first character in "test".
Which brings us to...
6.7.6.3 Function declarators (including prototypes)
...
7 A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to
type’’, where the type qualifiers (if any) are those specified within the [ and ] of the
array type derivation. If the keyword static also appears within the [ and ] of the
array type derivation, then for each call to the function, 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.
So in the prototype for strlen, char s[] is equivalent to char *s; s is declared as a pointer to char, not an array of char.
C's treatment of arrays is a bit baroque compared to other languages. That's due in part to the BCPL and B heritage. If you're curious as to why, you can read dmr's The Development of the C Language for some insights.
No, acctually s is a pointer name.
The declaration int strlen(char s[]) is same as int strlen(char *s)
When Char s[]={...} is declared address is attached to s, which never changes (like constant pointer) and anything try to change this property becomes an illegal operation such as s++.
But In function call int strlen(char s[]) , array is passed as pointer.