Difficulties to understand pointer-notations *myVar / myVar* (byte*&) myVar

Hi everybody,

my main goal is to use the base32-library to convert a base32-encoded sequency of characters into their ASCII-code representation.

I found this library which claims to can do this

The base32-library has a single example that tries to demonstrate the use.
Well for adpating the demo-code to my needs the comments are too poor for me to understand.

these are the lines of code that are of intererest (I add the complete demo-sketch below)

  byte* tempDecoded = NULL; // pointer to a "byte"-variable??


  // ASCII-code representation of the character-sequency as array of bytes
  byte enc6[] = {'f', 'o', 'o', 'b', 'a', 'r'};  


  // base32-encoded representation of the character-sequence as array of bytes
  byte dec6[] = {'M', 'Z', 'X', 'W', '6', 'Y', 'T', 'B', 'O', 'I', '=', '=', '=', '=', '=', '='}; // MZXW6YTBOI======


// definition of the function convert from base32 to ASCII
int Base32::fromBase32(byte* in, long length, byte*& out)



// call of the conversion-function embedded into checking to be equal to the pre-defined
// array of bytes
  if (base32.fromBase32(dec0, sizeof(dec0), (byte*&)tempDecoded) == 0 &&
    memcmp(tempDecoded, enc0, sizeof(enc0)) == 0) {} else { return false; }
  free(tempDecoded);

Now my questions are:
There is a definition of a "bytepointer"

  byte* tempDecoded = NULL; // pointer to a "byte"-variable??

the "variable" where the conversion-result is stored into is written as

(byte*&)tempDecoded

My - maybe wrong - understanding of this is:

start to store the sequence of bytes at the adress of variable tempDecoded

How the heck can I assure that nothing wrong gets overwritten through the byte-sequence???

Somehow I have the feeling I do not understand what is happening. And that my description is wrong. But I'm unable to solve it myself.

Somehow this function seems to allocate memory and free the memory in the end.
Without understanding what exactly this code is doing I find it very dangerous to modify it.

I would prefer that the function is used in the same way as a cpystr or memcpy-command is used.
With cpystr / memcpy the compiler expects a byte-array or string as the parameter and is able to interpret it as pointer to the RAM-location where the character-sequence is stored.
This is done by simply using the variable itself with no pointer-asterics or anything

char str1[]="Sample string";
  char str2[40];
  strcpy (str2,str1);//str1 copies to str2

Now this "fromBase32-function uses the asterics and the "&"-symbol in combination like this

(byte*&)tempDecoded)

and I have no idea what this means
byte-pointer by reference???
referenced bytepointer?????

And how I would have to modify it to make it work with arrays of char containing the character-sequence.

here is the complete democode that comes with the library

#include "Base32.h"

Base32 base32;

