This question already has answers here:
Why isn't the size of an array parameter the same as within main?
(13 answers)
Closed 7 years ago.
#include "stdio.h"
#define COUNT(a) (sizeof(a) / sizeof(*(a)))
void test(int b[]) {
printf("2, count:%d\n", COUNT(b));
}
int main(void) {
int a[] = { 1,2,3 };
printf("1, count:%d\n", COUNT(a));
test(a);
return 0;
}
The result is obvious:
1, count:3
2, count:1
My questions:
Where is the length(count/size) info stored when "a" is declared?
Why is the length(count/size) info lost when "a" is passed to the test() function?
There's no such thing as "array pointer" in C language.
The size is not stored anywhere. a is not a pointer, a is an object of type int[3], which is a fact well known to the compiler at compile time. So, when you ask the compiler to calculate sizeof(a) / sizeof(*a) at compile time the compiler knows that the answer is 3.
When you pass your a to the function you are intentionally asking the compiler to convert array type to pointer type (since you declared the function parameter as a pointer). For pointers your sizeof expression produces a completely different result.
Where is the length(count/size) info stored when "a" is declared?
It's not stored anywhere. The sizeof operator (used in the COUNT() macro) returns the size of the entire array when it's given a true array as the operand (as it is in the first printf())
Why is the length(count/size) info lost when "a" is passed to the test() function?
Unfortunately, in C, array parameters to functions are a fiction. Arrays don't get passed to functions; the parameter is treated as a pointer, and the array argument passed in the function call gets 'decayed' into a simple pointer. The sizeof operator returns the size of the pointer, which has no correlation to the size of the array that was used as an argument.
As a side note, in C++ you can have a function parameter be a reference to an array, and in that case the full array type is made available to the function (i.e., the argument doesn't decay into a pointer and sizeof will return the size of the full array). However, in that case the argument must match the array type exactly (including the number of elements), which makes the technique mostly useful only with templates.
For example, the following C++ program will do what you expect:
#include "stdio.h"
#define COUNT(a) (sizeof(a) / sizeof(*(a)))
template <int T>
void test(int (&b)[T]) {
printf("2, count:%d\n", COUNT(b));
}
int main(int argc, char *argv[]) {
int a[] = { 1,2,3 };
printf("1, count:%d\n", COUNT(a));
test(a);
return 0;
}
Nowhere.
Because it wasn't stored in the first place.
When you refer to the array in main(), the actual array declaration definition is visible, so sizeof(a) gives the size of the array in bytes.
When you refer to the array in the function, the parameter is effectively 'void test(int *b), and the size of the pointer divided by the size of the thing it points at happens to be 1 on a 32-bit platform, whereas it would be 2 on a 64-bit platform with LP64 architecture (or, indeed, on an LLP64 platform like Windows-64) because pointers are 8 bytes and int is 4 bytes.
There isn't a universal way to determine the size of an array passed into a function; you have to pass it explicitly and manually.
From the comment:
I still have two questions:
What do you mean by "..the actual declaration is visible.."? [T]he compiler (or OS) could get the length info through sizeof(a) function?
Why the pointer &(a[0]) doesn't contain the length info as the pointer "a"?
I think you learned Java before you learned C, or some other more modern language. Ultimately, it comes down to "because that is the way C is defined". The OS is not involved; this is a purely compiler issue.
sizeof() is an operator, not a function. Unless you are dealing with a VLA (variable length array), it is evaluated at compile time and is a constant value.
Inside main(), the array definition (I misspoke when I said 'declaration') is there, and when the sizeof() operator is applied to the name of an actual array - as opposed to an array parameter to a function - then the size returned is the size of the array in bytes.
Because this is C and not Algol, Pascal, Java, C#, ...
C does not store the size of the array - period. That is a fact of life. And, when an array is passed to a function, the size information is not passed to the function; the array 'decays' to a pointer to the zeroth element of the array - and only that pointer is passed.
1. Where is the length(count/size) info stored when "a" is declared?
It isn't stored. The compiler knows what a is and therefore knows it's size. So the compiler can replace sizeof() with the actual size.
2. Why is the length(count/size) info lost when "a" is passed to the test() function?
In this case, b is declared as a pointer (even though it may point to a). Given a pointer, the compiler does not know the size of the data pointed to.
Array pointer does not store the size. However, the[] type is not actually a pointer. It's a different type. When you say int a[] = {1,2,3}; you define array of 3 elements, and since it is defined so, sizeof(a) gives you the size of the whole array.
When however you declare parameter as int a[], it's pretty much the same as int *a, and sizeof(a) would be the size of the pointer (which coincidentally may be the same as the size of int, but not always).
In C, there's no way to store the size in pointer type, so if you need the size, you'd have to pass it as additional argument or use struct.
Where is the length(count/size) info stored when "a" is declared?
Nowhere. The question doesn't make sense BTW.
Why is the length(count/size) info lost when "a" is passed to the test() function?
Array decays into pointer(to the first element) when passed to a function. So the answer is 'nowhere' and similar to the previous question this one again doesn't make any sense.
Related
This question already has answers here:
How do I determine the size of my array in C?
(24 answers)
Miscalculation of array size inside a function
(3 answers)
Closed 1 year ago.
It's printing 0 but I expect 1. The size of first dimension in array is omitted because I want to pass multiple arrays entries in this same method how to get this for iteration
void printValues(char hotelData[][3][50], int n);
char hotelData [1][3][50] =
{
"unidadeid1Fk", "john fernandes", "executiveRoom"
};
int main( void )
{
printValues(hotelData, 0);
}
void printValues(char hotelData[][3][50], int n)
{
int arraySize = sizeof (hotelData) / sizeof (hotelData[0]);
printf("ArraySize: %i ", arraySize);
}
Output is
ArraySize: 0
And this code is returning this warning that I don't know what means and how to solve it:
teste.c: In function 'printValues': teste.c:29:32: warning: 'sizeof' on array function parameter 'hotelData' will return size of 'char
(*)[3][50]' [-Wsizeof-array-argument]
int arraySize = sizeof (hotelData) / sizeof (hotelData[0]);
^ teste.c:27:27: note: declared here
void printValues(char hotelData[][3][50], int n)
When an array is passed as an argument to a function, it is automatically converted to a pointer to its first element.1 Similarly, when a declaration of a parameter to a function is an array, it is automatically adjusted to be a pointer.
When the pointer to the first element of the array is passed, no size information is automatically passed. If, inside of the function, you want to know the size of the array, you must pass it as an argument or otherwise make it available to the function.
In contrast, the compiler knows the size of hotelData[0] because it knows the complete type of hotelData[0]. While hotelData has been converted to a pointer, it is a pointer of type “pointer to array of 3 arrays of 50 char” (also known as char (*)[3][50]), so it points to an array of 3 arrays of 50 char, and the size of that is 3•50•1 = 150.
The size of the pointer hotelData is likely 4 or 8 bytes. In any case, it is certainly less than 150 bytes, so dividing it by 150 yields 0 (in integer arithmetic).
Generally, the compiler only knows the sizes of things whose complete type declarations are visible. Even neglecting the fact that the parameter declaration char hotelData[][3][50] is automatically adjusted to char (*hotelData)[3][50], the complete type of hotelData[][3][50] is not visible at this point in the source code because the [] is empty. C does not pass any extra information about the size of an object along with the function argument; the type information has to be completely known from the parameter declaration. (Although you and I can see the call to printValues in the main routine above, the compiler is not able to use the information about the external object named hotelData in application to the parameter named hotelData; they are different things in spite of having the same name.)
Footnote
1 Whenever an array is used in an expression, it is automatically converted to a pointer to its first element unless it is the the operand of sizeof, is the operand of unary & or is a string literal used to initialize an array.
This question already has answers here:
Difference between passing array and array pointer into function in C
(3 answers)
Closed 5 years ago.
As far as I know, you cannot modify a Array variable
How come this code run without any error.
Is there anything I am missing out here. (It's not about why there is 'L-VALUE REQUIRED' error , it's about why there isn't.)
#include<stdio.h>
int strlens(char *s);
void main(){
char s[]="get me length of this string ";
// s++ ; this would give 'L-VALUE REQUIRED ERROR'
printf("%d",strlens(s));
}
int strlens(char s[]){
int i;
for(i=0; *s!='\0';++i, ++s) ; //++s: there is NO 'L-VALUE REQUIRED ERROR'
return i;
}
A quirk of the C language that is well-known to seasoned C programmers, but trips up new C coders to no end, is that arrays are "pass by reference". Generally speaking, an array name used in most expressions will "decay" to the address of its first element. Functions carry that to an extreme case, where the array syntax in the function parameter is actually an alias for the pointer type itself.
This is described in paragraph 7 of c11's §6.7.6.3 Function declarators:
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.
Historically, this quirk was an attempt to maintain behavioral compatibility to C's predecessors, B and BCPL, and efficient structure layout. C's predecessor had a semantic for arrays in that its physical layout was actually a pointer that got dynamically allocated and initialized at runtime. When passed to a procedure, the pointer semantic was a natural adoption. Dennis Ritchie invented the notion of allowing the array syntax represent the actual address of the array, and then maintained the pointer semantic when passed to a function. Thus, the inventor of the C language considered this quirk a novel solution to a real world problem (semantic compatibility).
References:
The Development of the C Language
This line
char s[]="get me length of this string ";
defines a character array. s is not a pointer, it evaluates to an address (when fed to a pointer for instance, or when accessing a value like s[i] equivalent to *(s+i)), or represents the space occupied by the array (eg in sizeof(s))
But in a function signature like this
int strlens(char s[]){
char s[] is equivalent to char *s, and you can treat s like a pointer.
char arr[] = "asds"
Here, arr is just a name. It refers to a memory location but is not a pointer. The compiler substitutes the address directly wherever arr is used. It is not a pointer because unlike pointers, it does not have any space allocated to store an address. It is a mere compile time symbol. Hence, at run-time there is nothing on which you can do pointer arithmetic on. If you had to increment something, that something should exist at run-time.
More details:
Basically, the literal "asds" is stored in your executable and the compiler knows where exactly it is (well, the compiler is placing it in the executable, so it should know?).
The identifier arr is just a name to that location. As in, arr is not a pointer, i.e: it does not exist in memory storing an address.
void func(char arr[])
In case of a function argument, the arr does exist in memory at run-time because the arguments are pushed onto the call stack before making the function call. Since arrays are passed by reference, the address of the first element of the actual parameter is pushed onto the call stack.
Therefore, arr is allocated some space on the stack where it stores the address to the first element of your actual array.
Now you have a pointer. Hence you can increment (or do any pointer arithmetic on it).
This question already has answers here:
Should I use char** argv or char* argv[]?
(10 answers)
Closed 8 years ago.
I've been fiddling around to see if there's any way to retain information about an array's length automatically when passed into a function (see my other question here: Why is this array size "workaround" giving me a warning?), but my question is more about a warning that gcc is giving that doesn't make sense to me.
According to this website (EDIT: I misread the website), char *p[10] declares a pointer to a 10-wide array of chars. But when I tried to pass in a pointer to an array into a function, I got this error message from the compiler:
Here is the rest of the program:
I know that when an array is passed into a function, it decays into a pointer (losing information about its length), but it seems that the declaration itself is decaying. What's going on here?
EDIT: When I replace the char *p[10] with char (*p)[10], it doesn't give the warning anymore, and more importantly, it displays the proper array length: 10. I guess my questions are 1) Why do the parentheses change things? and 2) Is this a well-known workaround or am I relying on some behavior of the compiler that isn't guaranteed? (i.e. that array length info can be passed by indirectly passing in a pointer to it?)
In fact char *p[10] is an array, of length 10, of pointers to char. You are looking for char (*p)[10]. That is a pointer to an array, of length 10, of char.
You might find http://cdecl.org/ a useful resource to help you test your understanding of declarations.
Regarding the discussion surrounding dynamic arrays, you are going to have to accept that once you allocate an array dynamically, the system provides no means for you to recover the length of the array. It is your responsibility to remember that information.
The subject of your question has been answered already but I wanted to address the heart of it, which is "can I encode the length of an array in its type?" Which is in fact what a pointer-to-array does. The real question is whether you can actually gain any brevity or safety from this. Consider that in each scope where you have a declaration of your type, the length still needs to be known a-priori. To show you what I mean let's generalize your example slightly by making 10 a compile-time constant N.
#define N 10
size_t arraylength(char (*arrayp)[N]) {
return sizeof(*arrayp);
}
int main(void) {
char array[N];
assert( arraylength(&array) == N ); //always true
}
So far so good. We didn't have to pass the length of array anywhere. But it's easy to see that anywhere the expression sizeof(*arrayp) is used, we also could have written N. And any place we declare a char(*)[ ], the bracketed length must come from somewhere.
So what if N isn't a compile time constant, and array is either a VLA or a pointer-to-array from malloc? We can still write and call arraysize, but it looks like this:
size_t arraylength(size_t N, char (*arrayp)[N]) {
return sizeof(*arrayp);
}
int main(void) {
size_t N = length_from_somewhere();
char array[N];
assert( arraylength(sizeof(array), &array) == N );
}
In defining arraysize N must still be visible before the declaration of arrayp. In either case, we can't avoid having N visible outside of the declaration of arrayp. In fact, we didn't gain anything over writing arraysize(size_t N, char* array) and passing array directly (which is a bit silly given the purpose of this function.) Both times arraylength could have equally been written return N;
Which isn't to say that array pointers are useless as parameters to functions -- in the opposite situation, when you want to enforce a length, they can provide type checking to make sure somefunc(char (*)[10]); receives a pointer to an array that is really (sans shady casting) 10 elements long, which is stronger than what a construct like [static 10] provides.
Also keep in mind that all of the length measurements above depend on the underlying type being char where length == size. For any larger type, taking the length requires the usual arithmetic e.g.
sizeof(*arrayp)/sizeof((*arrayp)[0])
In C, arrays decay to pointers to their first elements on most uses. In particular, what a function receives is always just a pointer to the first element, the size of the array is not passed with it.
Get a good text on C and read up on arrays.
I've been fiddling around to see if there's any way to retain information about an array's length automatically when passed into a function
The problem is so annoying that lots of programmers would love to have an answer. Unfortunately, this is not possible.
It seems that the declaration itself is decaying
Pointer to an array is not the same as a pointer to a pointer; that is why you are getting an error.
There is no decaying going on in your code, because you are not passing an array in your code sample: instead, you are trying to pass a pointer to an array &p. The pointer to an array of characters is not compatible to the expected type of the function, which is char**. Array size from the declaration is ignored.
You need to keep in mind two things:
1. Arrays are not pointers.
2. Array names decays to pointers (in most cases) when passed as arguments to functions.
So, when you declare
int a[10]; // a is an array of 10 ints
int *b; // b is a pointer to int
both of a and b are of different types. Former is of type int [10] while latter is of type int *.
In case of function parameter
void foo1 (int a[10]); // Actually you are not passing entire array
void foo2 (int a[]); // And that's why you can omit the first dimension.
void foo3 (int *a); // and the compiler interprets the above two third
ain all of the above function declarations is of same data type int *.
Now in your case
unsigned long arraySize(char *p[10]);
you can declare it as
unsigned long arraySize(char *p[]);
and hence
unsigned long arraySize(char **p);
All are equivalent.
char *p[10] char *p[] and char **p all are exactly equivalent but when they are declared as parameter of a function otherwise char *p[10] (an array of 10 pointers to char) and char **p (a pointer to pointer to char)are entirely of different type.
Suggested reading: C-FAQ: 6. Arrays and Pointers explains this in detailed.
Array name itself is a constant pointer. for example int arr[10]={0};
arr contains the address of arr[0]. hence arr equals&arr[0] .
when u pass the arraysize(&p) , you are actually passing a double pointer .
The correct format to pass a array pointer would be arraysize(&p[0]) or arraysizeof(p)
Note Array name is constant pointer , you cant change its value .
int arr[10];
arr++;
is invalid.
In your case you cant find a size of an array in function by passing the array name . it would return size of pointer(4 or 8 depends on your processor .
The method is to pass the size along with the array
func(array_name , array_size);
This question already has answers here:
How to find the size of an array (from a pointer pointing to the first element array)?
(17 answers)
Closed 9 years ago.
I am reading the TCPL by K&R, when I read something about array and pointer, I write this small code below:
#include <stdio.h>
int sum(int a[])
{
int t = 0;
int length = sizeof(a) / sizeof(a[0]) ;
// printf("%d\n",length);
for(int i = 0; i != length; ++i)
{
t += a[i];
}
return t;
}
int main()
{
int b[5] = {1, 2, 3, 4, 5};
printf("%d\n",sum(b));
return 0;
}
The output answer is 1 NOT 15, then I debug this code by adding printf("%d\n",length); the output length is 1 NOT 5.
The TCPL tells that a array name converts to pointer when the array name used as argument, but the output answer is wrong, so I wonder that:
What happend when call a funcion with array name used as argument?
The array a[] used parameter in sum(int a[]) has storage or not?
I see two styles when calling a array : fun(int a[]); fun(b) and fun(int *a);fun(b),what the difference?
Thx very much :-)
You cannot call a function and pass a whole array; if you use an array name as a function argument, it is implicitly rewritten as ("decays to") a pointer to its first element. It is equivalent to writing
int sum(int *a) { ... }
Thus, within the function, sizeof array, does NOT give you the size of the array, only the size of a pointer to its first element.
So how do you know how many elements there are in the array? You need to pass this number explicitly to functions (or define a macro with the number of elements and use it where needed).
Your third question gets to the heart of the matter: there is no difference between those two as far as the compiler is concerned. Everything about how the argument is passed is the same.
Therefore, in response to your second question, the a parameter doesn't have storage for the underlying array, nor are the members of that array copied. The only storage allocated is for an int * pointer, and that pointer is stored in a. (That somewhat answers your first question as well.)
So, in your function:
int length = sizeof(a) / sizeof(a[0]) ;
is equivalent to
int length = sizeof(int *) / sizeof(int);
which returns 1 on systems where pointers and ints are the same size. If you run this on 64-bit Linux, you will get 2 instead, since pointers are 64 bits and ints are 32 bits.
Calling sizeof on an array declared as follows
int a[5];
will return the size of the array how you currently think it will (ie the full size in bytes of the array - in this case 20 bytes on my machine). When you pass an array like this to a function, the array will decay to a pointer to its first element. Thus when you call sizeof on your function argument you are actually calling it on a pointer type. Had you declared your function to take an int * argument, the error would be more obvious as the type of the variable that you call sizeof is explicit.
There is no problem with your call, and there is no difference between fun(int a[]) and fun(int *a) (expect that it is more obvious to the reader that you expect an array and not any pointer). Bot arguments are a pointer to an int.
Your problem here is how you try to determine the length of the array. As the square brackets are empty, there is no way for the compiler to know how long the array behind a is. You can for example provide the length of the array as a second argument. Note: When calling the function, sizeof(b) will provide the correct length, because the compiler knows its length.
The sizeof() operator can not be used for getting a dynamically allocated array length.
Here you can find examples of the sizeof() using.
When you try to do sizeof(array_ptr) it is actually gives you size of the pointer.
Thus, you have to pass array length as parameter of the function
Consider the following statements:
int *pFarr, *pVarr;
int farr[3] = {11,22,33};
int varr[3] = {7,8,9};
pFarr = &(farr[0]);
pVarr = varr;
At this stage, both pointers are pointing at the start of each respective array address. For *pFarr, we are presently looking at 11 and for *pVarr, 7.
Equally, if I request the contents of each array through *farr and *varr, i also get 11 and 7.
So far so good.
Now, let's try pFarr++ and pVarr++. Great. We're now looking at 22 and 8, as expected.
But now...
Trying to move up farr++ and varr++ ... and we get "wrong type of argument to increment".
Now, I recognize the difference between an array pointer and a regular pointer, but since their behaviour is similar, why this limitation?
This is further confusing to me when I also consider that in the same program I can call the following function in an ostensibly correct way and in another incorrect way, and I get the same behaviour, though in contrast to what happened in the code posted above!?
working_on_pointers ( pFarr, farr ); // calling with expected parameters
working_on_pointers ( farr, pFarr ); // calling with inverted parameters
.
void working_on_pointers ( int *pExpect, int aExpect[] ) {
printf("%i", *pExpect); // displays the contents of pExpect ok
printf("%i", *aExpect); // displays the contents of aExpect ok
pExpect++; // no warnings or errors
aExpect++; // no warnings or errors
printf("%i", *pExpect); // displays the next element or an overflow element (with no errors)
printf("%i", *aExpect); // displays the next element or an overflow element (with no errors)
}
Could someone help me to understand why array pointers and pointers behave in similar ways in some contexts, but different in others?
So many thanks.
EDIT: Noobs like myself could further benefit from this resource: http://www.panix.com/~elflord/cpp/gotchas/index.shtml
The difference is because for farr++ to have any effect, somewhere the compiler would need to store that farr will evaluate to the address of the second element of the array. But there is no place for that information. The compiler only allocates place for 3 integers.
Now when you declare that a function parameter is an array, the function parameter won't be an array. The function parameter will be a pointer. There are no array parameters in C. So the following two declarations are equivalent
void f(int *a);
void f(int a[]);
It doesn't even matter what number you put between the brackets - since the parameter really will be a pointer, the "size" is just ignored.
This is the same for functions - the following two are equivalent and have a function pointer as parameter:
void f(void (*p)());
void f(void p());
While you can call both a function pointer and a function (so they are used similar), you also won't be able to write to a function, because it's not a pointer - it merely converts to a pointer:
f = NULL; // error!
Much the same way you can't modify an array.
In C, you cannot assign to arrays. So, given:
T data[N];
where T is a type and N is a number, you cannot say:
data = ...;
Given the above, and that data++; is trying to assign to data, you get the error.
There is one simple rule in C about arrays and pointers. It is that, in value contexts, the name of an array is equivalent to a pointer to its first element, and in object contexts, the name of an array is equivalent to an array.
Object context is when you take the size of an array using sizeof, or when you take its address (&data), or at the time of initialization of an array. In all other contexts, you are in value context. This includes passing an array to a function.
So, your function:
void working_on_pointers ( int *pExpect, int aExpect[] ) {
is equivalent to
void working_on_pointers ( int *pExpect, int *aExpect ) {
The function can't tell if it was passed an array or a pointer, since all it sees is a pointer.
There are more details in the answers to the following questions:
type of an array,
sizeof behaving unexpectedly,
Also see this part of C for smarties website, which is very well-written.
Trying to increment farr or varr fails because neither one is a pointer. Each is an array. The name of an array, when evaluated by itself (except as the operand of the sizeof or address-of operator) evaluates to a value (an rvalue) that's of the correct type to be assigned to a pointer. Trying to increment it is a bit like trying to increment 17. You can increment an int that contains the value 17, but incrementing 17 itself won't work. The name of an array is pretty much like that.
As for your second part, it's pretty simple: if you attempt to declare a function parameter of array type, the compiler silently "adjusts" it to a pointer type. As such, in your working_on_pointers, aExpect and pExpect have exactly the same type. Despite the array-style notation, you've defined aExpect as having type 'pointer to int'. Since the two are the same, it's entirely expected that they'll act the same.
Have a look at this answer I posted in relation to differences between pointers and arrays here on SO.
Hope this helps.
okay, i may be wrong. but arrays and pointers can be used alternately.
int * ptr = (int *)malloc(2* sizeof(int));
ptr[0]=1;
ptr[1]=2;
printf ("%d\n", ptr[0]);
printf ("%d\n", ptr[1]);
here i declared a pointer and now i am treating it as array.
moreover:
As a consequence of this definition,
there is no apparent difference in the
behavior of the "array subscripting"
operator [] as it applies to arrays
and pointers. In an expression of the
form a[i], the array reference "a"
decays into a pointer, following the
rule above, and is then subscripted
just as would be a pointer variable in
the expression p[i] (although the
eventual memory accesses will be
different, as explained in question
2.2). In either case, the expression x[i] (where x is an array or a
pointer) is, by definition, identical
to *((x)+(i)).
reference: http://www.lysator.liu.se/c/c-faq/c-2.html
you need to understand the basic concept of arrays.
when you declare an array i.e
int farr[]
you are actually declaring a pointer with this declaration
const int * farr
i.e; a "constant" pointer to integer. so when you do farr++ you are actually trying to add up to a pointer which is constant, hence compilers gives you an error.
if you need to understand, try to declare a pointer with the above declaration and you would not be able to do the arithmetic which are legal on normal pointers.
P.S:
its been quiet a while i have coded in C so i am not sure about exact syntax. but bottom line is the difference between a pointer and a constant pointer.