1

To fully understand how pointers, values, and references work, I am making a basic C++ program that attempts to tamper with some static and dynamic arrays and understand exactly how they should be passed in.

First I generate a static array of 3 elements. I then pass it into a function that modifies all elements. I then pass it into another function with a slightly different signature, but can also alter the array's values.

Next I generate a dynamically sized array, pass it into a function by reference so that all of the values in this dynamically sized array can be altered.

The code is as follows:

#include "stdafx.h"
#include <iostream>
#include <string>

using namespace std;

void changeIndexStaticArrayMethod1(int* stat);
void changeIndexStaticArrayMethod2(int (&stat)[3]);
void changeIndexDynamicArrayMethod1(int* dyn, int size);

int main() {
    const int MAX = 3;
    int arr[MAX] = { 1,2,3 };

    changeIndexStaticArrayMethod1(arr);
    cout << arr[0] << endl;
    cout << arr[1] << endl;
    cout << arr[2] << endl;
    cout << endl;
    changeIndexStaticArrayMethod2(arr);
    cout << arr[0] << endl;
    cout << arr[1] << endl;
    cout << arr[2] << endl;

    int SIZE;
    cout << "Please choose a size for the array" << endl;
    cin >> SIZE;

    int *ne = new int[SIZE];
    //Build array
    for (int i = 0; i < SIZE; i++) {
        ne[i] = i;
    }

    changeIndexDynamicArrayMethod1(ne, SIZE);
    for (int i = 0; i < SIZE; i++) {
        cout << "ne[" << i << "] = " << ne[i] << endl;
    }


    //To hang program
    cin >> SIZE;

    delete[] arr;
    delete[] ne;
    return 0;
}

void changeIndexStaticArrayMethod1(int* stat) {
    stat[0] = 10;
    stat[1] = 20;
    stat[2] = 30;
}

void changeIndexStaticArrayMethod2(int (&stat)[3]) {
    stat[0] = 40;
    stat[1] = 50;
    stat[2] = 60;
}

void changeIndexDynamicArrayMethod1(int* dyn, int size) {
    for (int i = 0; i < size; i++) {
        dyn[i] = i * 10;
    }
}

All of the above code works how I want it to, I just have a few questions as to why (some of the methods of passing arrays by reference I have found on other SO questions).

  • In the changeIndexStaticArrayMethod1() and changeIndexDynamicArrayMethod1() functions, why are we able to use the dereference * operator for our array as reference? My knee jerk reaction is seeing that as practically passing the array in by values since it is the dereference operator. I know that with arrays, it is much different than using variables, but also, why will the following not work for single int variables:

    void changeStaticNumber(int* num){ num = 100; }

Obviously the above will work if we use &num and not int* num, and obviously I don't fully understand the relationship between pointers and arrays, but I cannot figure out why when we pass an array by reference, int* staticArray is ok.

Any explanation for these problems I am having would be much appreciated. Thanks.

Dominic Farolino
  • 1,362
  • 1
  • 20
  • 40
  • An array decays to a pointer when it is passed as an argument to a function. See e.g. http://stackoverflow.com/questions/1461432/what-is-array-decaying. – Jonathan Potter Feb 26 '15 at 04:55
  • So I would interact with it as I am passing it to a function the same way I interact with a regular old pointer variable pointing to an address of some sort? – Dominic Farolino Feb 26 '15 at 05:08
  • The pointer points to the first element in the array. You can use it just like the original array identifier, except you lose information about the number of elements in the array (and sizeof no longer works). – Jonathan Potter Feb 26 '15 at 05:13
  • You forgot to experiment with `std::vector` as well! – Neil Kirk Feb 26 '15 at 11:11

3 Answers3

1

why are we able to use the dereference * operator for our array as reference?

The * in C means many things. It can mean the unary indirection ("contents of") operator, it can mean the binary multiplication operator and it can mean a pointer declaration. The int* stat is a pointer declaration.

Since you aren't using the * to dereference the contents of the pointer inside that function, I'm not quite sure what you are asking.

When you take the array name of your array in main(), it "decays" into a pointer to the first element. So what those function do, is to take a pointer by value. If you dereference the pointer by typing *stat = something; you access the actual array in main.

Should you do something weird like changing the pointer itself, for example stat++;, then it will not affect the address used in main. You passed the pointer itself by value, so the pointer is a local copy.

My knee jerk reaction is seeing that as practically passing the array in by values since it is the dereference operator.

You can't really pass arrays by value in C or C++, without resorting to dirty tricks (storing them inside structs or classes). For example, had your function been written as void changeIndexStaticArrayMethod1(int stat[3]) it would still give you a pointer to the first element. It will not pass an array by value, as the syntax might trick you into believing.