boolean tests()
{
  String encoded, decoded = "";
  byte* tempEncoded = NULL;
  byte* tempDecoded = NULL;

  //            encoding                                         decoding
  byte enc0[] = {};                                byte dec0[] = {};
  byte enc1[] = {'f'};                             byte dec1[] = {'M', 'Y', '=', '=', '=', '=', '=', '='}; // MY======
  byte enc2[] = {'f', 'o'};                        byte dec2[] = {'M', 'Z', 'X', 'Q', '=', '=', '=', '='}; // MZXQ====
  byte enc3[] = {'f', 'o', 'o'};                   byte dec3[] = {'M', 'Z', 'X', 'W', '6', '=', '=', '='}; // MZXW6===
  byte enc4[] = {'f', 'o', 'o', 'b'};              byte dec4[] = {'M', 'Z', 'X', 'W', '6', 'Y', 'Q', '='}; // MZXW6YQ=
  byte enc5[] = {'f', 'o', 'o', 'b', 'a'};         byte dec5[] = {'M', 'Z', 'X', 'W', '6', 'Y', 'T', 'B'}; // MZXW6YTB
  byte enc6[] = {'f', 'o', 'o', 'b', 'a', 'r'};    byte dec6[] = {'M', 'Z', 'X', 'W', '6', 'Y', 'T', 'B', 'O', 'I', '=', '=', '=', '=', '=', '='}; // MZXW6YTBOI======
  byte enc7[] = {0};                               byte dec7[] = {'A', 'A'};
  byte enc8[] = {0, 0};                            byte dec8[] = {'A', 'A', 'A', 'A'};
  byte enc9[] = {0, 0, 0};                         byte dec9[] = {'A', 'A', 'A', 'A', 'A'};

  byte enc10[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0F, 0xD5, 0x9B, 0x8D};
  byte dec10[] = {0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 
                  0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 
                  0x41, 0x41, 0x41, 0x41, 0x42, 0x37, 0x4B, 0x5A, 0x58, 0x44, 0x49};

  if (base32.toBase32(enc0, sizeof(enc0), (byte*&)tempEncoded, true) == 0 &&
    memcmp(tempEncoded, dec0, sizeof(dec0)) == 0) {} else { return false; }
  free(tempEncoded);

  if (base32.fromBase32(dec0, sizeof(dec0), (byte*&)tempDecoded) == 0 &&
    memcmp(tempDecoded, enc0, sizeof(enc0)) == 0) {} else { return false; }
  free(tempDecoded);

  if (base32.toBase32(enc1, sizeof(enc1), (byte*&)tempEncoded, true) > 0 &&
    memcmp(tempEncoded, dec1, sizeof(dec1)) == 0) {} else { return false; }
  free(tempEncoded);

  if (base32.fromBase32(dec1, sizeof(dec1), (byte*&)tempDecoded) > 0 &&
    memcmp(tempDecoded, enc1, sizeof(enc1)) == 0) {} else { return false; }
  free(tempDecoded);

  if (base32.toBase32(enc2, sizeof(enc2), (byte*&)tempEncoded, true) > 0 &&
    memcmp(tempEncoded, dec2, sizeof(dec2)) == 0) {} else { return false; }
  free(tempEncoded);

  if (base32.fromBase32(dec2, sizeof(dec2), (byte*&)tempDecoded) > 0 &&
    memcmp(tempDecoded, enc2, sizeof(enc2)) == 0) {} else { return false; }
  free(tempDecoded);

  if (base32.toBase32(enc3, sizeof(enc3), (byte*&)tempEncoded, true) > 0 &&
    memcmp(tempEncoded, dec3, sizeof(dec3)) == 0) {} else { return false; }
  free(tempEncoded);

  if (base32.fromBase32(dec3, sizeof(dec3), (byte*&)tempDecoded) > 0 &&
    memcmp(tempDecoded, enc3, sizeof(enc3)) == 0) {} else { return false; }
  free(tempDecoded);

  if (base32.toBase32(enc4, sizeof(enc4), (byte*&)tempEncoded, true) > 0 &&
    memcmp(tempEncoded, dec4, sizeof(dec4)) == 0) {} else { return false; }
  free(tempEncoded);

  if (base32.fromBase32(dec4, sizeof(dec4), (byte*&)tempDecoded) > 0 &&
    memcmp(tempDecoded, enc4, sizeof(enc4)) == 0) {} else { return false; }
  free(tempDecoded);

  if (base32.toBase32(enc5, sizeof(enc5), (byte*&)tempEncoded, true) > 0 &&
    memcmp(tempEncoded, dec5, sizeof(dec5)) == 0) {} else { return false; }
  free(tempEncoded);

  if (base32.fromBase32(dec5, sizeof(dec5), (byte*&)tempDecoded) > 0 &&
    memcmp(tempDecoded, enc5, sizeof(enc5)) == 0) {} else { return false; }
  free(tempDecoded);

  if (base32.toBase32(enc6, sizeof(enc6), (byte*&)tempEncoded, true) > 0 &&
    memcmp(tempEncoded, dec6, sizeof(dec6)) == 0) {} else { return false; }
  free(tempEncoded);

  if (base32.fromBase32(dec6, sizeof(dec6), (byte*&)tempDecoded) > 0 &&
    memcmp(tempDecoded, enc6, sizeof(enc6)) == 0) {} else { return false; }
  free(tempDecoded);

  if (base32.toBase32(enc7, sizeof(enc7), (byte*&)tempEncoded, true) > 0 &&
    memcmp(tempEncoded, dec7, sizeof(dec7)) == 0) {} else { return false; }
  free(tempEncoded);

  if (base32.fromBase32(dec7, sizeof(dec7), (byte*&)tempDecoded) > 0 &&
    memcmp(tempDecoded, enc7, sizeof(enc7)) == 0) {} else { return false; }
  free(tempDecoded);

  if (base32.toBase32(enc8, sizeof(enc8), (byte*&)tempEncoded, true) > 0 &&
    memcmp(tempEncoded, dec8, sizeof(dec8)) == 0) {} else { return false; }
  free(tempEncoded);

  if (base32.fromBase32(dec8, sizeof(dec8), (byte*&)tempDecoded) > 0 &&
    memcmp(tempDecoded, enc8, sizeof(enc8)) == 0) {} else { return false; }
  free(tempDecoded);

  if (base32.toBase32(enc9, sizeof(enc9), (byte*&)tempEncoded, true) > 0 &&
    memcmp(tempEncoded, dec9, sizeof(dec9)) == 0) {} else { return false; }
  free(tempEncoded);

  if (base32.fromBase32(dec9, sizeof(dec9), (byte*&)tempDecoded) > 0 &&
    memcmp(tempDecoded, enc9, sizeof(enc9)) == 0) {} else { return false; }
  free(tempDecoded);

  if (base32.toBase32(enc10, sizeof(enc10), (byte*&)tempEncoded, true) > 0 &&
    memcmp(tempEncoded, dec10, sizeof(dec10)) == 0) {} else { return false; }
  free(tempEncoded);
  
  if (base32.fromBase32(dec10, sizeof(dec10), (byte*&)tempDecoded) > 0 &&
    memcmp(tempDecoded, enc10, sizeof(enc10)) == 0) {} else { return false; }
  free(tempDecoded);

  return true;
}

