0

Is it possible to use address-of operator alongside prefix increment on pointers in the same statement, if yes how?

Example,

#include <stdio.h>
#include <stdint.h>

void main() {
    uint8_t arr_var[2];
    arr_var[0] = 0xa;
    arr_var[1] = 0xf;
    uint8_t *ptr = arr_var;
    uint8_t **dptr = &(++ptr);
}

Im getting the error

error: lvalue required as unary '&' operand

uint8_t **dptr = &(++ptr);

Is there any other alternatives rather than making it 2 separate statements (increment (ptr++) and then address-of (&ptr)).

Community
  • 1
  • 1
tonyjosi
  • 717
  • 1
  • 9
  • 17
  • 3
    Why do you want a pointer to a pointer? What is the actual problem you need to solve using such a pointer? – Some programmer dude Jan 28 '20 at 09:27
  • 2
    OT: `void main()` --> `int main(void)`. – Bob__ Jan 28 '20 at 10:05
  • 1
    Why didn't you increment ptr in the previous instruction? – Pierre François Jan 28 '20 at 10:14
  • 1
    "Is there any other alternatives rather than making it 2 separate statements" Is there are reason why it must be a single statement? Are you deliberately obfuscating the code? – Lundin Jan 28 '20 at 11:30
  • 1
    If you have to ask how to cram more code into a single statement, the answer is "Don't!". Why do you want to write code that's harder to understand? If you want to pre-increment some variable, do it on the line before. If you want to post-increment it, do it on the line after. You gain nothing by cramming it into one line. Except for the bugs you won't be able to solve because you made your code too complex. "Brevity of code" is just a cargo-cult aphorism. "Understandability of code" is paramount. – Andrew Henle Jan 28 '20 at 11:38
  • Yeah - please stop making your code difficult to debug:( – Martin James Jan 28 '20 at 13:56

2 Answers2

2

Problem:

Unlike C++, pointer incrementation/decrementation does not return an lvalue in C.

The addressof operator must have an lvalue as the operand.

Solution:

Since you want to achieve your task in a single statement, here is a tricky way to do it:

uint8_t **dptr = ++ptr ? &ptr : &ptr;

Some other solutions from the comment section:-

Lundin: uint8_t **dptr = (++ptr, &ptr);

Ardent Coder
  • 3,777
  • 9
  • 27
  • 53
  • Please see the edits, im getting error: lvalue required as unary '&' operand – tonyjosi Jan 28 '20 at 09:43
  • I want the incremented ptr and its address hence `&++ptr` – tonyjosi Jan 28 '20 at 09:48
  • 1
    @tonyjosi What do you *really* want? What is the *actual* problem you try to solve? By using a pointer to a pointer, you have a pointer to the variable `ptr` itself. If you do `++ptr` or `--ptr` is irrelevant, it won't change what `dptr` is pointing to. Your question is truly [an XY problem](http://xyproblem.info/). – Some programmer dude Jan 28 '20 at 09:58
  • @Someprogrammerdude Since the OP has asked for a solution that does it in a **single line**, I couldn't think of any other solution. The code is *not wrong* in the sense that the array pointer and the int pointer to the first element will very likely have the same representation and the same address internally. – Ardent Coder Jan 28 '20 at 10:49
  • @Someprogrammerdude dereferencing `dptr` as `*dptr` still works though `**dptr` doesn't because the intent of OP isn't clear enough. Anyways I'll update my answer so that it fully works like a double pointer. – Ardent Coder Jan 28 '20 at 11:26
  • 2
    Slightly less obscure is `uint8_t **dptr = (++ptr, &ptr);` but it is still rotten code. – Lundin Jan 28 '20 at 11:33
  • That's a nice one @Lundin I'll tag you in the post with another update. Let's try to collect all the tricky ways to do this :P – Ardent Coder Jan 28 '20 at 11:35
  • 1
    Okay. This is nice: `#define NICE(a,b,c,d,e) (d%:%:d a%:%:b%:%:c d d 666, e a??=??=b??=??=c)` ... `uint8_t **dptr = NICE(p,t,r,+,&);` – Lundin Jan 28 '20 at 12:29
  • Unfortunately `#define` adds up for an extra line of code lol @Lundin And I don't know if it works because I'm not much familiar with trigraphs. – Ardent Coder Jan 28 '20 at 12:32
  • 1
    Then use `#define NICE(a,b,c,d,e) (d%:%:d a%:%:b%:%:c d d 666, e a??=??=b??=??=c)\uint8_t **dptr = NICE(p,t,r,+,&);`. Of course it works, it is pure standard C. – Lundin Jan 28 '20 at 12:35
  • @EricPostpischil Please look at the edit history of the answer, and then you will see the line `uint8_t **dptr = ++ptr; // This will compile but throw a warning` which was what I commented about. – Some programmer dude Jan 28 '20 at 13:17
  • 1
    @Someprogrammerdude: Wasn’t your comment address to the author of the question, tonyjosi, not the author of the answer, Ardent Coder? That made it seem that “your assignment” referred to tonyjosi’s code, not Ardent Coder’s. – Eric Postpischil Jan 28 '20 at 14:28
  • @EricPostpischil Assignment as in C++ assignment as in `=` :) Perhaps *initialization* would have been a better word (as it wasn't an actual assignment). – Some programmer dude Jan 28 '20 at 15:03
2

It seems I was thrown off by one difference between C and C++...

In C the result of the increment or decerement operators is never an lvalue, and you can only get the addresses of lvalues.

This increment/decrement reference explicitly include the example &++a and says it's invalid.

To get a pointer to ptr you must use plain &ptr. Before of after incrementing the pointer doesn't matter, as dptr will be a pointer to ptr itself.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621