Possible to declare an array in function argument? [duplicate] - c

This question already has an answer here:
Why can't I pass constant arrays as arguments?
(1 answer)
Closed 4 years ago.
Is there some way to pass an array of ints into a function in C, like this:
func(int[]{1, 2, 3});
or like this?
func({1, 2, 3});
I am aware of the existence of va_list, but it's not quite what I am looking for.

It looks like you're looking for a compound literal (defined in C11 §6.5.2.5 Compound literals; also a feature in C99):
func((int[]){ 1, 2, 33, 491 });
A compound literal looks like a cast followed by a braced initializer for the type specified in the cast. The scope of the compound literal is to the end of the statement block in which it is introduced, so it will be valid for the entire block in which the call to func() is found. Consequently, it is valid for the whole of the call to func(). And the compound literal is a modifiable value.
We can validly quibble about the interface to the function not specifying how many values are in the array (so how does func() know how big the array is), but that is somewhat tangential to the idea of the compound literal notation.
The function itself is a perfectly ordinary function taking an array argument:
extern void func(int arr[]);
void func(int arr[])
{
…
}
Or, of course:
extern void func(int *arr);
void func(int *arr)
{
…
}
And (with the major caveat about how the function knows how big the array is), you could write:
void calling_func(void)
{
func((int[]){ 1, 2, 33, 491 });
int array[] = { 2, 99, 462, -9, -31 };
func(array);
}

Related

passing array initial values to a C macro [duplicate]

This has been bugging me for some time, for example, if I'm trying to write this code:
// find the length of an array
#define ARRAY_LENGTH(arr) (sizeof(arr)/sizeof(int))
// declare an array together with a variable containing the array's length
#define ARRAY(name, arr) int name[] = arr; size_t name##_length = ARRAY_LENGTH(name);
int main() {
ARRAY(myarr, {1, 2, 3});
}
The code gives this error:
<stdin>:8:31: error: macro "ARRAY" passed 4 arguments, but takes just 2
Because it sees ARRAY(myarr, {1, 2, 3}); as passing ARRAY the argument myarr, {1, 2, and 3}. Is there any way to pass an array literal to macros?
EDIT: In some of the more complex macros I needed, I may also need to pass two or more arrays to the macro, so variadic macro does not work.
Yes, the {} aren't parenthesis for the preprocessor. You can simply protect the arguments by a dummy macro
#define P99_PROTECT(...) __VA_ARGS__
ARRAY(myarr, P99_PROTECT({1, 2, 3}));
Should work in your case. By that you have a first level of () that protects the , from being interpreted as argument separator. These () of the macro call then disappear on the expansion.
See here for more sophisticated macros that do statement unroling.

What is the use of this kind of declaration? [duplicate]

This question already has answers here:
typedef int (*pf) needs explaining
(5 answers)
Closed 8 years ago.
I came across this kind of a declaration.
typedef int (*func) (int,int,int);
What is the meaning and use of this?
It defines func as type for function which accepts 3 integers and returns integer.
This is helpful when you pass functions as callbacks or put function addresses into arrays or something like that.
That's the typedef'd name. It reads as: func is a pointer to a function that takes three ints and returns an int.
You can see more on this link
It defines a type func which is a pointer to a function returning an int and taking 3 int arguments.
An example of using this would be:
typedef int (*func) (int, int, int);
int foo(int a, int b, int c) {
return a + b * c;
}
...
// Declare a variable of type func and make it point to foo.
// Note that the "address of" operator (&) can be omitted when taking the
// address of a function.
func f = foo;
// This will call foo with the arguments 2, 3, 4
f(2, 3, 4);
A more realistic scenario might be having a bunch of functions that have the same return type and taking the same type/number of arguments, and you want to call different functions based on the value of some variable. Instead of having a bunch of if-statements or a large switch/case you could place the function pointers in an array and use an index to call the appropriate function.

Declaring C arrays