void setup()
{
  pinMode(13, OUTPUT);
  digitalWrite(13, LOW);

  if (tests() == true) 
  { // if tests passed, then on-board LED is blinking
    while (1)
    {
      state = !state;
      digitalWrite(13, state);
      delay(100);
    }
  }
  else
  { // if tests failed, then on-board LED is on
    digitalWrite(13, state); 
  }
}

void loop()
{
}

thank you very much in advance
best regards Stefan

It's References to pointers.

well that's a link - to a website - which at least for me - is even more difficult to understand.
best regards Stefan

1 Like

reference to pointer. when pointer is passed to a function normally it gets copied, but in this case it is passed by reference and is changed inside the function so original pointer is now pointing to a new chunk of data.

If you pass a value to the function, it will be copied and used as another value.
So, by passing it as a pointer to the function, it tries to change the original value instead of copying it.

It's the same thing.

If you pass a pointer to the function, it will be used as another value.
So you can change the original value instead of copying it by passing it to the function as a reference to a pointer.

Try running this code. (Available in Uno and Nano)

In testFunc1, the value of the original pointer has not changed.
However, in testFunc2, the value of the original pointer has changed.

int testvalue1 = 0;
int testvalue2 = 0;
int* testpointer = &testvalue1;

void setup() {
  Serial.begin(9600);
  printValue();
  testFunc1(testpointer);
  printValue();
  testFunc2(testpointer);
  printValue();
}

void loop() {
}

void testFunc1 (int* value) {
  *value += 10;
  value = &testvalue2;
  * value += 10;
}

void testFunc2 (int*& value) {
  *value += 10;
  value = &testvalue2;
  * value += 10;
}

void printValue() {
  Serial.print("testvalue1 = ");
  Serial.print(testvalue1);
  Serial.print(" , testvalue2 = ");
  Serial.print(testvalue2);
  Serial.print(" , testpointer = ");
  Serial.println((unsigned int)testpointer, HEX);
}

image

In testFunc1, value is the value of the copied pointer.
So, if you change the value, doesn't change the original value.

In testFunc2, value is a reference to a pointer.
So, if you change the value, the original value will change.

EDIT:
I'm using google translations, so the explanations may be weird!
Understand from the my sample code if you can!

1 Like

So I use simple example-numbers to check if my understanding is right
There is this variable

  byte* tempDecoded = NULL;

which is a variable of type byte-pointer.

For even easier understanding let's say variable tempDecoded contains the value 0

This means the variable tempDecoded is pointing to RAM-adress 0

The variable tempDecoded has to be stored in RAM somewhere.
Let's say variable tempDecoded is stored at RAM-adress 100

Now the call of the converting function with

base32.fromBase32(dec0, sizeof(dec0), (byte*&)tempDecoded)

