When we need to pass the size of the array as a parameter

I am a bit confused about passing an array in C / C ++. I saw some cases in which the signature is such

void f(int arr[]) 

something like that

 void f(int arr[], int size) 

Can someone figure out what the difference is, when and how to use it?

+4
source share
8 answers

First, the array passed to the function actually passes a pointer to the first element of the array, for example, if you have

 int a[] = { 1, 2, 3 }; f(a); 

Then f() gets &a[0] passed to it. So, when writing prototypes of functions, the following equivalents:

 void f(int arr[]); void f(int *arr); 

This means that the size of the array is lost, and f() , in general, cannot determine the size. (That's why I prefer void f(int *arr) form over void f(int arr[]) .)

There are two cases when f() does not need information, and in these two cases, it does not have an additional parameter.

Firstly, arr has a special, consistent value, which both the caller and f() mean "end". For example, you might agree that a value of 0 means "Finish."

Then one could write:

 int a[] = { 1, 2, 3, 0 }; /* make sure there is a 0 at the end */ int result = f(a); 

and define f() something like:

 int f(int *a) { size_t i; int result = 0; for (i=0; a[i]; ++i) /* loop until we see a 0 */ result += a[i]; return result; } 

Obviously, the above pattern only works if both the caller and the callee agree and follow the agreement. An example is the strlen() function in the C library. It calculates the length of a string by finding 0 . If you give him something that does not have 0 at the end, all bets are disabled and you are in the territory of undefined behavior.

The second case is when you really don't have an array. In this case, f() takes a pointer to an object ( int in your example). So:

 int change_me = 10; f(&change_me); printf("%d\n", change_me); 

with

 void f(int *a) { *a = 42; } 

okay: f() doesn't work in the array anyway.

+8
source

When an array is passed in C or C ++, only its address is passed. That is why the second case is quite common, where the second parameter is the number of elements in the array. The function has no idea, just looking at the address of the array, how many elements it should contain.

+1
source

You can write

 void f( int *arr, int size ) 

since the latter (size) allows you not to go beyond the boundaries of the array when reading / writing to it

+1
source

The first signature simply passes the array without the ability to tell how large the array is, and can lead to problems with errors outside the boundaries and / or security flaws. \

The second signature is a safer version because it allows the function to check the size of the array to prevent the shortcomings of the first version.

If this is not homework, raw arrays are a bit outdated. Use std :: vector instead. It allows you to transfer a vector around without having to manually transfer the size as it does it for you.

+1
source

The size of the array is not transmitted with the array itself. Therefore, if another function needs size, it will have it as a parameter.

The fact is that some functions implicitly understand that an array has a certain size. Therefore, they do not need to explicitly state this. For example, if your function works with an array of 3 floats, you do not need the user to tell you that it is an array of 3 floats. Just take an array.

And then there are these functions (let's call them β€œterrible” because they are) that fill the array with arbitrary data to the point defined by this data. sprintf is probably the "best" example. It will continue to put characters in this array until it finishes writing them. This is very bad because there is no explicit or implicit agreement between the user and the function regarding how large this array can be. sprintf will write a certain number of characters, but the user will not be able to know exactly how many of them are written (in the general case).

This is why you should never use sprintf ; use snprintf or _snprintf , depending on your compiler.

+1
source

Anytime you need to know the size of an array, it should be provided. There is nothing special about the two forms of passing the array itself; The first parameter is the same. The second method simply provides the information needed to determine the size of the array, while the first does not.

Sometimes the array itself contains information about its size. For example, in your first example, perhaps arr[0] given the size of the array, and the actual data starts with arr[1] . Or consider the case of c-lines ... you provide only char[] , and it is assumed that the array ends on the first element equal to \0 . In your example, a negative value can act as a similar watch. Or perhaps the function just does not care about the size of the array and simply assumes that it is large enough.

Such methods are inherently unsafe, although ... it's easy to forget to set arr[0] or accidentally overwrite the null terminator. Then f suddenly does not know how much space he has available. Always prefer to explicitly specify the size, either using the size parameter, as you show, or with a second pointer to the end of the array. The latter is a method commonly used by standard library functions in C ++. You still have the problem of providing the wrong size, therefore, therefore, in C ++ it is not recommended to use such an array in the first place ... use the actual container that will track this information for you.

+1
source

C and C ++ are not the same thing. However, they have some common subset. What you are observing here is that the "first" dimension of an array when passing a function is always obtained only in the passed pointer. "Signature" (C does not use this term) of a function declared as

 void toto(double A[23]); 

always easy

 void toto(double *A); 

The fact that the above 23 somewhat redundant and is not used by the compiler. Modern C (aka C99) has an extension that allows you to declare that A always has 23 elements:

 void toto(double A[static 23]); 

or that the const pointer is qualified

  void toto(double A[const 23]); 

If you add another dimension, the image changes, then the size of the array is used:

 void toto(double A[23][7]); 

in C and C ++ there is

 void toto(double (*A)[7]); 

which is a pointer to an array of elements 7 . In C ++, these array bounds must be an integer constant. In C, it can be dynamic.

 void toto(size_t n, size_t m, double A[n][m]); 

The only thing you need to look here is that here n and m go to A in the parameter list. Therefore, it is better to always indicate functions with parameters in this order.

+1
source

The difference is that the second includes a parameter indicating the size of the array. The logical conclusion is that if you do not use such a parameter, the function does not know what the size of the array is. And indeed it is. In fact, he does not know that you have an array. In fact, you do not need to have an array to call the function.

The array syntax here, without the specified size inside the square brackets, is fake. The parameter is actually a pointer. For more information see http://c-faq.com/aryptr/index.html , especially section 4.

0
source

All Articles