Which way is better to pass arrays as function arguments in C?

你离开我真会死。 提交于 2021-01-21 09:24:08

问题


There are 3 ways to pass arrays as function arguments.

  • Formal parameters as a pointer, e.g., void myFunction(int *param) {}
  • Formal parameters as a sized array, e.g., void myFunction(int param[10]) {}
  • Formal parameters as an unsized array, e.g., void myFunction(int param[]) {}

Which way is better in terms of efficiency and readability?


回答1:


Which way is better to pass arrays as function arguments in C?

I am going for Door #4. The receiving function needs to know the size.

void myFunction(size_t array_element_count, int *param);

Alternatively code could use a terminating sentinel, but there are no special "I-am-not-an-int" values.

In terms of the below, they emit the same code. This is a style issue. As such, follow the group's style guide. For me I favor size_t array_element_count, int param[array_element_count] as most informative to code's intent.

void myFunction(size_t array_element_count, int *param);
void myFunction(size_t array_element_count, int param[array_element_count]);
void myFunction(size_t array_element_count, int param[]);

In terms of style, f(size, ptr) vs f(ptr, size), I recall reading on the next C rev promoting f(size, ptr). IAC, with more complex arrays and VLA support , the below is useful:

foo(size_t row, size_t col, matrix[row][col]);



回答2:


As far as the compiler is concerned, there is no difference.

Section 6.7.6.3p7 of the C standard regarding Function Declarators states:

A declaration of a parameter as ‘‘array oftype’’ shall be adjusted to ‘‘qualified pointer totype’’, 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 int *param, int param[10], and int param[] as functions parameters are exactly equivalent. The only difference is in terms of readability.

Generally, I would use the array syntax without the size if an array is expected so it's clearer to the reader what the parameter is for.




回答3:


All three notations are equivalent, which makes the sized array declaration very confusing:

With void myFunction(int param[10]); you will not get strong type checking and sizeof(param) will be the size of an int* pointer, not that of the array passed to the function. Avoid this notation for these reasons.

C99 introduced a new syntax to specify that a pointer argument must point to an array of at least a certain number of items:

void myFunction(int param[static 10]);

This notation is not very common and compilers do not fully check the size constraint that it implies. Note also that sizeof(param) is still that of a pointer. So part of the confusion remains.

For readability, I would suggest using void myFunction(int *param); if param points to an int variable and void myFunction(int param[]); if param points to an array of int. The size of this array should be passed as a separate argument.

With this convention, I usually define main as:

int main(int argc, char *argv[]) { ... }



回答4:


If you know the size at compile time and can do it (e.g., because you aren't passing a pointer to a subarray), then I would say

struct ints10 { int ints10[10]; };
void myFunction(struct ints10 *param);

because that can be strongly type-checked and sizeof will work on the destination as expected.

Otherwise

void myFunction(int param[10]);
void myFunction(int param[2]);
     //doesn't matter that the sizing is inconsistent here
     //the (innermost, e.g., if you have `int a[2][3][4]` in a param, it gets adjusted to `int (*a)[3][4]`) size is 
     //is adjusted to a pointer and isn't checked (comptime or runtime)
     //for consistency only for positiveness (comptime)
void myFunction(int param[]);
void myFunction(int *param);

are all fully compatible as far as typechecking is concerned because of how array arguments are adjusted to pointers.

I would recommend being as descriptive as possible (i.e., int param[10]) but keep in mind that the innermost index of an array specified as parameter is adjusted to a pointer, which means the size in it is only as good as a comment (except that the contents of it is syntactically checked and verified as a positive integer).

As far as codegeneration is concerned, all mentioned forms should generate the same assembly even on a not-very-smart compiler.

If you don't know the size at compile time, then you need an extra parameter for passing it, but passing it otherwise will make the function a tiny bit less efficient.




回答5:


In terms of a function parameter declaration, all three versions are treated exactly the same way.

Remember that under most circumstances1 array expressions "decay" to pointer expressions - that is, if you have something like

char arr[10];
foo( arr );

the expression arr in the call to foo "decays" from type "10-element array of char" to "pointer to char", so what foo actually receives is an argument of type char *:

void foo( char *a ) { ... }

As a "convenience", you may declare a as char a[10] or char a[], but they will be interpreted as char *a.


  1. Except when it is the operand of the sizeof, _Alignof, or unary & operators, or is a string literal used to initialize a character array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T and the value of the expression will be the address of the first element of the array.



来源:https://stackoverflow.com/questions/61777092/which-way-is-better-to-pass-arrays-as-function-arguments-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!