1

I am trying to access the values pointed by pointers in a 2D array of double pointers, passed as a function arguments

float cfun (float **indatav, int rows, int cols)
{
    float* *outdatav = new float*[rows];
    for (int i=0; i < rows; i++){
        outdatav[i] = new float[cols];
    }

    for (int i=0; i < rows; i++){
        for (int j=0; j < cols; j++){
            outdatav[i][j] = *(*(indatav[i])[j]);
            }
    }

    return outdatav;
}

I have tried several variants but none of them works. This variant seems to me the most correct but doesn't work and I don't understand why. Any hint or explanation would be highly appreciated.

I know that having outdatav[i][j] = indatav[i][j]; with a return type of float** could work but this is not what I am looking for, because in this case the function would return the memory adress of the double pointers, while I am looking for the values of the variables pointed by those pointers.

A reproducible example would be:

#include <iostream> 
#include <vector>
using namespace std;

//float cfun (float **indatav, int rows, int cols)
float** cfun (float **indatav, int rows, int cols)
{
    float** outdatav = new float*[rows];
    for (int i=0; i < rows; i++){
        outdatav[i] = new float[cols];
    }

    for (int i=0; i < rows; i++){
        for (int j=0; j < cols; j++){
            outdatav[i][j] = *(*(indatav[i])[j]);
        }
    }
    return outdatav;
}

int main(){

//  float indatav[2][2] = {{1.,2.};{3;4}} // WRONG!
    float indatav[2][2] = {{1.,2.},{3,4}};// RIGHT!
    int rows = 2, cols = 2;

//  float y[2][2] = cfun(**indatav, rows, cols); // Try compiling this!
    float **y = cfun(indatav, rows, cols); // THIS DOES WHAT YOU ARE AKSING!
    return 0;
}

Where ywould be have the values {{1.,2.},{3,4}}. // Note changes

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
Joachim
  • 490
  • 5
  • 24
  • Please try to create a [mcve] to show us, especially how you call the function `cfun`. And what do you mean by "none of them works"? Do you get build errors? Wrong results when running? Crashes? Something else? Please take some time to refresh [how to ask good questions](http://stackoverflow.com/help/how-to-ask), as well as [this question checklist](https://codeblog.jonskeet.uk/2012/11/24/stack-overflow-question-checklist/). – Some programmer dude Sep 29 '19 at 12:39
  • The second code block you gave won't even compile! Try. Then try with the changes I've made - at least then it will compile. – Adrian Mole Sep 29 '19 at 16:54

2 Answers2

1

After a long discussion I understood I was not passing correctly the arguments in the functions and was messing up with the pointers and data-types. Here is the final answer:

#include <iostream>
#include <vector>
using namespace std;

float** cfun (float **indatav, int rows, int cols) 
{
    float* *outdatav = new float*[rows];
    for (int i=0; i < rows; i++){
        outdatav[i] = new float[cols];
    }

    for (int i=0; i < rows; i++){
        for (int j=0; j < cols; j++){
            outdatav[i][j] = indatav[i][j]; 
            }
    }
    return outdatav; 
}

int main(){

    int rows = 2, cols = 2;
    float list[rows][cols]= {{1.,2.},{3.,4.}};

    float* *indatav = new float*[rows];
    for (int i=0; i < rows; i++){
        indatav[i] = new float[cols];
    }

    for (int i=0; i < rows; i++){
        for (int j=0; j < cols; j++){
          indatav[i][j]=list[i][j];
        }
    }

    float **y = cfun(indatav, rows, cols);

    for(int i=0; i<rows; i++){
      for(int j=0; j<rows; j++){
        cout << y[i][j] <<endl;
      }
    }

    return 0;
}

Obviously I am open to any more elegant solution for the main function.

Joachim
  • 490
  • 5
  • 24
0

You seem very comfortable when you correctly dereference your outdatav 2D array, so what makes you think the indatav 2D array should be treated any differently? Try the following two-line correction:

float** cfun (float **indatav, int rows, int cols) // Now return 2D pointer!
{
    float* *outdatav = new float*[rows];
    for (int i=0; i < rows; i++){
        outdatav[i] = new float[cols];
    }

    for (int i=0; i < rows; i++){
        for (int j=0; j < cols; j++){
        //  outdatav[i][j] = *(*(indatav[i])[j]);
            outdatav[i][j] = indatav[i][j]; // Why don't you think this will work?
            }
    }

    return outdatav; // Note change in function declaration!
}

After all, both outdatav and indatav have exactly the same declarations - both are float**.

In your edited question, you now have a call: y = cfun(**indatav, rows, cols); and you add

Where y would be have the values {{1.,2.},{3;4}}

This is exactly how I have interpreted what you want. You would need to declare your variable, "y," as: float** y and the actual value for the data at row 0 and column 1 would be given by the expression y[0][1]. However, your call to cfun wrong and should be: y = cfun(indatav, rows, cols); for the example you have given.

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
  • 1
    There is one additional problem: `return outdatav;` won't compile, because `outdatav` is declared as `float** outdatav`, but function is declared as returning `float`: `float cfun`. – Algirdas Preidžius Sep 29 '19 at 12:45
  • 1
    in my opinion, taking into account, the functionality of the function, asker probably wanted to just return `float**`. But, that's only my opinion, and a guess. Since it's hard to know the intention without the [mcve]. – Algirdas Preidžius Sep 29 '19 at 12:51
  • @AlgirdasPreidžius Indeed, otherwise the allocated pointers are lost to the world! – Adrian Mole Sep 29 '19 at 12:55
  • @Adrian First, thank you for your response. What I meant by "some variants" is that I have precisely tried the answer you are giving, but this just returns the values of the pointers **indatav. I don't want the position of the pointers in the memory of the computer, I want the values which are pointed by the pointers in **indatav, and I would like my function to return those values. This is also why I left as return type of the function float and not **float. I don't know if this is clear enough ? Please tell me if it still isn't. I will also adapt my question. – Joachim Sep 29 '19 at 14:12
  • @AlgirdasPreidžius No I really want to return the values pointed by the pointers of the 2 dimensional array. So I really want to return `float`and not `**float`. – Joachim Sep 29 '19 at 14:17
  • A function can return only one, fixed-size thing. If you have to return a dynamically allocated array, the solution is to return a pointer to it. Or encapsulate it into an object and return it, and by the way, there is already one for that - `std::vector`. – rustyx Sep 29 '19 at 14:26
  • @Adrian It seems to me, but I am surely wrong, that `outdatav`and `indatav`are not necessarly of the same type. Outdata contains `floats`as values, while `indatav`contains pointers, or adresses which point to adresses which point to values. It is precisely those values which I want to retrieve and put in `outdatav`, if those values are floats, then there shouldn't be any problem. So pointing at those values with `outdatav[i][j] = *(*(indatav[i])[j]);`should work, in my way of understanding it. But I am surely mistaking. But still, I would like to understand why. – Joachim Sep 29 '19 at 14:26
  • @rustyx So the idea would be here to declare `outdatav`as a vector and not as an array ? But still, the question remains: how to access the values pointed by the `**indatav` ? – Joachim Sep 29 '19 at 14:32
  • @Adrian Yes indatav is an array of float variables. But **indatav is an array of pointers, pointing to the float variables. Correct me if I'm wrong. This is why I thought that, accessing those float variables, I could copy them into outdatav, and then, return them, by declaring the float type of return. Yes, I mean that each element [i][j] is a pointer to a float data – Joachim Sep 29 '19 at 16:46
  • @JoachimBsh You can't have it both ways! You give: `float indatav[2][2] = {{1.,2.};{3,4}}` so `indatav[i][j]` ***is not a pointer to float data*** it is just an actual `float`. – Adrian Mole Sep 29 '19 at 16:49
  • @Adrian Again, thank you very much for your time and your reply. I will try to repeat it in the way I understand it, please correct me if I'm wrong. `indatav` when being called in `cfun` is in the form `{{1.,2.},{3,4}}`. When declaring the function `cfun`, the function takes as arguments the pointers to the arrays of `indatav`, and not the float values. It then allocates those pointers in `outdatav` which is a double pointer object. – Joachim Sep 29 '19 at 18:23
  • @Adrian Now, I tried to compile your correction but still get the error: `test.cpp:30:41: error: cannot convert ‘float (*)[2]’ to ‘float**’ for argument ‘1’ to ‘float** cfun(float**, int, int)’ float **y = cfun(indatav, rows, cols);` So does this mean I should declare `float indatav` as a 2-dimensional pointing structure ? If yes, should I do it like you did with the 2 for loops in `cfun` ? – Joachim Sep 29 '19 at 18:23
  • @Adrian Well, first of all really a lot of thanks because this really helped me. It was blocking the final phase of my project and was really a pain in the ***. Again, thanks a lot. I will update the full answer – Joachim Sep 29 '19 at 19:05
  • @JoachimBsh From your comments, I see a lot of misconceptions on how the C++ language works. To learn it in a structured manner, consider learning from a [good C++ book](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). – Algirdas Preidžius Sep 30 '19 at 12:56
  • @AlgirdasPreidžius I have to agree! Was going to 'upvote' your comment but I've run out of "comment" upvotes for today … I didn't even known that was possible! (Still have two **real** votes left, though.) – Adrian Mole Sep 30 '19 at 13:00