Passing array to function

Question 1:
I was able to use a range-based for loop (RBFL) in main() for my array, but when I passed it by value (which makes a copy) to a function in PassArray I was not able to use RBFL. It gives this error:

"[Error] 'begin' was not declared in this scope; did you mean 'std::begin'?"

So I did some searching and it turns out a pointer does not contain size information, but that the array does and that it needs a begin() & end(). I also find out that it is better to use a vector and that in C++ "std::span" is available. I have the latest VS and have the project set to C++20, but it still says identifier span is undefined and not found.

Question 2:
In my "PassArray2(ptrArray);" is there a way to send an argument of the address of my array without having to create a pointer to it or does it just require a pointer? I tried a number of ways where I have commented "//Not work".

Question 3:
In my "PassArray3(myIntArray);"

I know that one can create a reference to a particular index of an array, but does it even make any sense to make a function with a reference to the array itself? A reference to an array does not have the address and size of array nor does it have the pointer ability to reference the indeces, so it may not even make sense. Perhaps there is a way to send the reference that I am not aware of?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include <iostream>

using namespace std;

void PassArray(int myIntArray[])
{
	//PROBLEM printing ('std::begin')
//	for (auto index : myIntArray)
//		cout << index << " ";
		
	//This works
	for (int index = 0; index < 4 ; ++index)
		cout << myIntArray[index] << " ";
	
	cout << endl;
}

void PassArray2(int* myIntArray)
{
	//PROBLEM printing ('std::begin')
//	for (auto index : myIntArray)
//		cout << index << " ";

	//PROBLEM printing 'span' not defined
	//for (auto index : span(myIntArray, 4))
	//	cout << index << " ";


	//This works
	for (int index = 0; index < 4; ++index)
		cout << myIntArray[index] << " ";
	
	cout << endl;
}

void PassArray3(int& myIntArray)
{
	//for (int index = 0; index < 4; ++index)
	//	cout << myIntArray[index] << " ";
}

int main()
{
	int myIntArray[4] = { 1,2,3,4 };

	//This works
	for (auto index : myIntArray)
		cout << index << " ";
	cout << endl;

	//*************************************************************************
	//			1) PASS FULL ARRAY:

	PassArray(myIntArray);




	//*************************************************************************
	//		2) PASS ARRAY POINTER:
	//PassArray2(&(myIntArray[0]));		//Not work
	//PassArray2(&myIntArray[0]);		//Not work
	//PassArray2(&myIntArray);			//Not work
	//PassArray2(myIntArray);			//Not work
	//PassArray2(&&myIntArray);			//Not work
	//PassArray2(myIntArray + 0);		//Not work
	//PassArray2(&(myIntArray + 0));	//Not work
	

	//This works when you add a pointer for the argument
	int* ptrArray = myIntArray;
	PassArray2(ptrArray);

	//PROBLEM printing 'span' not defined
	for (auto index : span(ptrArray, 4))
		cout << index << " ";
	cout << endl;

	//*************************************************************************	
	//		3) PASS ARRAY REFERENCE:
	PassArray3(myIntArray);

	return 0;
}

I have the latest VS and have the project set to C++20, but it still says identifier span is undefined and not found.

Set the language standard to c++latest, a quirk in how VS implemented C++20.

There are C++20 features that don't require setting to c++latest, better to just do it anyway.
When you pass an array it decays to a pointer. That has lots of advantages in terms of speed but deficiencies in that the receiving procedure has no idea how big the array is. Pass the array size or use a vector. The same amount of information will get passed.
Passing a regular array to a function the array will "decay to a pointer," no way around it, no matter which one of three ways you declare your formal function parameters.

https://www.tutorialspoint.com/cplusplus/cpp_passing_arrays_to_functions.htm
but that the array does and that it needs a begin() & end(). I also find out that it is better to use a vector and that in C++ "std::span" is available


careful here.
std::array and a C array are different, std::array is a lot like a vector and is a c++ object. C arrays are not objects. While you can compute the size of a C array, it is not really any better than passing it along since you already knew it (must be a compile time constant). The computation is odd looking and does as much or more work than just providing the value. C++ std::array knows its size, of course. A vector isn't 'better' in general, std:: array exists for a reason, and C arrays are also very handy for some simple tasks. Vectors are good at what they do, and most use them as the default go-to container, but we have 10 or more containers and each on has strengths that may make them better or worse than just going vector on everything.
Last edited on
I was able to use a range-based for loop (RBFL) in main() for my array, but when I passed it by value (which makes a copy) to a function in PassArray I was not able to use RBFL.

