hudac
hudac

Reputation: 2798

Sending pointer to a function, while the pointer is part of an array of pointers

I'm trying to send a pointer to function, but the pointer is part of an array of pointers

void func(A **pa)
{
     return;
}


A *pa;
pa=(A*)malloc(2*sizeof(A));

So, the first item in the array pa[0] is easy to send (because it is the place the pointer points to)

func(&pa);

But now I get stuck, how can I send the second item? pa[1]

I tried something like func(&pa + 1*sizeof(A)); but it didn't seem to work.

Upvotes: 1

Views: 286

Answers (4)

Miltos Kokkonidis
Miltos Kokkonidis

Reputation: 3996

NOTE: This answer has been updated to reflect the clarifications @hudac, the OP (original poster), gave a four hours ago. The question asked is both valid and quite interesting. Having said that, there may be ways the OP's code can be simplified, and I will look at those after providing an answer to the original question.

First, I will try to make the question's code a bit more concrete, by giving an example definition for A and func, in accordance with the OP's recent clarification:

typedef struct { int x; int y;} A;

void func(A **ppa)
{
   printf("(%d,%d)\n",(*pa)->x,(*pa)->y);
}

Then, I will give some code that provides appropriate context for both the question and the answer:

void main() {
    A *pa;  
    pa = (A*) malloc(2 * sizeof(A));

    pa[0].x = 3;    pa[0].y = 4;
    pa[1].x = 13;    pa[1].y = 42;

    func(&pa);      
    //the answer to the question goes here
}

The question as it stands asks for a way to pass a pointer to a pointer to the second element of the dynamically allocated array of A's pa. The OP tried, having succeeded in passing a pointer to a pointer to the first element of pa (func(&pa);) tried to do pass a pointer to a pointer to the second element using pointer arithmetic, which of course did not work as desired. None of the answers given even comes close to being correct given the OP's code! This turns out to be quite an interesting question because having func expect an A ** rather than an A * makes things so much more complicated than they have to be. It is possible to make things simpler without understanding the problem the OP got into, but this would provide no insight into why it was so difficult (in fact, impossible) to get that pointer arithmetic right.

A small detour to revisit the basics: if you have an assignment, you have an lvalue (the left-hand side expression) and an rvalue (the right-hand side expression); the lvalue is something that has an address and the rvalue has a value which the assignment stores in the lvalue's address. An example: x = 5; An expression may have both an lvalue and an rvalue (e.g. x) or it may only have an rvalue (e.g. 5). The operator & only applies to lvalues i.e. to things that have a memory address i.e. things such as x, but not things such as 5.

Back to the question: pa is of type A * whereas func expects an argument of type A **. The OP had no problem figuring out how to invoke func so that it would work with the first element of pa:

func(&pa);

Please note that I find it very difficult to stomach giving this bit of code together with a comment that this is a call to func working on the first element of pa. Function func needs to operate on pa[0] (a.k.a. * pa) i.e. something of type A but because of how func has been defined we are passing &pa of type A ** !!! I will address this issue later by defining functions with more appropriate argument types. For now, I will try to work with what I have.

The reason why the OP and others found it so difficult to make a call to func that would work with the second element of pa is that what is required is a pointer expression whose value holds the address of a bit of memory holding the address of the 2nd element of pa. THERE IS NO SUCH POINTER EXPERSSION BECAUSE THE ADDRESS OF THE 2ND ELEMENT OF pa IS NOT STORED ANYWHERE. (Apologies if the capitals hurt your eyes :-) I needed to make this as clear as possible!) Access to the 2nd element of pa is by means of pointer arithmetic, using the address of the 1st element (which is what pa holds).

That does not mean that it is impossible to answer the question. It just means that the answer will be unexpected and a nasty hack. So, assuming the question does not allow us to introduce another variable in main(), we would simply have to change pa in order to make the call to func, and change it back in order to be able to work with pa without nasty surprises later on in main().

pa++; func(&pa); pa--;

This is the answer to the OP's question. The other answers currently posted here try to answer different and much simpler questions. But the original question is much more interesting and now it has an answer :-) But more interesting than the answer, I feel, is the observation I emphasised using capitals.

