I have a function in C (I am using gcc 4.8.0) which receives an array as its argument. Is there a way to accurately determine the number of elements in the array, without passing an additional argument array_count?
There is no way to determine in general the number of array elements passed as parameter.
When you pass a array as argument in C, you only pass the pointer to that array, that is the pointer to the first element (indexed 0) of the memory zone holding that array.
Very often, programmers have the convention of passing, as another argument, the size of that array. For example, the standard qsort(3) library function is expecting, as its second nmemb argument, the number of elements in the array to be sorted.
Alternatively, you might use flexible array members, e.g. pass (in C99, not in earlier C standard) address of structures like
struct my_flexarray_st {
int size; // allocated size
int len; // used length, should be less than size
double arr[]; /// only len numbers are meaningful
};
Whatever method you use, you need to understand that array sizes are conventionally known by functions when passed by argument. So please, document that convention. You could even have the (bad) convention that all arrays have some global variable as their dimension.
For heap allocated memory zones, the standard gives you malloc, calloc and friends to get such fresh zones, but no way to query their allocated sizes. Some C libraries have non-standard extensions to query that (but I don't recommend using them).
In recent C++11 (which is not the same as the C language) you might be interested by std::vector and std::array template containers.
Arrays decay into pointers in function arguments so size cannot be determined.
An lvalue [see question 2.5] of type array-of-T which appears in an expression decays (with three exceptions) into a pointer to its first element; the type of the resultant pointer is pointer-to-T because an array is not a "modifiable lvalue,"
(The exceptions are when the array is the operand of a sizeof or & operator, or is a literal string initializer for a character array.)
You can't , unless the array is static (i.e. not dynamic-allocated) , then you can use sizeof operator.
Not possible. This is why you either use a data structure like a linked list where you can actually determine the length or you require a length argument in your function.
Even with the required length argument alone there is no way to know it is true.
So, your API should also require a standard sentinel value to terminate the array.
Generally this could be NULL or something but depends on your array type.
This is doable in C. You can query size of array if you are in the same scope of its definition via sizeof. If you are in scope of function which takes array as parameter you need to declare the parameter as pointer to array (not just as array - in this case array will decay to pointer to first element), in this case size of array would be saved during argument passing:
void foo(int (*param)[3] ) { assert (sizeof(*param) == sizeof(int)*3; }
However, if you mean by "array" pointer to some dynamically allocated memory with not-known at compile time size, then you definetely need to pass size separately.
you can do a while look
function(arr[])
{
/* not this is pseduo code */
int i = 0;
while (*arr[i++] != null)
{
}
// i is number of elements
}
Related
This question already has answers here:
Finding length of array inside a function [duplicate]
(7 answers)
Closed 2 years ago.
In C I can write a function declaration in 2 different ways (Which I was told are totally equal)
void test (int *arr);
void test (int arr[]);
But why we every need to use the first one? I mean the latter allows us to get the number of elements in the array using sizeof() something which isn't possible in the first one.
I mean the latter allows us to get the number of elements in the array using sizeof() something which isn't possible in the first one.
No, that's not possible for the latter, too. Here is a misunderstanding of yours. Both notations are absolutely equivalent as function parameter and denote a pointer. arr[] does not denote an array nor a pointer to an array explicitly.
Take a look at here:
C pointer notation compared to array notation: When passing to function
You can only get the size of the array if you use sizeof() at the array name itself inside of the scope the array is visible or pass another argument/parameter to the function which contains the information about the size of an array from the previous sizeof() use.
You cannot use sizeof() at a pointer to an array to get the array size, neither in the function where the array is declared nor in another.
But why we every need to use the first one?
To simple symbolize that it is a single pointer and not an array as this confusion in fact already brought you to here. :-)
I mean the latter allows us to get the number of elements in the array using sizeof() something which isn't possible in the first one.
This statement is wrong.
Both versions are in fact identical.
The function does not know the size of the array and you cannot use sizeof to get the size of the array. Instead you will only get the size of the pointer which the passed array decays to.
I mean the latter allows us to get the number of elements in the array
using sizeof()
No, it is not right information at all as to functions. After passing an array to a function taking the array as a parameter, the array decays into pointer thereby yielding size of the type's pointer type rather than that of the type per se.
For example for int type,
sizeof int
sizeof *int
For illustration,two dimensional pointer arrays in C like int* x[][4] can be declared ,where first index can be fixed at run time that it is dynamic then can i say that dynamic declaration of dynamic one-dimensional array can be achieved in someway by replacing the second index to value 1 like int*[][1] and for two dimensional array dynamic two-dimensional array by int*[][][1] Does calloc() malloc() internally use them is my logic correct at all and this applied that is in a simplistic case of dynamic array declaration use inside a function in C language program
For illustration,two dimensional pointer arrays in C like int* x[][4]
can be declared
Only in two cases:
when an initializer for x implicitly conveys the value of the first dimension,
int* x[][4] = { {NULL, NULL, NULL, NULL}, {NULL, NULL, NULL, NULL} };
as the type of a function parameter. In that case, it is exactly equivalent to declaring the parameter to have type int *(*)[4]: pointer to array of four pointers to int. And that would also be the case if the first dimension were actually given.
void foo(int* x[][4]);
,where first index can be fixed at run time
In case (1) above, no, the first dimension is determined at compile time.
In case (2) above, not exactly. It is then the declaration of a pointer to a 1D array. Such a pointer can point to the first element of a 2D array of int *, and it can be indexed as if it in fact designated such a 2D array. The size of the first dimension is not conveyed, but if the pointer in fact points to an object then that dimension is fixed for the function's purposes, whether the pointed-to object is dynamically allocated or not.
that it is
dynamic then can i say that dynamic declaration of dynamic
one-dimensional array can be achieved in someway by replacing the
second index to value 1 like int*[][1]
That change produces a statically different type (in those contexts where it is valid at all). In case (2), but not case (1), both this type and the one we were discussing previously can point to a dynamically-allocated object, but they can also point to an automatic- or static-duration object of appropriate type. There's nothing inherently dynamic there.
and for two dimensional array
dynamic two-dimensional array by int*[][][1]
No. Not even for the type of a function parameter. At most the (one) leading dimension can be omitted.
Does calloc() malloc()
internally use them
Not at all. How could they? The allocation functions do not see this datatype at all. You tell them only how much space to allocate, either as a single composite value (malloc) or as an (element count, element size) pair (calloc). Thus the caller needs to know how much memory is needed. And this in any event applies only in case (2). Case (1) inherently produces static or automatic allocation, not dynamic.
is my logic correct at all
No.
and this applied that
is in a simplistic case of dynamic array declaration use inside a
function in C language program
Neither as a local variable of a function (case 1) nor as a function parameter (case 2).
Here consider the following sample of code:
int *a = malloc(sizeof(int) * n);
Can this code be used to define an array a containing n integers?
int *a = malloc(sizeof(int) * n);
Can this code be used to define an array a containing n integers?
That depends on what you mean by "define an array".
A declaration like:
int arr[10];
defines a named array object. Your pointer declaration and initialization does not.
However, the malloc call (if it succeeds and returns a non-NULL result, and if n > 0) will create an anonymous array object at run time.
But it does not "define an array a". a is the name of a pointer object. Given that the malloc call succeeds, a will point to the initial element of an array object, but it is not itself an array.
Note that, since the array object is anonymous, there's nothing to which you can apply sizeof, and no way to retrieve the size of the array object from the pointer. If you need to know how big the array is, you'll need to keep track of it yourself.
(Some of the comments suggest that the malloc call allocates memory that can hold n integer objects, but not an array. If that were the case, then you wouldn't be able to access the elements of the created array object. See N1570 6.5.6p8 for the definition of pointer addition, and 7.22.3p1 for the description of how a malloc call can create an accessible array.)
int *a = malloc(sizeof(int) * n);
Assuming malloc() call succeeds, you can use the pointer a like an array using the array notation (e.g. a[0] = 5;). But a is not an array itself; it's just a pointer to an int (and it may be a block of memory which can store multiple ints).
Your comment
But I can use an array a in my program with no declaration otherwise
suggests this is what you are mainly asking about.
In C language,
p[i] == *(p + i) == *(i + p) == i[p]
as long as one of i or p is of pointer type (p can an array as well -- as it'd be converted into a pointer in any expression). Hence, you'd able to index a like you'd access an array. But a is actually a pointer.
Yes. That is exactly what malloc() does.
The important distinction is that
int array[10];
declares array as an array object with enough room for 10 integers. In contrast, the following:
int *pointer;
declares pointer as a single pointer object.
It is important to distiguinsh that one of them is a pointer and that the other as an actual array, and that arrays and pointers are closely related but are different things. However, saying that there is no array in the following is also incorrect:
pointer = malloc(sizeof (int) * 10);
Because what this piece of code does is precisely to allocate an array object with room for 10 integers. The pointer pointer contains the address of the first element of that array.(C99 draft, section 7.20.3 "Memory management functions")
Interpreting your question very literally, the answer is No: To "define an array" means something quite specific; an array definition looks something like:
int a[10];
Whereas what you have posted is a memory allocation. It allocates a space suitable for holding an array of 10 int values, and stores a pointer to the first element within this space - but it doesn't define an array; it allocates one.
With that said, you can use the array element access operator, [], in either case. For instance the following code snippets are legal:
int a[10];
for (int i = 0; i < 10; i++) a[i] = 0;
and
int *a = malloc(sizeof(int) * n);
for (int i = 0; i < n; i++) a[i] = 0;
There is a subtle difference between what they do however. The first defines an array, and sets all its elements to 0. The second allocates storage which can hold an equivalently-typed array value, and uses it for this purpose by initialising each element to 0.
It is worth pointing out that the second example does not check for an allocation error, which is generally considered bad practice. Also, it constitutes a potential memory leak if the allocated storage is not later freed.
In the language the Standard was written to describe (as distinct from the language that would be described by a pedantic literal reading of it), the intention was that malloc(n) would return a pointer that would, if cast to a T*, could be treated as a pointer to the first element of a T[n/sizeof T*]. Per N1570 7.22.3:
The
pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to
a pointer to any type of object with a fundamental alignment requirement and then used
to access such an object or an array of such objects in the space allocated (until the space
is explicitly deallocated).
The definition of pointer addition and subtraction, however, do not speak of acting upon pointers that are "suitably aligned" to allow access to arrays of objects, but rather speak of pointers to elements of actual array objects. If a program accesses space for 20 int objects, I don't think the Standard does actually says that the resulting pointer would behave in all respects as though it were a pointer to element [0] of an int[20], as distinct from e.g. a pointer to element [0][0] of an int[4][5]. An implementation would have to be really obtuse not to allow it to be used as either, of course, but I don't think the Standard actually requires such treatment.
The name of an array is a synonym for the address of the first element of the array, so why can't this address be set to NULL? Is it a language rule to prevent a memory leak?
Also, when we pass an array to a function, it's behavior changes and it becomes possible to set it to NULL.
I don't understand why this occurs. I know it has something to do with pointers, but I just can't wrap my mind around it.
Example:
void some_function(char string[]);
int main()
{
char string[] = "Some string!";
some_function(string);
printf("%s\n", string);
return 0 ;
}
void some_function(char string[])
{
string = NULL;
}
Output: Some string!
I read that when an array is passed into a function, what's actually passed are pointers to each element, but wouldn't the name of the array itself still be a synonym for the address of the first element? Why is setting it to NULL here even allowed, but not in the main function?
Is it at all possible to set an array to NULL?
An array is not a pointer - the symbol string in your case has attributes of address and size whereas a pointer has only an address attribute. Because an array has an address it can be converted to or interpreted as a pointer, and the language supports this implicitly in a number of cases.
When interpreted as a pointer you should consider its type to be char* const - i.e. a constant pointer to variable data, so the address cannot be changed.
In the case of passing the array to a function, you have to understand that arrays are not first class data types in C, and that they are passed by reference (i.e. a pointer) - loosing the size information. The pointer passed to the function is not the array, but a pointer to the array - it is variable independent of the original array.
You can illustrate what is effectively happening without the added confusion of function call semantics by declaring:
char string[] = "Some string!";
char* pstring = string ;
then doing:
pstring = NULL ;
Critically, the original array data cannot just "disappear" while it is in scope (or at all if it were static), the content of the array is the variable, whereas a pointer is a variable that refers to data. A pointer implements indirection, and array does not. When an array is passed to a function, indirection occurs and a pointer to the array is passed rather than a copy of the array.
Incidentally, to pass an array (which is not a first class data type) by copy to a function, you must wrap int within a struct (structs in C are first class data types). This is largely down to the original design of C under constraints of systems with limited memory resources and the need to to maintain compatibility with early implementations and large bodies of legacy code.
So the fact that you cannot assign a pointer to an array is hardly the surprising part - because to do so makes little sense. What is surprising perhaps is the semantics of "passing an array" and the fact that an array is not a first class data type; leading perhaps to your confusion on the matter.
You can't rebind an array variable. An array is not a pointer. True, at a low level they are approximately similar, except pointers have no associated dimension / rank information.
You cant assign NULL to the actual array (same scope), but you can assign to a parameter since C treats it like a pointer.
The standard says:
7 A declaration of a parameter as ‘‘array of type’’ shall be adjusted
to ‘‘qualified pointer to type’’,
So in the function the NULL assignment is legal.
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.