passing a struct array in a function as refence... ?

Started by
25 comments, last by Zahlman 16 years, 9 months ago
It looks as if several posters may have confused the terms 'array', 'pointer', and 'reference' in this context.
// 1) This function takes an array as an argumentvoid funcArray(char arg[5]);// 2) This one takes a pointervoid funcPointer(char *arg);// 3) And this on etakes a *reference* to an arrayvoid funcRefArray(char (&arg)[]);// 4) and finally... this one takes a reference to a pointervoid funcRefPointer(char *(&arg));

I never mentioned the pointer variants, I was talking about 1) and 3), and pointing out that in either the fnction can modify the array contents.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

Advertisement
Quote:Original post by swiftcoder
Quote:Original post by rip-off
Quote:Original post by swiftcoder
In this example, there is no need to pass the array by reference. Don't forget that arrays in C are really *just* pointers (extra syntax non-withstanding), so any function passed an array can modify the array's contents.

Arrays decay to pointers, arrays are not pointers.

nitpicker :)
If I declare 'char A[5]', A is a pointer. Albeit to a either the static data section or to a region on the stack, and immutable.


Nope. A is a C++ symbol. When the compiler translates the code to an exectable format "A" no longer exists. Its value is an array. &A == &A[0]. With a pointer &Pointer != &Pointer[0]. sizeof(A) == Num bytes in array. sizeof(Pointer) == the size of an address on the targer platform. A cannot be reseated, Pointer could be made point to some other variable.

The fact that arrays decay to pointers means that many properties of pointers are conceptually shared by arrays but they are not the same.

Quote:
Quote:
Quote:You only need to pass a reference to an array if you need the function to change the array pointer itself (i.e. pointing it at another buffer), and that doesn't work for static arrays.

If you pass a reference to an array, you can use sizeof on the array and not get sizeof(pointer).

But in fact that is just a syntactical issue, and you *have* created an unnecessary temporary pointer. And are you quite sure about that? I am not near a compiler to test that, but it seems to me you should get the same result whether you pass an array, or a reference to an array (note that I never mentioned using a pointer directly).

I see no temporary pointer. Maybe at underlying levels the compiler will choose to use this to implement the code, but we are not writing code at that level.
I believe you are incorrect, unless I'm misinterpreting you. You will get different results.
Quote:Original post by swiftcoder
If I declare 'char A[5]', A is a pointer. Albeit to a either the static data section or to a region on the stack, and immutable.


No.

The address of an array variable is the address of its contents. This is unlike pointers, the address of which is irrelevant, but the value of which contains the address of something else.

The sequence of operations performed for accessing A[3] is:
  • Get the address of A, add 3, dereference (if A is an array).
  • Get the address of A, dereference, add 3, dereference (if A is a pointer).


That is, accessing a memory buffer through a pointer requires an additional dereference in order to access the value of the pointer, which is the address of the buffer.

Quote:But in fact that is just a syntactical issue, and you *have* created an unnecessary temporary pointer. And are you quite sure about that? I am not near a compiler to test that, but it seems to me you should get the same result whether you pass an array, or a reference to an array (note that I never mentioned using a pointer directly).


When you pass a reference to an array, the type is conserved. Since the array size is encoded in the type, it is accessible to the compiler. On the other hand, you cannot pass an array by value in C and C++. The array automatically decays to a pointer if you do, and the size information is lost. The only way to conserve type information is using a reference:

#include <iostream>int byref(int (&a)[5]){  return sizeof(a);}int byval(int a[5]){  return sizeof(a);}int main(){  int a[5];  std::cout << byref(a) << std::endl << byval(a) << std::endl;}


Outputs:
204


Quote:Original post by swiftcoder
It looks as if several posters may have confused the terms 'array', 'pointer', and 'reference' in this context.
*** Source Snippet Removed ***
I never mentioned the pointer variants, I was talking about 1) and 3), and pointing out that in either the fnction can modify the array contents.


This may be true, but when passing an array to a function declared using (1) arg *is* a pointer, this is due to C++ specifying that an array passed as an argument to a function will decay to a pointer. This is a singular point of confusion.

