0

simple call by reference

void foo(int* A)
{
    // ...
}

void main()
{
    int A[] = {1,1,1,1,1,1,1,1,1};
    foo(A);
}

not sure why but it is lessening the size of the array and losing/leaking information on the array....

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
rtbaldwin
  • 88
  • 1
  • 10
  • 4
    Use [`std::array`](http://en.cppreference.com/w/cpp/container/array) or [`std::vector`](http://en.cppreference.com/w/cpp/container/vector) and save your self the pain. P.S: sizeof inside foo will give you the size of the pointer, because it's evaluated at compile time (it couldn't know what the pointer is pointing to). – Borgleader Feb 01 '14 at 01:00
  • 1
    re "simple call by reference", **no** it's not. it's call by value, passing a pointer. re `void main`, **no** that's not valid c++ (or c, for that matter). re "lessening the size", no, only apparently, but this so called **decay** is a heritage from C that's quite problematic. – Cheers and hth. - Alf Feb 01 '14 at 01:09
  • Note for [tag:c++] _'call by reference '_ would literally mean `void foo(int &A[])` – πάντα ῥεῖ Feb 01 '14 at 01:11
  • `void main()` is incorrect; the correct declaration is `int main(void)`. Please discard whatever textbook told you to use `void main()`; its author doesn't know the language very well. – Keith Thompson Feb 01 '14 at 01:25
  • 1
    @πάνταῥεῖ `void foo(int &A[])` is illegal C++, you probably meant `void foo(int (&A)[9])`. – fredoverflow Feb 01 '14 at 15:26

4 Answers4

2

You're passing a pointer to the first element of an array. Create your function with the prototype

void foo(int* A, int size);

You will still be able to access A[0...size-1] like normal.

jProg2015
  • 1,098
  • 10
  • 40
1

not sure why but it is lessening the size of the array and losing/leaking information on the array....

In foo(), sizeof(A) == 8 not because it is "leaking" information, but because 8 is the size of the pointer of type int*. This is true regardless of how many integers A was initialized with in main().

This may shine some light on what is happening:

#include<iostream>
using namespace std;

void foo(int* A)
{
  cout << "foo: " << sizeof(A) << endl; // 8
}

void bar(int A[])
{
  cout << "bar: " << sizeof(A) << endl; // still 8
}

int main()
{
  int A[] = {1,1,1,1,1,1,1,1,1};
  cout << "main: " << sizeof(A) << endl; // 36 (=4*9)
  foo(A);
  bar(A);
  return 0;
}

Output:

main: 36
foo: 8
bar: 8

In main, sizeof "knows" the size of A[] - it is sizeof(int) * length = 4 * 9 = 36. This information is lost when A[] is cast to a pointer A* in foo.

What if we pass in A as bar(int A[]) instead. Will that retain the array length? No! In that case, sizeof(A) is still 8, the size of the pointer. Only in main does the compiler retain the information of array size of A.

If you want your functions to know the size of the array, use the std::vector<int> template, or pass in the size separately.

Here's another discussion on this: When a function has a specific-size array parameter, why is it replaced with a pointer?

Community
  • 1
  • 1
Matt
  • 20,108
  • 1
  • 57
  • 70
1

You should totally drop C-style arrays and use std::array instead. Just compare this (which is the solution to your problem):

void foo(int* A, std::size_t size) {
    // ...
}

int main() {
    int A[] = {1,1,1,1,1,1,1,1,1};
    foo(A, (sizeof(A) / sizeof(int)));
}

to:

template<std::size_t Size>
void foo(const std::array<int, Size>& array) {
    // ...
}

int main() {
    std::array<int, 9> A {{ 1, 1, 1, 1, 1, 1, 1, 1, 1 }};
    foo(A);
}

Ain't it beautiful? Or just take a look at how gorgeous it is with std::vector:

void foo(const std::vector<int>& vector) {
    // vector.size() is the size
}

int main() {
    std::vector<int> A = { 1, 1, 1, 1, 1, 1, 1, 1, 1 };
    foo(A);
}

And if you really want foo to be a generic algorithm, I'll just blow your mind with iterators:

template<class Iterator>
void foo(Iterator begin, Iterator end) {
    // ...
}

int main() {
    std::array<int, 9> A {{ 1, 1, 1, 1, 1, 1, 1, 1, 1 }};
    std::vector<int> B = { 1, 1, 1, 1, 1, 1, 1, 1, 1 };
    foo(A.begin(), A.end());    // not a single problem
    foo(B.begin(), B.end());    // was given that day
}

C++ has an amazing (arguably) standard library and an amazing type system (if you don't overlook C legacy "features", like void*): use them.

Shoe
  • 74,840
  • 36
  • 166
  • 272
0

The correct way to pass array by reference is

void foo(int (&A) [9])
{
    // sizeof(A) == sizeof(int) * 9
}

the generic way is so:

template <std::size_t N>
void foo(int (&A) [N])
{
    // sizeof(A) == sizeof(int) * N
}

You may use std::array (C++11 required) which has a syntax more intuitive

template <std::size_t N>
void foo(std::array<int, N> &A)
{
    // A.size() == N
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302