0

I have to convert from std::array<std::array<int, 4>, 4> to int** because some legacy api expects the result in int**.

I tried to do it like this:

#include <array>
#include <iostream>

std::array<int *, 4> toIntStar(std::array<std::array<int, 4>, 4> &v) {
  int n = static_cast<int>(v.size());
  std::array<int *, 4> a;

  for (int i = 0; i < n; ++i) {
    a[i] = &v[i][0];
  }
  return a;
}

int **somefunction() {
  std::array<std::array<int, 4>, 4> cpparray{
      {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}, {13, 14, 15, 16}}};

  std::array<int *, 4> resultStar = toIntStar(cpparray);

  int **result = &resultStar[0];
  return result;
}

int main() {
  auto result = somefunction();
  std::cout << result[0][0] << '\n';
  std::cout << result[0][1] << '\n'; // crashes here
  //....
}

However it crashes in the line:

std::cout << result[0][1] << '\n'; // crashes here

Were is the mistake here?

Sandro4912
  • 313
  • 1
  • 9
  • 29
  • 4
    `resultStar` is a local variable in `somefunction` whose lifetime ends when `somefunction` returns – 463035818_is_not_an_ai Jan 21 '21 at 10:48
  • cant find the right duplicate, this is at least related: https://stackoverflow.com/questions/4643713/c-returning-reference-to-local-variable – 463035818_is_not_an_ai Jan 21 '21 at 10:51
  • 2
    Does the API take ownership of the passed `int **` (does it free that memory), or does it only read it? – t.niese Jan 21 '21 at 11:02
  • it takes ownership. So I have to allocate result on the heap and then return it. – Sandro4912 Jan 21 '21 at 11:06
  • 3
    If it really takes ownership (If all memory allocated for `int**` is freed by that legacy function), then both `&v[i][0]` and `&resultStar[0]` are not valid (regardless of the fact that `resultStar` is already a locale variable whose lifetime ends at the end of the function). In addition, it is also important to know how the memory for the `int **` must be allocated, because the way that functions frees that memory has to match how it is allocated, without that information it is impossible to give you a correct answer. – t.niese Jan 21 '21 at 11:12
  • If where you are passing it to takes ownership, it should have a function for allocating. If it doesn't, stop using it because it is faulty by design – Caleth Jan 21 '21 at 12:14
  • @Sandro4912 `because some legacy api expects the result in int**` -- An `int**` is merely a pointer to a pointer. There is no information beyond that. So how can such an API guarantee that the client allocated the memory in the fashion the API function expects? What if the allocation is done [this way](https://stackoverflow.com/questions/21943621/how-to-create-a-contiguous-2d-array-in-c/21944048#21944048), where the entire "data area" is done with a single allocation? – PaulMcKenzie Jan 21 '21 at 12:21
  • in this case it does not really matter how it is freed. The int** goes only into some unit tests. The API whit int** comes from here: https://www.codewars.com/kata/5671d975d81d6c1c87000022/train/cpp – Sandro4912 Jan 21 '21 at 12:38
  • @Sandro4912 the `equal` function that you show in your link does **not** take ownership of the memory that is passed to it using `int **puzzle`. If you are not sure what taking ownership means you need to read more about that. `in this case it does not really matter how it is freed` it is **always** important if a function to which you pass data, frees the passed memory or not, and if it does how. – t.niese Jan 21 '21 at 15:20
  • yes i think in case of the link nobody frees the memory right? So I would need to delete the memory manually after the `equal` function. I think in this case the whole interface should be done with a more safe method like `std::array`. – Sandro4912 Jan 21 '21 at 16:12

1 Answers1

3

Were is the mistake here?

The mistake is that you create an array in automatic storage and return a pointer to it. When the function returns, the automatic array is destroyed and the pointer is left dangling.

eerorika
  • 232,697
  • 12
  • 197
  • 326