Yes you can use a range based loop only when the array is in scope, you loose scope when you you try to pass the array to the function. By the way, do you realize that the "copy" you are thinking about is a pointer, not a "copy" of the actual array.

So I did some searching and it turns out a pointer does not contain size information,

Yes a pointer is not an array, it is a pointer. When you try to pass an array to a function you are actually only passing a pointer to the array.

I also find out that it is better to use a vector

Yes in C++ std::vector should be preferred over raw arrays in most cases.

and that in C++ "std::span" is available. I have the latest VS and have the project set to C++20, but it still says identifier span is undefined and not found.

Did you read any documentation for std::span? Did you #include the proper header file that defines std::span?

In my "PassArray2(ptrArray);" is there a way to send an argument of the address of my array without having to create a pointer to it or does it just require a pointer?

Yes you can just use the name of the array which decays to a pointer. You never actually pass an array to a function, you pass a pointer.

Do you realize that the following two function definitions are actually the same?

1
2
int function(int name[])
int function(int *name)


Do you realize that this: void PassArray3(int& myIntArray)
expects a single integer, not an array?

EDIT:

By the way when working with raw arrays you really should pass the size to the function, to help eliminate trying to access your array out of bounds.

Last edited on
Template argument deduction makes passing an array easy:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>

template <class T, std::size_t N>
constexpr std::size_t size(const T(&array)[N]) noexcept
{
   return N;
}

int main()
{
   int arr[] { 1, 2, 3, 4, 5 };

   std::cout << "The length of the array is " << size(arr) << '\n';
}
The length of the array is 5
I also find out that it is better to use a vector

A C++ container is always a better choice vs. a C style array, whether it be std::list, std::vector or even std::array. Passing a C++ container to a function it doesn't decay to a pointer.

Overloading iostream's operator<< makes displaying a C++ container as simple as displaying Plain Old Data like an int or double.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <array>
#include <iostream>
#include <string>
#include <vector>

template <typename T, size_t N>
constexpr std::ostream& operator<<(std::ostream&, std::array<T, N> const&) noexcept;

template <typename T>
constexpr std::ostream& operator<<(std::ostream& os, const std::vector<T>&) noexcept;

int main()
{
   std::array<int, 5> a { 1, 2, 3, 4, 5 };
   std::cout << a << '\n';

   std::array<double, 3> b { 6.1, 7.275, 8.3333333333 };
   std::cout << b << '\n';

   std::array<std::string, 4> c { "Test", "Word", "Hello", "Good-bye" };
   std::cout << c << '\n';

   std::vector v { 10, 15, 20, 25, 30 };
   std::cout << v << '\n';

}

template <typename T, size_t N>
constexpr std::ostream& operator<<(std::ostream& os, std::array<T, N> const& arr) noexcept
{
   os << "The array contains " << arr.size() << " elements.\n";

   for (const auto itr : arr)
   {
      os << itr << ' ';
   }
   os << '\n';

   return os;
}

template <typename T>
constexpr std::ostream& operator<<(std::ostream& os, const std::vector<T>& vec) noexcept
{
   os << "The vector contains " << vec.size() << " elements.\n";

   for (auto const& x : vec)
   {
      os << x << ' ';
   }

   return os;
}
The array contains 5 elements.
1 2 3 4 5

The array contains 3 elements.
6.1 7.275 8.33333

The array contains 4 elements.
Test Word Hello Good-bye

The vector contains 5 elements.
10 15 20 25 30
Thanks all, very useful info.

1) No, I did not know a pass by value for an array converts to a pointer, but since the range-based for loop works outside and not inside the function I knew there must be some change. This clarifies a lot!

2) I thought that somehow it is in the iostream/using namespace std;, since the usage is std::span. I guess you can somehow have an include use the same namespace and now it works after I add this:

#include <span>

3) Oh yes, the way I have it now the parameter is a ref to an int.
void PassArray3(int& myIntArray){....}

I actually had it like this before removing the brackets and trying this and that, and it gave me an error message:

void PassArray3(int& myIntArray[])
{
for (int index = 0; index < 4; ++index)
cout << myIntArray[index] << " ";
}

PassArray3(myIntArray);

Error (active) E0251 array of reference is not allowed
Error C2234 'myIntArray': arrays of references are illegal

So If I wanted to, how would I pass my array and have the function parameter as a reference to an array (which it will convert to a pointer)? Or is it just now allowed?


