1

I'm talking about this bit of code:

#include <iostream>

using namespace std;

void citire(int& n, int* a)
{
    cin >> n;
    a = new int[100];
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
    }
}

int main()
{
    int n, *a;
    citire(n, a);
    for (int i = 0; i < n; i++)
    {
        cout << *a << " ";
    }
    return 0;
}

I'm getting an error saying that a is not initialized and I can't seem to understand why. I'm using a = new int[100] inside that function, and a is a pointer, so it wouldn't matter where I initialize it (as long as I do before I use its value).

If I add that line before the function call citire(n, a) in int main(), the code will work.

The only reason I might think of that generates the error is the fact that initialization occurs in a function. So, if I wouldn't call citire(n, a), then a would be uninitialized. Is this the reason for the error?

Or why do I get it?

Edit:

The confusion appeared because I know that arrays are basically pointers, and when passing an array as argument, like this:

#include <iostream>

using namespace std;

void citire(int& n, int a[])
{
    cin >> n;
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
    }
}

int main()
{
    int n;
    int a[100];
    citire(n, a);
    for (int i = 0; i < n; i++)
    {
        cout << *a << " ";
    }
    return 0;
}

I don't need to pass it by reference - a shallow copy is created.

Why does that happen by default with arrays, but it doesn't with pointers? (Although now it is clear why my program was crashing.)

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
  • 4
    `citire::a` is a copy of `main::a`, since it is passed by value. You'd want to pass it by reference (like you did `n`) instead. Side note: you're leaking memory -- use `std::vector` instead of a naked `new`. – Quentin Nov 09 '20 at 10:18
  • 3
    You pass `a` *by value* to the function, so the assignment in the function will only assign to the local variable. The `a` variable in the `main` function won't be modified. – Some programmer dude Nov 09 '20 at 10:19
  • 4
    `void citire(int& n, int* a)` -> `void citire(int& n, int*& a)`. It's getting unreadable though isn't it? Use a `std::vector` instead! – Bathsheba Nov 09 '20 at 10:21
  • 2
    Close voter: the problem is not casued by a typo, but rather by a misunderstanding on how passing a pointer works. There's no reason to close this question. And I don't see why it should be downvoted either; there's a [mcve] and it's clear. – Fabio says Reinstate Monica Nov 09 '20 at 10:56
  • Can you check the edit, please? –  Nov 09 '20 at 12:17
  • Pointers are not values where pointers point to. In your edit you edit the elements the pointer points to, not pointer the itself. In your new code you do not do `a = something` but do `a[i] = something`. – KamilCuk Nov 09 '20 at 12:20
  • 1
    Please ask a new question instead of editing to ask a new question. It's unfair to the answerer. – Hatted Rooster Nov 09 '20 at 12:21
  • @HattedRooster I felt like it would be okay because it's the thing that made me ask the question in the first place. –  Nov 09 '20 at 12:31
  • Does this answer your question? [How to pass pointer to function and dynamically allocate memory within function C++](https://stackoverflow.com/questions/23156999/how-to-pass-pointer-to-function-and-dynamically-allocate-memory-within-function) – Hari Nov 09 '20 at 12:36

2 Answers2

1

I fixed your code and also printed some addresses for your understanding.

Old code:

#include <iostream>

using namespace std;

void citire(int& n, int* a)
{
    cin >> n;
    a = new int[100];
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
    }
    cout << "In citire Address of a = " << &a <<endl;
    cout << "In citire Address of n = " << &n <<endl;
}

int main()
{
    int n, *a;
    cout << "Address of a = " << &a <<endl;
    cout << "Address of n = " << &n <<endl;
    citire(n, a);
    for (int i = 0; i < n; i++)
    {
        cout << *a << " ";
    }
    return 0;
}

Output:

Address of a = 0x7ffee5ab6b90
Address of n = 0x7ffee5ab6b98
5
1 2 3 4 5
In citire Address of a = 0x7ffee5ab6b50
In citire Address of n = 0x7ffee5ab6b98
0 0 0 0 0

