Solarian Programmer

My programming ramblings

C++ - Passing a C-style array with size information to a function

Posted on November 28, 2016 by Sol

When you pass a C-style array to a function it will decay to a pointer to the first element of the array, basically losing the size information.

As a side note, in a pure C++ code, one will prefer to use std::vector or std::array instead of C-style arrays. However, there are cases like in embedded systems in which using the Standard Template Library is forbidden by your company guide rules or simply not available on the platform. This is why I think the approach presented in this article could be of some interest to C++ programmers.

In C, you will need to pass the size of the array as an extra parameter to the function or use a global variable. A potential problem with this approach is that it is easy to screw up by forgetting the array to pointer decay rule or by passing the wrong size information.

Here is an example of a classical bug when one forgets about the array to pointer decay rule:

 1 void func(int *my_array) {
 2 	// Wrong, my_array_size won't be equal with the actual number of the elements from the original array
 3 	size_t my_array_size = sizeof(my_array)/sizeof(my_array[0]);
 4 
 5 	// ...
 6 
 7 }
 8 
 9 int main() {
10 	// C-style array
11 	int my_array[5] = {1, 2, 3, 4, 5};
12 
13 	// Good, here my_array_size will be 5!
14 	size_t my_array_size = sizeof(my_array)/sizeof(my_array[0]);
15 	return 0;
16 }

As mentioned before, a better version is to pass the array information to the function:

 1 void func(int *my_array, size_t my_array_size) {
 2 
 3 	// ...
 4 
 5 }
 6 
 7 int main() {
 8 	// C-style array
 9 	int my_array[5] = {1, 2, 3, 4, 5};
10 
11 	// Good, here my_array_size will be 5!
12 	size_t my_array_size = sizeof(my_array)/sizeof(my_array[0]);
13 
14 	// Pass both the array and the array size to the function
15 	func(my_array, my_array_size);
16 	return 0;
17 }

A problem with the above approach is that nothing prevents you from passing the wrong size information to the function, e.g:

1 int main() {
2 	// C-style array
3 	int my_array[5] = {1, 2, 3, 4, 5};
4 
5 	// Pass both the array and the array size to the function
6 	func(my_array, 50);		// Disaster waiting to happen! passing the wrong size information
7 	return 0;
8 }

A potential solution, for the C language, to the above problem is to use a macro that will always put the correct size of the array, something like:

 1 #define COUNT_OF(array) (sizeof(array) / sizof(array[0]))
 2 
 3 int main() {
 4 	// C-style array
 5 	int my_array[5] = {1, 2, 3, 4, 5};
 6 
 7 	// Pass both the array and the array size to the function
 8 	func(my_array, COUNT_OF(my_array));		// Better C approach
 9 	return 0;
10 }

You can obviously avoid the pointer decay problem if you use a global variable, however this is considered a bad practice so we won’t discuss it here.

If you are using C++ there is a better approach, you can pass the array as a reference to the function, this way you will keep the size information:

 1 // The array is passed as a reference to the function, keeping the size information (only for C++)
 2 template<typename T, size_t N>
 3 void func(T (&a)[N]) {
 4 	// Here N stores the correct size information for the array
 5 	// Basically N is equal to sizeof(my_array)/sizeof(my_array[0]) so the next code will work as expected:
 6 	for(int i = 0; i < N; ++i) {
 7 		a[i] = a[i] + i;
 8 	}
 9 }
10 
11 
12 int main() {
13 	// C-style array
14 	int my_array[5] = {1, 2, 3, 4, 5};
15 
16 	// Pass the array to a function
17 	func(my_array);
18 	return 0;
19 }

Similarly, you can pass a multi-dimensional C-style array to a function without losing the size information:

1 template<typename T, size_t M, size_t N>
2 void func(T (&my_array)[M][N]) {
3 	// Here M = no. of lines and N = no. of columns
4 	// ....
5 }

If you are interested to learn more about modern C++ I would recommend reading A tour of C++ by Bjarne Stroustrup.

or Effective Modern C++ by Scott Meyers.


comments powered by Disqus