4) I read briefly on templates and am long past needing to read it fully. I will check this when I fully read the chapter and get comfortable with it.

How long did it take you guys to be fully comfortable with C++ and finally proclaim you are a programmer?
How long did it take you guys to be fully comfortable with C++ and finally proclaim you are a programmer?

Well, in my case it hasn't happened yet. Being a self-taught hobbyist I know my knowledge of C++ has got lots of holes.

I've been doing this since before C++98 was officially approved. I might finally "get it" 3 days after I'm dead, but I doubt it.

Whether I can declaim being a programmer or not, certainly not as one for hire as a worthwhile employee.

You can't pass a C style/regular array by reference into a function, no ifs, ands or buts. The thing is already being passed as a pointer.
You can't pass a C style/regular array by reference into a function, no ifs, ands or buts. The thing is already being passed as a pointer.
But you pass an array by reference just above:
1
2
template <class T, std::size_t N>
constexpr std::size_t size(const T(&array)[N])

In this snippet the parameter array is an lvalue reference to array of N elements of type const T.

So If I wanted to, how would I pass my array and have the function parameter as a reference to an array (which it will convert to a pointer)? Or is it just now allowed?
A reference to array looks like int(&xs)[10]. This is the syntax you need.
1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
void f(int(&xs)[10]) 
{
  for (auto const& x: xs) std::cout << x << ' ';
  std::cout << '\n'; 
}

int main()
{
  int xs[10] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
  f(xs);
}


The declaration syntax is not very intuitive, but there is logic to its design:
https://mbozzi.com/cdecl.html
Genuine understanding is better than memorizing some arcane syntax rule:
http://jdurrett.ba.ttu.edu/3345/handouts/RL-rule.html

Note that your compiler was complaining about
int& xs[10];
Because this syntax would declare an array of references. But references are not objects, so such a declaration is nonsense.
WOW, that works!

It is actually easier to see it now that you mention it, that if someone asked me to create an array of references...I would write:

int& myIntArray[10];

And if someone said write an array of pointers, it would be:

int* myIntPointers[10];

Yet, the below line is still not intuitive to me and I understand some of the contents of the links, but not all of it and will have to read it slowly and absorb it. I don't think that I would have ever guessed this.

int(&xs)[10]

So this is a true reference to the array and does not convert to a pointer on the function side (in the background)?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>
#include <span>

using namespace std;


void PassArray3(int (&myIntArray)[])
{
	//This works
	for (auto index : span(myIntArray, 4))
		cout << index << " ";
	cout << endl;

	//This works
	for (int index = 0; index < 4; ++index)
		cout << myIntArray[index] << " ";
	cout << endl;
}

int main()
{
	int myIntArray[4] = { 1,2,3,4 };



	//****************************************************************
//					3) PASS ARRAY REFERENCE:

	PassArray3(myIntArray);


	return 0;
}

So this is a true reference to the array and does not convert to a pointer on the function side (in the background)?
Yes. You need to know these two things when talking about "array decay":

First, the compiler silently rewrites function parameters that have array types.
If you declare a function like void f(int x[100]), the compiler will re-write it into void f(int* x). This process only applies to arrays. References are not arrays and so reference parameters like myIntArray in void PassArray3(int (&myIntArray)[]) are not re-written at all.

(Note this is a simplification, for the actual rules see [dcl.fct]/5)
https://eel.is/c%2B%2Bdraft/dcl.fct#5

Second, there is an implicit conversion from an array of T to T*.
This is called the array-to-pointer conversion and it happens to x on lines 5 and 6 of the following program:
1
2
3
4
5
6
7
void f(int* z) {}
int main() 
{ 
  int x[10]; 
  int* y = x; 
  f(x); 
}

The below line is still not intuitive to me

Well, it's a particularly tough example, because references don't exist in C and don't obey the pattern that Dennis Ritchie designed C's declarations to have.

It's probably easier to understand pointer-to-array declarations because they do obey the pattern:
Given this declaration:                      int (*x)[10]; 
if you write this in your computer program         x
you'll get a value with type                 int (* )[10]  (that's a pointer-to-array of 10 int)

Given this declaration:                      int (*x)[10]; 
if you write this in your computer program       (*x)
you'll get a value with type                 int     [10]  (that's an array of 10 int.)

Given this declaration:                      int (*x)[10]; 
if you write this in your computer program       (*x)[1 ]
you'll get a value with type                 int          
Last edited on
Topic archived. No new replies allowed.