means do the conversion. The conversion-process happends to store the bytesequence into RAM at RAM-Adress 250

before returning from the function-call;
inside variable tempDecoded the value 250 is stored

Which means the pointer-variable tempDecoded contains 250 and this means this variable points to RAM-Adress 250 (where the converted byte-sequence is stored?

is this correct?
best regards Stefan

something like that

:+1:

OK @chrisknightley @killzone_kid

thank you very much for explaining and confirming it.

OK now I have to think about it how I have to modify this code to make it work this way:

I have an base32-encoded character-sequence

byte myBase32encodedKey[] = {'A','B','C','D','E'};
byte myTargetForConvertedASCII_HexKey[16];

and I want it to convert to an array of bytes that contains the ASCII-coded representation of the same sequence.

But I don't like this malloc-thing inside this library
I don't like malloc-ing and free-ing RAM.

So what I would prefer much more is a modified version of the function fromBase32

which can be used in the same way as a strcpy-function

define two arrays of char like this

char str1[]="Sample string";
  char str2[40];
  char str3[40];
  strcpy (str2,str1);//str1 copies to str2

and simply call the variables themselves. Or doing a memcpy like this

memcpy(destination, source, sizeof destination);

'I'm aware that I have to take care of how many bytes to copy as memcpy does the copying absolutely mercyless to what it means or what might gets overwritten.

best regards Stefan

have never seen "&* symbol".
consider

#include <stdio.h>

struct Junk {
    int     val;
    const char *desc;
};

Junk junk = { 123, "some value" };

void
func (
    Junk *p)
{
    printf (" %s: %6d  %s\n", __func__, p->val, p->desc);
}

void
func2 (
    Junk &p)
{
    printf (" %s: %6d  %s\n", __func__, p.val, p.desc);
}

int
main ()
{
    Junk j;

    func (& junk);
    func2 (junk);

    return 0;
}

@gcjr
It doesn't make sense if you don't need to manipulate of the pointer original value in a function.

not sure what doesn't make sense

References to pointers exist to manipulate the value of the calling pointer variable.
The function in code you provided didn't that.

not sure how this is relevant to *& combo

are you suggesting you would only ever pass a pointer if the modified value needs to be returned?

doesn't in make sense to make sure the use of "*symbol" and "&symbol" is clear?

Not passing a pointer.
Passing a reference to pointer.

If use * symbols or & symbols, has not same result for *& symbols.
Take a closer look at my sample code and the execution results.

ok
reference to pointer
instead of pointer to pointer

actually it makes it more confusing as OP was asking about reference to pointer

To explain a bit more about the complete project:

The main thing is to have a Seeeduino-XIAO to act as a access-key by connecting its USB-C-Port to windows-computers

accessing a web-based email which is only accessabe through a browser.
( absolutely NO chance to use thundebird or something similar)
accessing the emails requieres entering a loooong email-adress that can't be changed
entering a passwort with minimum 12 characters
entering a TOTP-token based on a key that is only available as base32-encoding

normally this means:
call web-interface
type in by hand looooong email-adress
type in by hand password
start WinAuth or pick up the smartphone to start Google-Authenticator
read TOTP-token or copy TOTP-token to clipboard
type or paste TOTP-token into webinterface.

And most of this shall be done by the XIAO
call web-interface
plug in XIAO
XIAO does the login-details

I don't want to discuss if this is secure enough or not.
(it requires to have this particular XIAO)

additionally I want to implement a function on the XIAO that enables
sending the XIAO the base32-encoded key over serial interface.

The Arduino TOTP-library requires to have the key as ASCII-coded byte-array.
And this is the reason why I need base32-to ASCII-code-conversion

As the key shall be changeable on the run-time-level workarounds like using
a web-based conversion-tool and modify the source-code is not a solution.

So this are the main facts and requirements for this project.
If somebody can provide an easier to use solution for this go ahead and post a link

best regards Stefan

me the same I have just seen

*&

but not

&*

arrrghh!!! writing asterisks requires code-tags

thank you for taking the time to write and post an example. Really I can honor that.

To be honest I will not consider your code because your code has no comments and is using non-selfexplaining names. I estimate that it will take less time to analyse all details how the code behaves if I start from scratch but with self-explaining names.

best regards Stefan