void example( char arg[] );void foo() {   char array[4] = {};   example(array); // array decays to a pointer   char *pointer = array;   example(pointer); // look we can pass a pointer directly   // this wont   // array++;   }void example( char arg[] ) {    // look what we can do now!    arg++;}


However, 99% of the time passing an array by reference will be the same as passing it by pointer decay, as it is rare for someone to use "array specific" things like the sizeof trick.

An useful example that can be achieved via reference but not via pointer decay is an array size template:
template< class T, int N >int array_size( T (&arg)[N] ) {   return N;}void bar( int arg[] );void foo() {    int array[5];    int x = array_size(array); // x == 5    bar(array); // wont work because...}void bar( int arg[] ) {   int x = array_size(arg); // ...no function to match array_size( int *& )}
Quote:Original post by ToohrVyk
The sequence of operations performed for accessing A[3] is:
  • Get the address of A, add 3, dereference (if A is an array).
  • Get the address of A, dereference, add 3, dereference (if A is a pointer).


Huh? Consider the functions:
int foo(int A[], int n) {  return A[n];}int bar(int * A, int n) {  return A[n];}

Here's the assembly MSVC 2003 generates for foo:
	mov	eax, DWORD PTR _n$[esp-4]	mov	ecx, DWORD PTR _A$[esp-4]	mov	eax, DWORD PTR [ecx+eax*4]	ret	0

Here's bar:
	mov	eax, DWORD PTR _n$[esp-4]	mov	ecx, DWORD PTR _A$[esp-4]	mov	eax, DWORD PTR [ecx+eax*4]	ret	0
this thread have moved beyond the scope of my knowledge hehe
ok another question that may sound stupid to you;

#include <iostream>#include <string>using namespace std;void alter(string names[]){	names[0] = "zombie";	names[1] = "vampire";	names[2] = "mummy";	names[3] = "werewolf";	names[4] = "grim reaper";}void main(void){	string names[] = {"imp", "critter", "slime", "goblin", "troll"};	int i=0;	for(i=0;i<5;i++)	{		cout << names << endl;	}		cout << endl;	alter(names);	for(i=0;i<5;i++)	{		cout << names << endl;	}}


Now what do I do if I don't want the argument to be affected by the values inside the function? Since arrays seems to act like pointer, it's a tricky question for a beginner...
First, main returns an int, not void. The C++ Standard even specifies that you don't even need to write return in main, it will return 0 unless you explicitly return a different value.

Use std::vector. Its better than an array as it acts how you expect when you pass it to a function or return it from one:

#include <iostream>#include <vector>#include <string>using namespace std;// turns out I find a use for this example below =)template< class T, int N >int array_size( T (&arg)[N] ) { return N; }// because we didnt pass the vector by reference, the// vector in main will not be affectedvoid alter(std::vector<std::string> names){	names[0] = "zombie";	names[1] = "vampire";	names[2] = "mummy";	names[3] = "werewolf";	names[4] = "grim reaper";}int main(){	const char *names_data[] = {"imp", "critter", "slime", "goblin", "troll"};        // there is no easy way to initialise a std::vector directly        // currently this is about as easy as it gets        // in practise though such data will be loaded from        // an external source anyway        std::vector<std::string> names(data, data + array_size(data);	        // declare loop variables inside the for loop        // its much clearer        //int i=0;	for( int i = 0 ; i < names.size() ; i++ )	{		cout << names << endl;	}	cout << endl;	alter(names);	for( int i = 0 ; i < names.size() ; i++ )	{		cout << names << endl;	}}
but without the vector, it isn't possible? (just want to understand the basic way first)

Quote:Original post by Alpha Brain
but without the vector, it isn't possible? (just want to understand the basic way first)

You would have to allocate a new array, and copy the contents. C/C++ arrays can not be passed by value, so no matter how much you pass the 'handle' (basically a pointer) to the array around, each will refer to the same array.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

I think that this thread is a very strong argument for the use of std::vector instead of arrays. Arrays are far too complicated to be considered a basic language feature. I avoid their use as much as possible. When I do use an array it is either a local variable or I new[] some memory for use with a pointer. I would never write a function that takes an array as a parameter.

This topic is closed to new replies.

Advertisement