Can anyone please explain!
While referring ArrayDecay, I was stuck at this...,
void fun(int (&p)[7])
{
cout << sizeof(p) << endl;
}
int main()
{
int a[7] = {1, 2, 3, 4, 5, 6, 7,};
cout << "Actual size of array is: ";
cout << sizeof(a) <<endl;
// Calling function by reference
fun(a);
return 0;
}
I know the difference between (*p)[] and *p[] and their functioning.
But, can't figure out what (&p)[] is!.
In the context of function argument declarations, the & means reference.
So the function fun accepts one argument, which is a reference to an array of 7 integer elements.
The comment should have been a pretty big hint:
// Calling function by reference
fun(a);
Related
This question already has answers here:
What is the purpose of sized array as function argument is c and c++?
(2 answers)
Closed 1 year ago.
Does defining a sized array in a function signature (as opposed to the more commonly used unsized array or pointer syntax) have any bearing at all? My compiler is ignoring it completely, as the following sample code shows (which runs, although it prints some garbage values when a smaller-sized array is passed).
#include <iostream>
using namespace std;
void printArray(int intArray[5]) {
for (int i = 0; i < 5; i++) {
cout << intArray[i] << " ";
}
cout << endl;
}
int main()
{
int array1[1] = {1}; // Smaller array size than in the function signature
cout << "\nInvocation 1\n";
printArray(array1);
int array2[4] = {1, 2, 3, 4}; // Smaller array size than in the function signature
cout << "\nInvocation 2\n";
printArray(array2);
int array3[8] = {1, 2, 3, 4, 5, 6, 7, 8}; // Larger array size than in the function signature
cout << "\nInvocation 3\n";
printArray(array3);
return 0;
}
Does defining a sized array in a function signature (as opposed to the more commonly used unsized array or pointer syntax) have any bearing at all?
No, not the way you do it.
This would on the other hand make intArray a reference to the array you pass as an argument:
void printArray(int (&intArray)[5]) {
for (int i = 0; i < 5; i++) {
cout << intArray[i] << " ";
}
cout << endl;
}
A more generic form would be to make it a function template. This would then be instantiated once for each array size you call it with:
template<std::size_t N>
void printArray(int (&intArray)[N]) {
for (int i = 0; i < N; i++) {
cout << intArray[i] << " ";
}
cout << endl;
}
Does defining a sized array in a function signature (as opposed to the more commonly used unsized array or pointer syntax) have any bearing at all?
No, it has not, the passed array argument will always decay to a pointer to its first element, placing a size is indeed pointless from the compiler standpoint, it will ignore it, having void printArray(int intArray[5]){...}, void printArray(int intArray[]){...} or void printArray(int* intArray){...} will be basically the same.
My compiler is ignoring it completely, as the following sample code shows (which runs, although it prints some garbage values when a smaller-sized array is passed).
Which makes sense because in the loop you are accessing elements outside the bounds of the array, so the behavior is undefined.
This is how I would do it using std::array
#include <array>
#include <iostream>
template<typename type_t, std::size_t N>
void printArray(const std::array<type_t,N>& values)
{
for (const auto& value : values)
{
std::cout << value << " ";
}
std::cout << std::endl;
}
void printArray_s(const std::array<int, 5>& values)
{
for (const auto& value : values)
{
std::cout << value << " ";
}
std::cout << std::endl;
}
// helper function to avoid having to type value of N in std::array (syntactic sugar)
// used for array3
template<typename array_type, typename... args_t>
constexpr auto make_array(const args_t&&... values)
{
return std::array<array_type, sizeof...(args_t)>{ static_cast<array_type>(values)... };
}
int main()
{
// Smaller array size than in the function signature
std::array<int,1> array1{ 1 };
std::cout << "\nInvocation 1\n";
//printArray_s(array1); // <== will correctly give compiler error
// Smaller array size than in the function signature
std::array<int, 4> array2{ 1, 2, 3, 4 };
std::cout << "\nInvocation 2\n";
printArray(array2);
// Larger array size than in the function signature
auto array3 = make_array<int>(1, 2, 3, 4, 5, 6, 7, 8 );
std::cout << "\nInvocation 3\n";
printArray(array3);
return 0;
}
I need to print an array by implementing the use of a function before the main function. So I tried the following function:
int* printArr(int* arr)
{
for (int i = 0; i < 5; i++) {
cout << arr[i];
}
return arr;
}
I encountered two problems when implementing this into the whole code.
First, this is printing what I think is the address of the array and not the actual array. Pretty sure this is because of the return arr; in line 10. But if I do not write return then the code will produce an error. How can I fix this?
Second, I do not understand the second argument printArr has. In line 19, you can see cout << printArr(arr, 5) << endl;. How come there is a single numeric value, that one being 5 in this case, as an argument? How can I account for this in my function?
Please keep in mind that I am new to C++ and coding in general. Also, this code was given to me, hence why I do not understand certain aspects of it.
This is my code so you can see what I mean:
#include <iostream>
using namespace std;
// Declare function printArr here
int* printArr(int* arr)
{
for (int i = 0; i < 5; i++)
{cout << arr[i];}
return arr;
}
int main()
{
int arr[5] = {1, 3, 5, 7,9};
int last_num = arr[sizeof(arr)/sizeof(int)-1];
cout << "Before reversing" << endl;
cout << printArr(arr, 5) << endl;
// reverse "arr" using reference(&)
cout << "After reversing" << endl;
printArr(arr, 5);
return 0;
}
The declaration and implementation of printArr() is all wrong.
First, this is printing what I think is the address of the array and not the actual array.
The printArr() function itself is printing the contents of the array (well, the first 5 elements anyway), and then returning the address of the array. It is main() that is printing that address afterwards, when it passes the return value of printArr() to std::cout <<.
Pretty sure this is because of the return arr; in line 10. But if I do not write return then the code will produce an error. How can I fix this?
By getting rid of the return type altogether. There is no good reason to return the array pointer at all in this example, let alone to pass that pointer to std::cout. So printArr() should be returning void, ie nothing.
Second, I do not understand the second argument printArr has. In line 19, you can see cout << printArr(arr, 5) << endl;. How come there is a single numeric value, that one being 5 in this case, as an argument?
Because main() is passing in the element count of the array (5) so that printArr() can know how many elements to actually print, instead of hard-coding that value in the loop. However, your declaration of printArr() does not have a 2nd parameter with which to accept that value, that is why you are getting errors.
How can I account for this in my function?
By adding a 2nd parameter in the function declaration, eg:
#include <iostream>
using namespace std;
// Declare function printArr here
void printArr(int* arr, int size)
{
for (int i = 0; i < size; i++)
{
cout << arr[i] << ' ';
}
cout << endl;
}
int main()
{
int arr[5] = {1, 3, 5, 7, 9};
const int count = sizeof(arr)/sizeof(arr[0]);
int last_num = arr[count-1];
cout << "Before reversing" << endl;
printArr(arr, count);
// reverse "arr" using reference(&)
cout << "After reversing" << endl;
printArr(arr, count);
return 0;
}
Live Demo
In Visual Studio 2019, I have written the following test codes, but the results confused me.
#include <iostream>
using namespace std;
template<class T, class Func>
int call(T x, Func f) { return f(x); }
int square(int x) { return x * x; }
int main() {
int (*func0) (int) = square; // line 0, OK
//int (func1)(int) = square; // line 1, wrong
int (__cdecl *func1) (int) = square; // line 2, OK
//int (__cdecl func2)(int) = square; // line 3, wrong
cout << ((int(__cdecl*)(int)) square)(5) << endl; // line 4, OK
//cout << ((int(__cdecl)(int)) square)(5) << endl; // line 5, wrong
cout << call<int, int (*)(int)>(5, square) << endl; // line 6, OK
//cout << call<int, int ()(int)>(5, square) << endl; // line 7, wrong
cout << call<int, int(__cdecl*)(int)>(5, square) << endl; // line 8, OK
cout << call<int, int(__cdecl)(int)>(5, square) << endl; // line 9, OK
return 0;
}
(I am aware that I can omit the types when using call, but this is an experiment.)
I thought I was able to understand everything from line 0 to line 7. What I had in mind is that square is a funtion pointer, so it should have type int (*) (int) or perhaps int(__cdecl*) (int), and these two are either identical or can be casted to each other (I didn't change the calling convention of the project, so the default is __cdecl).
However, I was surprised that both line 8 and line 9 compile and run correctly. Why does this happen?
By comparing lines 6, 7 with lines 8, 9, I think the problem comes from adding __cdecl, but in Microsoft Docs nothing like this is mentioned.
I then printed out the types:
// ...
cout << typeid(square).name() << endl; // output: int __cdecl(int)
cout << typeid(*square).name() << endl; // output: int __cdecl(int)
cout << typeid(&square).name() << endl; // output: int(__cdecl*)(int)
cout << (typeid(square) == typeid(int(*) (int))) << endl; // output: false
cout << (typeid(square) == typeid(int(__cdecl) (int))) << endl; // output: true
cout << (typeid(square) == typeid(int(__cdecl*) (int))) << endl; // output: false
cout << (typeid(square) == typeid(*square)) << endl; // output: true
// ...
It seems that square indeed has type int (__cdecl) (int). Also, I don't understand why square and *square are of the same type...
Could someone explain these phenomena to me?
square and *square are the same type because functions decay, just like arrays do, to pointers, except (just like arrays) under certain contexts. In particular, decay is suppressed under typeid and &, but not under *, so typeid(square) gives you the type of square, int (__cdecl)(int), while typeid(*square) means typeid(*&square) means typeid(square) gives the same thing. This leads to the odd fact that you can write as many *s as you want and they will all do nothing: *************square is the same as square.
Now, to the rest of your question, you wrote the type "function taking int returning int" wrong. int ()(int) means "function taking no arguments returning function taking int returning int". You wanted int(int). Then this works:
cout << call<int, int(int)>(5, square) << "\n"; // line 7, fixed (FYI: endl is not normally necessary)
Because now call has arguments list (int x, int f(int)), and a parameter declaration of function type is automatically adjusted to have pointer to function type, making call<int, int(int)> functionally identical to call<int, int (*)(int)>. (This does not work for variable declarations or casts, so lines 1, 3, 5 remain incorrect.) The extra parentheses caused the type to be misinterpreted. Line 9 works because putting __cdecl inside the parentheses makes them not be misinterpreted (instead of being the function declarator, they become grouping symbols).
cout << call<int, int (__cdecl)(int)>(5, square) << "\n"; // line 9, OK
Again, the type of call's parameter is adjusted. int (__cdecl f)(int) becomes int (__cdecl *f)(int), which makes line 9 functionally identical to line 8.
The error with the line:
int (func1)(int) = square; // line 1, wrong
is that you are missing a '*', it needs to be:
int (*func1)(int) = square; // line 1, wrong
same with
//int (__cdecl func2)(int) = square; // line 3, wrong
cout << ((int(__cdecl)(int)) square)(5) << endl; // line 5, wrong
needs to be
cout << ((int(__cdecl*)(int)) square)(5) << endl; // line 5, wrong
When I'm trying to print the values of an array, its memory location is getting printed instead of values. What am I doing wrong?
int main()
{
int list[3];
for (int i=0; i<3; i++)
{
list[i] = i;
std::cout<<list<<std::endl;
}
}
OUTPUT: 0x7ffffef79550
C++ doesn't provide an overload for arrays when using the iostream library. If you want to print the values of an array, you'll need to write a function or find one somebody else has written.
What's happening under the hood is list is decaying to an int*, and that's what you're seeing printed.
This looks like a typographical error:
std::cout << list
You want to print a specific element of the array, right?
std::cout << list[i]
When printing "the whole array" without index, the pointer to first element is printed (see the other answer for reason).
std::cout << list << std::endl;
You're printing the array object itself. What do you expect to see? The name of the array identifier? The address of the first element in the array? (actually this is what happens in your case). Or do you expect the array to neatly iterate over it's elements and build a comma separated string of all the values and output it to the stream? If this is what you want, you have to implement it yourself.
template <std::size_t N>
std::ostream& operator<<(std::ostream& out, int (&arr)[N]) {
std::copy(std::begin(arr), std::end(arr), std::ostream_iterator<int>{out, ", "});
return out;
}
int main() {
int arr[] = {1, 2, 3, 4, 5};
std::cout << arr << std::endl; // Ok, prints "1, 2, 3, 4, 5, ".
}
You need to dereference the list. Instead of:
std::cout << list << std::endl;
do:
std::cout << *list << std::endl;
This question already has answers here:
error: no matching function for call to 'begin(int*&)' c++
(3 answers)
Closed 6 years ago.
I'd like to get length of an array. I have this code:
#include <iterator>
#include <iostream>
#include <string>
using namespace std;
void printArrLen(int arr[]);
int testArr [3] = {1, 4, 5};
int main() {
printArrLen(testArr);
cout << "main/testArr; Memory address: " << testArr << ", value: " << *testArr << endl;
cout << end(testArr) << endl;
}
void printArrLen(int arr[]) {
cout << "printArrLen/arr; Memory address: " << arr << ", value: " << *arr << endl;
cout << "printArrLen/testArr; Memory address: " << testArr << ", value: " << *testArr << endl;
// This works:
cout << end(testArr) << endl;
// This doesn't work - no matching function for call to 'end(int*&)':
// cout << end(arr) << endl;
// Doesn't work:
// cout << "arrLen: " << end(arr) - begin(arr) << endl;
}
Output:
printArrLen/arr; Memory address: 0x601318, value: 1
printArrLen/testArr; Memory address: 0x601318, value: 1
0x601324
main/testArr; Memory address: 0x601318, value: 1
0x601324
Uncommenting cout << end(arr) << endl; in printArrLen gives no matching function for call to 'end(int*&)'
I'm aware that begin/end(arr) wont work if arr is a pointer.
Why do they work on testArr in printArrLen and main, if the testArr seems to be a pointer too? How it can be proven in printArrLen that testArr is not a pointer and arr is while they both seem to contain a memory address?
I'm aware that begin/end(arr) wont work if arr is a pointer. Why do they work on testArr in printArrLen and main, if the testArr seems to be a pointer too?
Pointers are not arrays.
In your code,
testArr is array which has been initialised with 3 elements.
arr is array parameter. Array parameter is special in the sense that the array decays to pointer, so what is actually passed to the function printArrLen is a pointer (to arr first element).
Btw, you don't have to provide array size when you initialise it. This would do as well (and better):
int testArr[] = {1, 4, 5};
I'd like to get length of an array.
[...]
void printArrLen(int arr[]);
Not like this. arr in this function is actually a pointer to the first element of the array. Or more precisely, it may point to the first element of an array. It's just an int* and could point anywhere. In any case, there is no size information anymore inside of the function. You simply cannot get it.
The [] syntax is just there to confuse you. But don't take my word on it -- ask your compiler by trying this piece of code:
void printArrLen(int arr[]) {}
void printArrLen(int* arr) {}
You will see that it will complain about a redefinition.
int testArr [3] = {1, 4, 5};
testArr, in contrast to the arr parameter above, is an array, and carries the size information in its type.
int main() {
printArrLen(testArr);
Here you pass to the function a pointer to the first element of testArr, i.e. an int* pointing to the "1" element.
// This works:
cout << end(testArr) << endl;
Because testArr is an array.
// This doesn't work - no matching function for call to 'end(int*&)':
// cout << end(arr) << endl;
Because arr is a pointer.
Use std::vector if the array's size is only known at runtime, or std::array if it's already known at compile time. Both containers always know their own size.
How it can be proven in printArrLen that testArr is not a pointer
and arr is while they both seem to contain a memory address?
This question makes less sense than it seems.
Consider this:
int main()
{
int i = 0;
double d = 0.0;
}
Now, how can you "prove" that i is not a double but d is?
The answer is that you do not have to "prove" it, because, obviously, you already know.
Technically, there is another answer to your question, of course, and that is using typeid...
#include <typeinfo>
#include <typeindex>
#include <iostream>
void printArrLen(int arr[]);
int testArr [3] = {1, 4, 5};
int anotherTestArr [3] = {1, 4, 5};
int yetAnotherTestArr [4] = {1, 4, 5, 6};
int main() {
printArrLen(testArr);
}
void printArrLen(int arr[]) {
std::cout << (std::type_index(typeid(arr)) == std::type_index(typeid(testArr))) << "\n";
std::cout << (std::type_index(typeid(anotherTestArr)) == std::type_index(typeid(testArr))) << "\n";
std::cout << (std::type_index(typeid(yetAnotherTestArr)) == std::type_index(typeid(testArr))) << "\n";
}
This does not have any direct use for you, but it is of great educational value. It will print:
0
1
0
This example demonstrates that arrays of different sizes are different types, and pointers are different types from all array types.
testArr is not a pointer, it is an array with 3 elements.
arr is a pointer - there is not enough knowledge to make begin and end work, because the compiler does not know that it's pointing to an array (and what the size of the hypothetical array is).
My suggestion is: use either std::array or std::vector, depending on what you need to do. If you want to use old-school arrays, change printArrLen to take an array reference:
template <size_t N>
void printArrLen(int (&arr)[N]) {
/* ... */
}
wandbox example