int array[5][3];
(obviously) creates a multi-dimensional C array of 5 by 3. However,
int x = 5;
int array[x][3];
does not. I've always thought it would. What don't I understand about C arrays? If they only allow a constant to define the length of a C array, is there a way to get around this in some way?
In ANSI C (aka C89), all array dimensions must be compile-time integer constants (this excludes variables declared as const). The one exception is that the first array dimension can be written as an empty set of brackets in certain contexts, such as function parameters, extern declarations, and initializations. For example:
// The first parameter is a pointer to an array of char with 5 columns and an
// unknown number of rows. It's equivalent to 'char (*array_param)[5]', i.e.
// "pointer to array 5 of char" (this only applies to function parameters).
void some_function(char array_param[][5])
{
array_param[2][3] = 'c'; // Accesses the (2*5 + 3)rd element
}
// Declare a global 2D array with 5 columns and an unknown number of rows
extern char global_array[][5];
// Declare a 3x2 array. The first dimension is determined by the number of
// initializer elements
int my_array[][2] = {{1, 2}, {3, 4}, {5, 6}};
C99 added a new feature called variable-length arrays (VLAs), where the first dimension is allowed to be a non-constant, but only for arrays declared on the stack (i.e. those with automatic storage). Global arrays (i.e. those with static storage) cannot be VLAs. For example:
void some_function(int x)
{
// Declare VLA on the stack with x rows and 5 columns. If the allocation
// fails because there's not enough stack space, the behavior is undefined.
// You'll probably crash with a segmentation fault/access violation, but
// when and where could be unpredictable.
int my_vla[x][5];
}
Note that the latest edition of the C standard, C11, makes VLAs optional. Objective-C is based off of C99 and supports VLAs. C++ does not have VLAs, although many C/C++ compilers such as g++ which support VLAs in their C implementation also support VLAs in C++ as an extension.
int x = 5;
int array[x][3];
Yes, it does. It's a C99 variable length array. Be sure to switch to C99 mode and be sure to have array declared at block or function scope. Variable length arrays cannot be declared at file scope.
Try:
const int x=5;
int array[x][3];
As you said x has to be a constant or else think what would happen if in the middle of the program you changed the value of x,what would be the dimension of array:(
But by declaring it constan if you change the value of x you get a compile error.

Prototype for variable-length arrays

I am trying to write a function that takes an array of an variable size in c.
void sort(int s, int e, int arr[*]){
...
}
It says that for variable length arrays, it needs to be bounded in the function declaration. What does that mean? I am using xcode 4.0, with the LLVM compiler 2.0.
Thanks for the help.
As I see that no one answers the real question, here I give mine.
In C99 you have variable length arrays (VLA) that are declare with a length that is evaluated at run time, and not only at compile time as for previous versions of C. But passing arrays to functions is a bit tricky.
A one dimensional array is always just passed as a pointer so
void sort(size_t n, int arr[n]) {
}
is equivalent to
void sort(size_t n, int *arr){
}
Higher dimensions are well passed through to the function
void toto(size_t n, size_t m, int arr[n][m]){
}
is equivalent to
void toto(size_t n, size_t m, int (*arr)[m]){
}
With such a definition in the inside of such a function you can access the elements with expressions as arr[i][j] and the compiler knows how to compute the correct element.
Now comes the syntax that you discovered which is only useful for prototypes that is places where you forward-declare the interface of the function
void toto(size_t, size_t, int arr[*][*]);
so here you may replace the array dimension by * as placeholders. But this is only usefull when you don't have the names of the dimensions at hand, and it is much clearer to use exactly the same version as for the definition.
void toto(size_t n, size_t m, int arr[n][m]);
In general for a consistent use of that it is just important that you have the dimensions first in the the parameter list. Otherwise they would not be known when the compiler parses the declaration of arr.
If you're not using the C99 variable length arrays (it appears you are, so see below), the usual solution is to pass in a pointer to the first element, along with any indexes you want to use for accessing the elements.
Here's a piece of code that prints out a range of an array, similar to what you're trying to do with your sort.
#include <stdio.h>
static void fn (int *arr, size_t start, size_t end) {
size_t idx;
for (idx = start; idx <= end; idx++) {
printf ("%d ", arr[idx]);
}
putchar ('\n');
}
int main (void) {
int my_array[] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
fn (my_array, 4, 6);
return 0;
}
This outputs elements four through six inclusive (zero-based), giving:
5 4 3
A couple of points to note.
Using my_array in that function call to fn automatically "decays" the array into a pointer to its first element. This actually happens under most (not all) circumstances when you use arrays, so you don't have to explicitly state &(my_array[0]).
C already has a very good sort function built in to the standard library, called qsort. In many cases, that's what you should be using (unless either you have a specific algorithm you want to use for sorting, or you're doing a homework/self-education exercise).
If you are using real VLAs, you should be aware that the [*] construct is only valid in the function prototype, not in an actual definition of the function.
So, while:
void xyzzy(int, int[*]);
is valid, the following is not:
void xyzzy(int sz, int plugh[*]) { doSomething(); }
That's because, while you don't need the size parameter in the prototype, you do very much need it in the definition. And, since you have it, you should just use it:
void xyzzy(int sz, int plugh[sz]) { doSomething(); }
The gcc compiler actually has a reasonably clear error message for this, far better than the "needs to be bounded in the function declaration" one you saw:
error: ‘[*]’ not allowed in other than function prototype scope
What you want to do it make your argument an int *; pass in the length of the array (which the caller presumably knows, but this routine does not) as a separate argument. You can pass an array as such an argument.
The usage of * inside of array brackets for variable-length arrays is limited to prototypes, and serves merely as a placeholder. When the function is later defined, the array's size should be stored in a variable available at either file scope or as one of the parameters. Here's a simple example:
void foo(int, int[*]);
/* asterisk is placeholder */
void foo(int size, int array[size]) {
/* note size of array is specified now */
}

Passing array literal as macro argument

This has been bugging me for some time, for example, if I'm trying to write this code:
// find the length of an array
#define ARRAY_LENGTH(arr) (sizeof(arr)/sizeof(int))
// declare an array together with a variable containing the array's length
#define ARRAY(name, arr) int name[] = arr; size_t name##_length = ARRAY_LENGTH(name);
int main() {
ARRAY(myarr, {1, 2, 3});
}
The code gives this error:
<stdin>:8:31: error: macro "ARRAY" passed 4 arguments, but takes just 2
Because it sees ARRAY(myarr, {1, 2, 3}); as passing ARRAY the argument myarr, {1, 2, and 3}. Is there any way to pass an array literal to macros?
EDIT: In some of the more complex macros I needed, I may also need to pass two or more arrays to the macro, so variadic macro does not work.
Yes, the {} aren't parenthesis for the preprocessor. You can simply protect the arguments by a dummy macro
#define P99_PROTECT(...) __VA_ARGS__
ARRAY(myarr, P99_PROTECT({1, 2, 3}));
Should work in your case. By that you have a first level of () that protects the , from being interpreted as argument separator. These () of the macro call then disappear on the expansion.
See here for more sophisticated macros that do statement unroling.

Resources