Note the addresses of variables a and n in main() and inside citire() function.

Modified code:

#include <iostream>

using namespace std;

void citire(int &n, int* &a)
{
    cin >> n;
    a = new int[n];
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
    }
    cout << "In citire Address of a = " << &a <<endl;
    cout << "In citire Address of n = " << &n <<endl;
}

int main()
{
    int n, *a;

    cout << "Address of a = " << &a <<endl;
    cout << "Address of n = " << &n <<endl;

    citire(n, a);

    for (int i = 0; i < n; i++)
    {
        cout << a[i] << " ";
    }

    delete [] a;
    return 0;
}

Output:

Address of a = 0x7ffee0eb1b90
Address of n = 0x7ffee0eb1b98
5
1 2 3 4 5
In citire Address of a = 0x7ffee0eb1b90
In citire Address of n = 0x7ffee0eb1b98
1 2 3 4 5

Note in this case, both n and a's addresses are same inside the function as well as in main. Since they were passed by reference, the actual variables (just aliased) were passed with their memory locations intact, any change done to them is also reflected in main as well.

Key takeaway: Even pointers are passed by value to functions unless you force it to pass by reference!

Edit (Array code):

#include <iostream>

using namespace std;

void citire(int& n, int a[])
{
    cin >> n;
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
    }
    cout << "In citire Address of a = " << &a <<endl;
    cout << "In citire Address of n = " << &n <<endl;
    cout << "In citire Address of first element of a = " << &a[0] <<endl;
}

int main()
{
    int n;
    int a[100];
    cout << "Address of a = " << &a <<endl;
    cout << "Address of n = " << &n <<endl;
    cout << "Address of first element of a = " << &a[0] <<endl;
    citire(n, a);
    for (int i = 0; i < n; i++)
    {
        cout << a[i] << " ";
    }
    return 0;
}

Output:

Address of a = 0x7ffeef1cda00
Address of n = 0x7ffeef1cd9f8
Address of first element of a = 0x7ffeef1cda00
5
1 2 3 4 5
In citire Address of a = 0x7ffeef1cd9b0
In citire Address of n = 0x7ffeef1cd9f8
In citire Address of first element of a = 0x7ffeef1cda00
1 2 3 4 5

Note that in case of arrays, even though they are passed by value, in a sense that the address of a changes in function calls, the address of the region (i.e., of 100 integers as you have statically declared), basically the address of the first element of the array (&a[0]) do not change. Think of it like this:

  • You have a black box, inside which you store a number which is the address of a[0] which is the actual region a points at.
  • Now say the black box itself has an identification number XXX.
  • During function call, you put the contents of the black box XXX, into another black box, say with an identification number YYY.
  • Undestand that YYY has the same pointed region i.e, &a[0].
  • You ship the new YYY black box to function which uses and manipulates the data in the region which starts at &a[0].

So you get the result reflected in main(). Also note that array and pointer types are not same.

swag2198
  • 2,546
  • 1
  • 7
  • 18
  • Got it. I expected it to work anyway because if instead of using pointers I would've used simple arrays instead of pointers I wouldn't need to pass it by reference. –  Nov 09 '20 at 12:14
  • First of all understand that arrays are not pointers and pointers are not arrays. Check this answer: https://stackoverflow.com/questions/1461432/what-is-array-to-pointer-decay. – swag2198 Nov 09 '20 at 12:38
0

I think you should read further about how parameters are passed in C functions.

Firstly, although a is a pointer, its memory allocation occcurs in citire(), in which a is assigned with its new memory address. But a is passed as value in citire(). As the program gets back in the main(), you still have the previous value of a.

Secondly, if you pass a pointer uninitialized to a function, the compiler will warn you because it supposes you will use the pointer (e.g. *a = 8) and as it is uninitialized, it could lead to a crash.

You'd better changer your function prototype:

int * cintire(int& n);
void cintire(int& n, int *& a);

Z.

Zyend
  • 572
  • 1
  • 4
  • 24