why will the following not work for single int variables:

void changeStaticNumber(int* num){ num = 100; }

Because num is the pointer itself, not its contents. In order to write code like that, you could pass the variable by reference int& num. Behind the lines this is really the same thing as passing a pointer, just with simplified syntax.

To understand the relation between pointers and arrays better, start by reading this whole chapter: http://c-faq.com/aryptr/index.html (C and C++ are identical when it comes to pointers).

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • Ok so `int* num` does not work with regular variables simply because if you wish to edit the original values, you need to pass them in so you have access to their address, which passing by reference (`&`) does. If the name of the array in main() decays to pointer to the first element address, accepting an address can be done by doing : void f(int n*), which makes sense because you are making a pointer to the address you are passed in. However, why does (&arr)[N] work? Wouldn't the `&` be redundant? And why does this preserve your ability to work with `sizeof()` where as using a ptr does not. – Dominic Farolino Feb 27 '15 at 01:47
  • @DomFarolino Not sure what you mean with "int* num does not work with regular variables". You can of course still access the variable pointed-at, there's just different syntax compared to references. `(&arr)[N]` is a reference to an array of N elements. It works because C++ says so, you can only pass an array of that given size, and therefore sizeof can be used. Pointers have no such type safety, you can pass an array of any size and it will decay into a pointer to the first element, with all information about how large the data pointed at is. – Lundin Feb 27 '15 at 07:12
0

Let me see if I can take a stab at this.

Pointers are simply address holders. Once you do int * ptr = myarray; --- what you are in tern doing is storing the address of the pointer my array into ptr --- array names are actually pointers to the first memory location in the array. You can use pointer arithmetic to get at everything else for example myarray +1 will point you to the next location or myarray[1].

Passing by value is not very useful when you need to modify your array. Passing in by reference is essentially making a pointer to the array and passing that. Since arrays like vectors are contiguous blocks of memory you can index through them rather easily.

As far as your example goes void changeStaticNumber(int* num){ num = 100; } will not work because what you are attempting to do is store 100 into the pointer's address. If you deference num and make it void changeStaticNumber(int* num){ *num = 100; } it will work because you are actually going one step further and accessing the data that num is pointing to. When you use &num it is essentially the same thing - & just gives you the address of something.

For example if you want to point a pointer to an int what you would do is

int num = 5; int *ptr = &num;

at this point in time ptr has the same address in num. To print out the data in num or that ptr is pointing to you need to dereference or go one step further as I like to tell myself and dereference to so cout << *ptr;

Alex Top
  • 33
  • 6
  • I know all the stuff you said it's just difficult since the array is a pointer. I think the way you worded it helped a lot. Does it make sense to say, since the array is a pointer, we have to set our function parameter (a pointer) equal to our array's address (first element + pointer arithmetic) so that we can actually change the values at the original address when referring to our function's pointervariable in the function? To me this makes sense because if we wanted to set a pointer equal our array we'd have to say int*parray = &array. And in the case of passing the array into the function.. – Dominic Farolino Feb 26 '15 at 05:33
  • The function parameter acts as the pointer. And the array passed in acts as the address...it seems to make sense now – Dominic Farolino Feb 26 '15 at 05:33
  • The up above int *ptr = array is the way to set it in the function. With array and vector there is no & required -- the name is a pointer. In a function this comes useful with dynamic stuff. When passing - & is the way you give the address so you are passing just the address correct! That is passed by reference - all data is accessible. If you change any data point in the function that you passed the array in it will change it in the original array where it was declared and initialized. If you want to limit accessibility use const - you can use it on both the array and the pointer. – Alex Top Feb 26 '15 at 06:05
0

In both changeIndexStaticArrayMethod1 and changeIndexDynamicArrayMethod1 you are not passing an array there is no pass by reference (which only happens if the parameter type is a reference type -- i.e. with &). The parameter has type int * (pointer to int). You are passing a pointer to int by value. There is no "dereference operator" in either function.

ne is already an int *, so passing it is nothing special. arr is an int [3], an array, not a pointer. In C, when an array-of-T is used in a context that expects a pointer-to-T, it is implicitly converted (without you needing to do anything) to a pointer to its first element. So when you do, changeIndexStaticArrayMethod1(arr), the compiler gets a pointer to the first element of arr, and passes that to the function.

The [] operator works on pointers. a[i] is always guaranteed to be the same as *(a + i). Inside both the changeIndexStaticArrayMethod1 and changeIndexDynamicArrayMethod1 functions, [] is used to access subsequent elements using a pointer to the first element.

newacct
  • 119,665
  • 29
  • 163
  • 224