I want to pass this two dimensional array of pointers to a function:
array:
*cmd[maxCmdSize][maxArgSize]
function:
void performCmd(char *cmd[maxCmdSize][maxArgSize])
How to achieve this without declaring the size of the dimensions in the function?
How to achieve this without declaring the size of the dimensions in the function?
You cannot omit the second dimension of the array.
So you need to have your prototype like this:
void performCmd(int *cmd[][maxArgSize]);
and call the method like this:
performCmd(cmd);
With VLA parameters (VLAs, i.e., variadic-length arrays, are an optional standard extension of C11), you can
pass the size as another parameter (which needs to preceede the VLA).
The innermost index, where the array decays to a pointer (an int *cmd[][maxArgSize] in a function parameter is equivalent to int *(*cmd)[maxArgSize]) need not be passed an does not affect multidimensional array-based pointer arithmetic.
int performCmd(int maxArgSize, char *cmd[][maxArgSize]);
int performCmd(int maxArgSize, char *cmd[][*]); //compatible alternative declaration
int performCmd(int maxArgSize, char *cmd[][maxArgSize])
{
return &cmd[1][0]-&cmd[0][0]; //returns maxArgSize
}
Also in a declaration (but not definition), the VLA size can be replaced with *.
(In the definition then, the size can also be any nonconst expression (including possibly a function call) not necessarily just a simple variable reference.)
Without VLA support you can simply pass a pointer to the base type and the dimensions, and then use that to emulate multidimensional pointer arithmetic on the base array.
Given, for example char x[2][3][4][5];, &x[1] means (char(*)[3][4][5])x + 1, (i.e., (char*)x+1*(3*4*5)), &x[1][1] means (char (*)[4][5])((char(*)[3][4][5])x+1) + 1 (i.e., (char*)x+1*(3*4*5)+1*(4*5)), etc. This works the same when the array dimensions are dynamic, and then you can use this math to translate a dynamic dimension, a base pointer, and a set of indices into an offset without having to rely on VLA support.
You would probably have to pass a char double pointer, and the two dimensions as other parameters.
void performCmd(char** cmd, int maxCmdSize, int maxArgSize) {
//do whatever this function does
}
Related
I'm currently learning function that work with multi-dimensional array in C.
Let's say I have
short myArray[10][30].
I have declared following function prototype to work with myArray.
void first(int n, short ar[][30]);
void second(int n, short ar[30]);
void third(int n, short (*ar)[30]);
My understanding is that the ar parameter in both first and third function are equivalent. short ar[][30] in first function is equivalent to the short (*ar)[30] in third function because they are both pointer to array of 30 short.
The ar in second function is different because in short ar[30], ar is a pointer to short, not a pointer to array of 30 short.
Is my understanding correct?
Yes your understanding is correct. 1 and 3 are equivalent. And 2 is also right (But not for passing 2d array - it is correct for passing 1D array). But will clarify a bit the second case.
And the second one that 30 inside of third brackets are not considered by the compiler. You can omit it still the compiler won't complain. Actually here you have passed an 1D array of short that decayed into pointer to the first element (First element being short it is short*). So the second one you can also write as short *ar.
void second(int n, short ar[]);
void second(int n, short* ar );
These two works and they are equivalent in this context. The second one is for passing 1D array something like
second(n, myArray[5]);
The thing is, most of the time array decays into pointer (exception is sizeof operator or Alignof etc). Passing an array to a function is a case where the array decays.
Also you are passing int arrays so it is wrong to write short.(int and short may have same size but it is guaranteed that size of int would be larger than or equal to the size of short). If you used short and then wrote int in the declaration that would have worked.
Edit: The second one is not for passing 2d array. Let's be clear on that. You can't pass 2d array to a function with the prototype declared as the second one. For pointers there are 2 things to consider - it's type and it's value. If you tried to pass a 2d array to the same function that would be illegal. 2d array decays into int (*)[30] which is not in anyway same as int * or int[].
1 and 3 are indeed the same, as would be
void fourth(int n, short ar[10][30]);
because when you pass an array as function parameter, it decays to a pointer to its first parameter, so the compiler sees 1 and 4 as 3.
That explains why this would also be correct:
void fifth(int n, short arr[15][30]);
As it decays to a pointer, the declared size of the first dimension is not used. You are supposed to give the actual size in another way.
But this one is different:
void second(int n, short ar[30]);
and your compiler should raise a warning there because the expected paramater is a pointer to short, when you pass a pointer to an array of 30 short. Of course the pointers will have same value (same address), and common compilers will give expected results, but aliasing a pointer to array and a pointer to element is not allowed by the standard. So please avoid it.
With such a declaration, second should be called as
cr = second(n, arr[0]);
because arr[0] is a short array and will correctly decay to a short *.
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);
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
}
I want to manipulate an array of integers in a function, but I am not sure if I should use the address prefix or the pointer prefix:
void shuffle(int *deck[]){
//statements
}
or
void shuffle(int &deck[]){
//statements
}
Further, when I directly want to manipulate the values of the array, I'm not sure if I should use (within the function)
*deck[4] = 34
or something else.
Any clarification is appreciated.
There are no references in C(your Q is tagged C only) so you will have to use the pointer version.
When you say pass an array to the function, what you essentially pass to the function is the pointer to its first element, both of the following two syntaxes mean one and the same thing to the compiler:
void shuffle(int *p_deck);
void shuffle(int deck[]);
Neither.
Since arrays can be passed by reference only, you don't need to do tricks, just pass a pointer and dereference it. (That syntax involving the & in your 2nd function is not valid, anyway). So:
void shuffle(int arr[])
{
arr[0] = 1337;
}
or
void shuffle(int *arr)
{
}
etc. And you can pass it like this:
int deck[52];
shuffle(deck);
You would have to use the pointer version, but because of the Right-Left Rule, I believe your:
int * deck[] would actually be an array of int pointers, instead of an array of ints.
http://cseweb.ucsd.edu/~ricko/CSE131/rt_lt.rule.html
You should just pass a reference to the first element in the array:
int * deck but you may want to pass in the size of the array so you avoid going out of bounds.
Arrays decay into pointers when passed to functions, so there's no point in using an additional level of indirection here.
According to §6.3.2.1 of the C99 standard,
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.
void shuffle(int deck[]) {
...
}
Note that C does not support references, only pointers. You're probably thinking of C++.
You can pass an array by reference in C++, if you specify the size of the array:
void shuffle(int (&deck)[52])
{
deck[4] = 34;
}
If you don't know the size, or if you're limited to C, you need to use pointers.
The other (C++) option is to use a vector for the deck and pass a reference to the vector instead.
C doesn't have references (a), that's C++.
In C, arrays of X decay into a pointer to X[0] when passed to functions, so one way is to use:
void shuffle (int *pDeck) {
// use pDeck[something]
}
:
int deck[] = {0,1,2,3,4,5,6,7,8,9};
shuffle (deck);
I actually prefer that method to the void shuffle (int pDeck[]) variant since the former makes it absolutely clear that you're now dealing with a pointer rather than an array.
The reason this is important is because you lose the size information when you do that, so you may want to pass that in as well:
void shuffle (int *pDeck, size_t sz) {
// use pDeck[0 thru sz-1]
}
:
int deck[] = {0,1,2,3,4,5,6,7,8,9};
shuffle (deck, sizeof (deck) / sizeof (*deck));
(a): Although they are a very nice feature. I do hope that ISO considers them for the next C standard, since a large number of problems newcomers to the language have are involved with pointers, and references can hide the complexity of that very well.
gcc 4.6.2 c89
I have the following 2D array that I want to pass to a function:
char elements[MAX_NUM_ELEMENTS][MAX_STRING_LEN] = {{0}};
My function prototype is:
int get_elements(char **elements)
And I am calling the function like this:
get_elements(elements);
However, I get the following error:
expected ‘char **’ but argument is of type ‘char (*)[128]’
All arrays declay into pointers, so sure why I can't just pass the pointer.
Many thanks for any advice,
"All arrays decay into pointers" is a common misconception about C.
The first few answers in this FAQ clarify the issue.
If the object to pass to your function is defined as:
char elements[MAX_NUM_ELEMENTS][MAX_STRING_LEN];
Your function prototype should not be:
int get_elements(char **elements)
but rather:
int get_elements(char elements[][MAX_STRING_LEN])
or
int get_elements(char (*elements)[MAX_STRING_LEN])
(both forms are equivalent)
The reason for this is the type of the value of an object of type
char [MAX_NUM_ELEMENTS][MAX_STRING_LEN]
is
char (*)[MAX_STRING_LEN] (a pointer to an array of MAX_STRING_LEN chars) and not char ** (a pointer to a pointer of char).
You can cast:
get_elements((char **) elements);
char ** and char[128][128] are obviously different types.
"Two -dimensional Array and Double Pointer are not the Same"
"A two - dimensional Array is a array of pointers"
Is what I learnt/memorized while reading about array and pointer
Say elements- data has memory startin Location 100 ..
And the elements Pointer has memory at Location 50 ..
The element data gets allocated memory from 100 to 100+MAX_NUM_ELEMENTS * MAX_STRING_LEN -1..
And you need to access data from 100 ..
But you are passing element as a double pointer .. so it tries to access ( 50->100->Actual data's) Location instead of accessing ( 50-> 100)'s location ..
If you change the prototype to int get_elements( char *element[]) .. It will work ..
Your prototype looks very broken, it lacks a type name.
And you can't use a "decayed" pointer, since that would lose the information about the dimensions of the array, which are (obviously) needed in order to compute accesses properly.
The best way, in my opinion, is to pass a pointer to the first element, along with the dimensions as needed. For 2D, this would do:
int get_elements(int *elements, size_t width, size_t height);
This also requires that you decide, and adhere to, an in-memory layout for your elements, such as column-major or row-major. This affects how you compute the address for a given element.