In order to regain our sanity, we need to revisit the choices made in the definition of func.

If all we ever wanted was to access the A's stored in the array we could consider eliminating reliance on pointers altogether.

typedef struct { int x; int y;} A;
void bar(A a)
{
   printf("(%d,%d)\n", a.x, a.y);
}
void main() {
    A *pa;  
    pa = (A*) malloc(2 * sizeof(A));

    pa[0].x = 3;    pa[0].y = 4;
    pa[1].x = 13;    pa[1].y = 42;

    bar(pa[0]);      
    bar(pa[1]);
}

There are two reasons why we might want to consider having our function take a A * argument rather than a plain A: 1. if the function needs to modify the A pointed to and/or 2. if A happens to be a large structure and we do not want every call to our function to result in copying a big chunk of memory to the stack.

typedef struct { int x; int y;} A;
void foo(A *a)
{
   int tmp = a->x;
   a->x = a->y;
   a->y = tmp;
}
void bar(A a)
{
   printf("(%d,%d)\n", a.x, a.y);
}
void main() {
    A *pa;  
    pa = (A*) malloc(2 * sizeof(A));

    pa[0].x = 3;    pa[0].y = 4;
    pa[1].x = 13;    pa[1].y = 42;

    foo(&pa[0]); //or alternatively: foo(pa);
    bar(pa[0]);  //or alternatively: bar(*pa);

    foo(&pa[1]); //or alternatively: foo(pa + 1);
    bar(pa[1]);  //or alternatively: bar(*(pa+1));
}

One additional note than may help the OP is that in performing pointer arithmetic the type of the pointer plays a role. So the numeric value of pa + 1 equals the numeric value of pa plus sizeof(A). (This relates to the failed attempt to make func work with the second element of pa the following call: func(&pa + 1*sizeof(A)))

Final note to OP: If you do not want to change the signature of func because you had plans to get an A** pointer inside func and do funny things with it, like assign to it another pointer (e.g. pointing to a newly malloc()-allocated chunk of memory), you would be walking into a minefield! Please check my answer to another question which I believe you will find relevant: Why the free in line2 makes memcpy do nothing?? Is free before malloc is o.k?? The moral of the story is that pointers are useful but conceptual complexity and likelihood of error grows exponentially with each * (and often there are better alternatives) :-)

Upvotes: 2

Omkant
Omkant

Reputation: 9204

try this :

func(&pa[0]); // for 1st object 
func(&pa[1]);// for 2nd object

pa will give you the address of an array of A. &pa will give you the address of whole array.

means,

A * ptr;

ptr = pa ;// increment `ptr` will give you next element in same array
ptr = &pa ;// increment `ptr` will give you the next array of that type

Also change the function func signature to

void func(A *pa)
{
     return;
}

============================================================

If you want to pass the array of pointers to func

do like this :

A **pa = malloc(2*sizeof(A*));

and then send it like

func(&pa[0]);
func(&pa[1]);

and func will be

void func(A **pa)
{
     return;
}

Upvotes: 1

gil_bz
gil_bz

Reputation: 484

If you want to pass a pointer to the array of A's you should do it like this:

func(&pa[0]); 
func(&pa[1]);

But if it is an array, should you not just pass a pointer to the array itself, and the array's size? This basically means only the first line.

If you wanted to pass a pointer to an array of pointers you should've done it completely differently:

A **pa;
pa=(A**)malloc(2*sizeof(A*));

but then you will also have to malloc each A and change Func accordingly.

Also note thatfunc(&pa + 1*sizeof(A)) would not work because of pointer mathematics: you only need to do func(&pa + 1) and the compiler takes care of the rest to get the second member in the array.

Upvotes: 2

wallyk
wallyk

Reputation: 57784

You are looking for &pa[1]:

func (&pa[1]);   // call function with second element of pointer array

By the way, I can't tell if you mean to allocate an array of only two pointers, but if you are, the malloc is in error. It should be

pa = malloc (2 * sizeof(A*));  // note the addition of * after "A"

What you are doing is allocating twice the size of an A, which conceivably could be thousands of bytes long. That much space is not needed for a pointer to such an object.

Also, in C, one need not—and should not—cast the return type of malloc().

Upvotes: 2

Related Questions