0

I made the following simplified code for the purpose of this question:

typedef struct {
int m;    // 
particle_t **inparticles;    // Pointers to particles pointers
} grid_t;

typedef struct {
  double x;
  double y;
} particle_t;

void apply_force( particle_t &particle, particle_t &neighbor , double *dmin, double *davg, int *navg)
{
    double dx = neighbor.x - particle.x; // do stuff ...
    double dy = neighbor.y - particle.y;
}

void apply_grid_force(particle_t &particle, grid_t &bin, double dmin, double davg, int navg)
{
    for(int j = 0; j < bin.m; j++) {
        apply_force(particle, bin.inparticles[j], &dmin, &davg, &navg);
    }
}
// error here: invalid initialization of non-const reference of type ‘particle_t&’ from an rvalue of type ‘particle_t*’

int main()
{
    particle_t *particles = (particle_t*) malloc( 10 * sizeof(particle_t) ); // memory for particles pointers
    grid_t *grid = (grid_t*) malloc( 5 * sizeof(grid_t) ); // memory for grid pointers
    
    for(int i = 0; i < num_bins; i++) {
        grid[i].inparticles = (particle_t**) malloc(3 * sizeof(particle_t *)); // memory for pointers to particles pointers
        grid[i].m = 0; 
    }
    
    apply_grid_force(grid[i].inparticles[j], grid[i], dmin, davg, navg);
// error here: invalid initialization of reference of type ‘particle_t&’ from expression of type ‘particle_t*’
}

How can I pass the poniter to pointer "inparticles" to the function apply_grid_force so I can use the "particle" it is pointing to?

If I am not mistaken the problem is arising from me trying to cast the double-pointer to a pointer (inparticles to particles) but I am not sure how to solve it.

Yaser Baqi
  • 155
  • 1
  • 12
  • Please do not use `typedef struct` in C++, it creates problems and solve none. – Slava Mar 16 '21 at 03:16
  • 2
    `malloc` -- Looks like you're writing C code, not C++. Why are you not using `std::vector`? – PaulMcKenzie Mar 16 '21 at 03:18
  • I apologize for the C and C++ code Frankenstein monster. I am only editing part of the code and that's what I am working with. – Yaser Baqi Mar 16 '21 at 03:22
  • "If I am not mistaken the problem is arising from me trying...". Unfortunately looks like problem is arising from you not understanding what you are doing. You mix pointers with refernces left and right so it is difficult to say what is where. You better be consistent. – Slava Mar 16 '21 at 03:23
  • @Slava could you please provide a source for "Please do not use typedef struct in C++"? I would like to learn more. – Zois Tasoulas Mar 16 '21 at 03:25
  • You are confusing pointers and references in `apply_force(&particle, bin.inparticles[j], &dmin, &davg, &navg);` where `void apply_force( particle_t &particle, ...` takes a *reference-to* `particle_t` yet you are attempting to pass the *address of* `particle` (e.g. `&particle`). That's apples and oranges. – David C. Rankin Mar 16 '21 at 03:26
  • 3
    @zois 1 unlike C in C++ `struct` name is a type, so using `typedef struct ...` is pointless. 2 - you cannot forward declare such name, so it create problems. – Slava Mar 16 '21 at 03:27
  • 3
    I suggest avoiding the term "double pointer". Use something like "pointer to pointer" instead. The problem is that "double pointer" can mean `double*`. See https://stackoverflow.com/tags/double-pointer/info – Keith Thompson Mar 16 '21 at 03:28
  • @Slava granted, new code should not `typedef` structs (or classes), but depending on how old this legacy code is it may have originally been written that way in the 90s. For purposes here, so long as there is no reliance on a constructor, etc.. (which `malloc()` knows nothing about) it won't impact this particular question. But you are 100% correct as a general proposition. (the same applies to the use of `malloc()` in C++, it shouldn't be the allocation method used today, but for a decade plus of legacy code, you still find it in places) – David C. Rankin Mar 16 '21 at 03:31
  • @YaserBaqi -- Maybe the confusion is that `&` has two meanings in C++, and neither are related. The first one is the classic `C` definition of `&` meaning `address-of`. Then the second meaning is for C++, where `&` means reference. You seem to be conflating the two meanings. – PaulMcKenzie Mar 16 '21 at 03:37
  • `apply_grid_force(grid[i].inparticles[j], grid[i], dmin, davg, navg);` is not within any loop, so the `i` and `j` subscripts make no sense. Please show your actual code. [A Minimal, Complete, and Verifiable Example (MCVE)](http://stackoverflow.com/help/mcve). As shown, you would need something like `void apply_grid_force (particle_t &particle, grid_t &bin, double dmin, double davg, int navg) {...}` that calls `apply_force (particle, bin.inparticles[j], &dmin, &davg, &navg);` and then your call in `main()` makes sense -- but as shown, no values are initialized in `main()`. – David C. Rankin Mar 16 '21 at 03:47

3 Answers3

1

You are not trying to cast a pointer-to-pointer to a pointer, you are casting a pointer-to-a-struct into a struct. inparticles is of the type particle_t**, so its elements are of the type particle_t* (that's what you're passing to the function with grid[i].inparticles[j], you're getting an element of the array.)

Here's the thing, apply_grid_force doesn't take a pointer to a particle, it takes a reference, which is different. References are used just like regular variables but aren't copied when passed to a function, so modifying a passed reference modifies the original copy, just like a pointer, except that unlike a pointer you treat it, in code, like you would any other particle_t. It also means you should pass a particle_t to apply_grid_force, not a particle_t*, by dereferencing it:

apply_grid_force(*grid[i].inparticles[j], grid[i], dmin, davg, navg);
Digit
  • 68
  • 5
0

Is just dereference it will remove an error ? Like this:

apply_grid_force(*grid[i].inparticles[j], grid[i], dmin, davg, navg);

I also agree with comments related to the implementation.

Digit
  • 68
  • 5
Valeca
  • 122
  • 8
0

There seems to be a confusion with pointers and object-oriented concepts.

I will answer your question in both C (not object oriented) and C++ (object oriented).

C

To use it in the function:

void accessParticle(particle_t *particle)
{
    particle->x = 5; //"particle" is a pointer to a particle_t structure
} 

To pass it to the function:

accessParticle(grids[0].inparticles[0]); //"inparticles" is de-referenced to a pointer

C++

To use it in the function:

void accessParticle(particle_t &particle)
{
    particle.x = 5; //"particle" is an object-reference to a particle_t structure
} 

To pass it to the function:

accessParticle(*(grids[0].inparticles[0])); //Read explanation bellow

Here, inparticles is first de-referenced to a pointer to a particle_t structure, which is then de-referenced to a particle_t structure. The whole structure is not copied since only the object reference of this structure is passed to the function. In this way, particle (inside the accessParticle function) makes reference to the same object instance.

Please read this to further clarify any doubts: