0

I am not a beginner in C/C++ but I can't seem to find what is wrong with this piece of c++ code. I also tried it with the c equivalent(malloc) and I get the same result.

#include <iostream>

void foo(int *n) {
  n = new int;
  *n = 11;
}

int main() {
  int *num = NULL;
  foo(num);
  std::cout << num << '\n';
  if (num) {
    delete num;
  }
  return 0;
}
Quentin
  • 58,778
  • 7
  • 120
  • 175
  • 2
    `num` is passed by value. Why would you expect it to change in main? – tkausl Jan 29 '20 at 18:14
  • If you do not know what is wrong how would we know? I do not see anything wrong., except memory leak you have in `foo()` – Slava Jan 29 '20 at 18:16
  • I don't pass the value, I pass the reference. If i passe the value it would be foo(*num), right? – DImiTrisXam Jan 29 '20 at 18:16
  • @DImiTrisXam, you pass the pointer by value. There is no reference in your code. – ChrisMM Jan 29 '20 at 18:17
  • 1
    Make an alias for `int *` lets say `intptr` and rewrite your code using it. Do you see the problem now? – Slava Jan 29 '20 at 18:18
  • You are passing the pointer in as "n", then reassigning only that pointer parameter, it does not change "num" in main(). – jamieguinan Jan 29 '20 at 18:20
  • @DImiTrisXam: The thing is, your function's definition requires that a pointer be passed as argument to it, not a reference to pointer. You need to change its signature to: `void foo(int* &n) { ... }` – machine_1 Jan 29 '20 at 18:21
  • @machine_1 or for C that would be pointer to pointer – Slava Jan 29 '20 at 18:21

1 Answers1

3

n is a pointer that is being passed by value, so any modifications made by the function to the pointer itself are not applied to the caller's variable. And as such, you are leaking memory since you are new'ing memory that you are not able to delete afterwards.

To do what you are attempting, you need to pass n by reference instead:

void foo(int* &n) {
  n = new int;
  *n = 11;

  // or simply:
  // n = new int(11);
}

Otherwise, you should change your function to return the new pointer instead of outputting it via a reference parameter:

#include <iostream>

int* foo() {
  int *n = new int;
  *n = 11;
  return n;

  // or simply:
  // return new int(11);
}

int main() {
  int *num = foo();
  std::cout << num << '\n';
  delete num;
  return 0;
}

That being said, in C++11 and later, you should be using std::unique_ptr instead of a raw pointer:

#include <iostream>
#include <memory>

void foo(std::unique_ptr<int> &n) {
  n.reset(new int(11));

  // or:
  // std::unique_ptr<int>(new int(11)).swap(n);

  // or, in C++14 and later:
  // n = std::make_unique<int>(11);
}

int main() {
  std::unique_ptr<int> num;
  foo(num);
  std::cout << num.get() << '\n';
  return 0;
}
#include <iostream>
#include <memory>

std::unique_ptr<int> foo() {
  return std::unique_ptr<int>(new int(11));

  // or, in C++14 and later...
  // return std::make_unique<int>(11);
}

int main() {
  std::unique_ptr<int> num = foo();
  std::cout << num.get() << '\n';
  return 0;
}
Remy Lebeau
  • 454,445
  • 28
  • 366
  • 620