Despairing of a pointer-holding array

Hey guys,

since I spent the whole evening to fiddle about the basics of pointers (and learning quite a lot) I’m now at a point I just don’t get why my ESP32 crashes. It’s only one line of code I really do not understand - I hope someone could bring some light into the darkness…? The line between the hashtags is the problematic one.

And: Why is the address of array1[0] = 0x3ffc00bc within getPointer() and within setup() it is 0 (just before the hashtags)? As far as I understand array is a global variable?

int *arr[3];

int value = 5;
int val2 = 3;
int *array1[3] = {0,0,0};


int *(*getPointer())[3] {
  extern int * array1[3];
  int *pValue= &value;
  array1[0] = &value;
  array1[1] = &val2;
  printf("Address of array1 within getPointer(): %p\n", (void *)&array1);
  printf("Address of value within getPointer(): %p\n", (void *)&value);
  printf("Address of val2 within getPointer(): %p\n", (void *)&val2);
  printf("Content of array1 within getPointer(): %p\n", (void *)*array1); // Address of value
  printf("Address of array1[0] within getPointer(): %p\n", (void *)array1[0]); // Address of value
  printf("Address of array1[1] within getPointer(): %p\n", (void *)array1[1]); // Address of val2
  printf("Address of array1[2] within getPointer(): %p\n", (void *)array1[2]); // Address of array1[2] -> 0x0
  printf("Content of array1[0] within getPointer(): %i\n", *array1[0]);
  printf("Content of array1[1] within getPointer(): %i\n", *array1[1]);
  //printf("Content of array1[2] within getPointer(): %i\n", *array1[2]); // ESP stürzt ab --> vermutl. weil array1[2] leer ist
  return &array1;
}


void setup() {

arr[0] = &value;


  
  // put your setup code here, to run once:
  delay(3000);
  Serial.begin(115200);
  delay(1000);
  Serial.println("Ready");
  Serial.print("value: ");
  Serial.println(value);

  printf("Address of arr is %p\n", (void *)arr);  

  Serial.print("Content of arr[0] is ");
  Serial.println(*arr[0]);

  printf("Address of arr[0] is %p\n", (void *)&(*arr[0]));
  
  printf("Address of array1 is %p\n", (void *)array1);  

  printf("Address of array1[0] is %p\n", (void *)array1[0]);
  printf("Address of array1[1] is %p\n", (void *)array1[1]);
  printf("Address of array1[2] is %p\n", (void *)array1[2]);





// #############################################



  printf("Content of array1[0] : %i\n", *array1[0]); // Das crasht den ESP -> Reboot
  


// #############################################




/*
  Serial.print("Content of array1[0] is ");
  Serial.println(*array1[0]); // reboots ESP
*/
/*
  Serial.print("array1[0]: ");
  printf("Address of content of array1[0] is %p\n", (void *)*array1[0]);  // reboots ESP
*/

  printf("Address of value is %p\n", (void *)&value);  

  printf("Address of getPointer() is %p\n", (void *)getPointer());  // = array1

  printf("Address of getPointer()[0] is %p\n", (void *)*getPointer()[0]); // = value

  printf("Address of getPointer()[1] is %p\n", (void *)*getPointer()[1]); // = val2
/*
  Serial.print("rValue: ");
  Serial.println(rValue);
 */
}

void loop() {
  // put your main code here, to run repeatedly:

}

Many, many thanks in advance and best regards!

Does it still crash at the same point if you replace this:

int *array1[3] = {0,0,0};

with this:

int *array1[3] = {&value,0,0};

No, that works properly... and the address of array1[0] is then 0x3ffbebf8, not 0 anymore.

This construct:

int *array1[3] = {0,0,0};

Initialises the array to null pointers. It does not create 3 integers somewhere and fill the array with pointers to them, as you might have thought.

Attempts to dereference a null pointer may well cause a crash.

The function getPointer(), which you have not called at this stage, would have initialised array1[0] to &value.

6v6gt:
which you have not called at this stage

That's the point. This is so simple, I'm so annoyed of myself right now. Thanks for this quick help!

what is the purpose of the following (never seen such a thing in my entire career)

int *(*getPointer())[3] {

i specified a non-zero value for array1[0] and that avoided a crash. (i assume an attempt to access address zero is an exception; It generated a segmentation fault on my laptop probably because it is outside the memory space for the task)

   array1 [0] = &value;
    printf("Content of array1[0] : %i\n", *array1[0]); // Das crasht den ESP -> Reboot

with that change, i get the following

Ready
value: 5
Address of arr is 0x3ffc00c8
Content of arr[0] is 5
Address of arr[0] is 0x3ffbebec
Address of array1 is 0x3ffc00bc
Address of array1[0] is 0x0
Address of array1[1] is 0x0
Address of array1[2] is 0x0
Content of array1[0] : 5
Address of value is 0x3ffbebec

getPointer:
Address of array1 within getPointer(): 0x3ffc00bc
Address of value within getPointer(): 0x3ffbebec
Address of val2 within getPointer(): 0x3ffbebe8
Content of array1 within getPointer(): 0x3ffbebec
Address of array1[0] within getPointer(): 0x3ffbebec
Address of array1[1] within getPointer(): 0x3ffbebe8
Address of array1[2] within getPointer(): 0x0
Content of array1[0] within getPointer(): 5
Content of array1[1] within getPointer(): 3
Address of getPointer() is 0x3ffc00bc

getPointer:
Address of array1 within getPointer(): 0x3ffc00bc
Address of value within getPointer(): 0x3ffbebec
Address of val2 within getPointer(): 0x3ffbebe8
Content of array1 within getPointer(): 0x3ffbebec
Address of array1[0] within getPointer(): 0x3ffbebec
Address of array1[1] within getPointer(): 0x3ffbebe8
Address of array1[2] within getPointer(): 0x0
Content of array1[0] within getPointer(): 5
Content of array1[1] within getPointer(): 3
Address of getPointer()[0] is 0x3ffbebec

getPointer:
Address of array1 within getPointer(): 0x3ffc00bc
Address of value within getPointer(): 0x3ffbebec
Address of val2 within getPointer(): 0x3ffbebe8
Content of array1 within getPointer(): 0x3ffbebec
Address of array1[0] within getPointer(): 0x3ffbebec
Address of array1[1] within getPointer(): 0x3ffbebe8
Address of array1[2] within getPointer(): 0x0
Content of array1[0] within getPointer(): 5
Content of array1[1] within getPointer(): 3
Address of getPointer()[1] is 0x3ffbebec

your modified code

int *arr[3];
int value = 5;
int val2 = 3;
int *array1[3] = {0,0,0};
// -----------------------------------------------------------------------------
int *(*getPointer())[3] {
    printf ("\n%s:\n", __func__);
    extern int * array1[3];
    int *pValue= &value;
    array1[0] = &value;
    array1[1] = &val2;
    printf("Address of array1 within getPointer(): %p\n", (void *)&array1);
    printf("Address of value within getPointer(): %p\n", (void *)&value);
    printf("Address of val2 within getPointer(): %p\n", (void *)&val2);
    printf("Content of array1 within getPointer(): %p\n", (void *)*array1); // Address of value
    printf("Address of array1[0] within getPointer(): %p\n", (void *)array1[0]); // Address of value
    printf("Address of array1[1] within getPointer(): %p\n", (void *)array1[1]); // Address of val2
    printf("Address of array1[2] within getPointer(): %p\n", (void *)array1[2]); // Address of array1[2] -> 0x0
    printf("Content of array1[0] within getPointer(): %i\n", *array1[0]);
    printf("Content of array1[1] within getPointer(): %i\n", *array1[1]);
    //printf("Content of array1[2] within getPointer(): %i\n", *array1[2]); // ESP stürzt ab --> vermutl. weil array1[2] leer ist
    return &array1;
}

// -----------------------------------------------------------------------------
void setup() {
    arr[0] = &value;
    // put your setup code here, to run once:
    delay(3000);
    Serial.begin(115200);
    delay(1000);
    Serial.println("Ready");
    Serial.print("value: ");
    Serial.println(value);
    printf("Address of arr is %p\n", (void *)arr);
    Serial.print("Content of arr[0] is ");
    Serial.println(*arr[0]);

    printf("Address of arr[0] is %p\n", (void *)&(*arr[0]));
    printf("Address of array1 is %p\n", (void *)array1);
    printf("Address of array1[0] is %p\n", (void *)array1[0]);
    printf("Address of array1[1] is %p\n", (void *)array1[1]);
    printf("Address of array1[2] is %p\n", (void *)array1[2]);

    // #############################################
    array1 [0] = &value;
    printf("Content of array1[0] : %i\n", *array1[0]); // Das crasht den ESP -> Reboot
    // #############################################

    /*
    Serial.print("Content of array1[0] is ");
    Serial.println(*array1[0]); // reboots ESP
    */
    /*
    Serial.print("array1[0]: ");
    printf("Address of content of array1[0] is %p\n", (void *)*array1[0]);  // reboots ESP
    */
#if 1
    printf("Address of value is %p\n", (void *)&value);
    printf("Address of getPointer() is %p\n", (void *)getPointer());  // = array1
    printf("Address of getPointer()[0] is %p\n", (void *)*getPointer()[0]); // = value
    printf("Address of getPointer()[1] is %p\n", (void *)*getPointer()[1]); // = val2
#endif
    /*
    Serial.print("rValue: ");
    Serial.println(rValue);
    */
}

// -----------------------------------------------------------------------------
void loop() {
    // put your main code here, to run repeatedly:
}

gcjr:
what is the purpose of the following (never seen such a thing in my entire career)

It actually returns a pointer to an array (size 3) of pointers to integers. I found this site very useful to understand that expression: Declare a C/C++ function returning pointer to array of integer pointers - GeeksforGeeks

alve89:
It actually returns a pointer to an array (size 3) of pointers to integers. I found this site very useful to understand that expression: Declare a C/C++ function returning pointer to array of integer pointers - GeeksforGeeks

wow.
but you statically initialize the function pointer, not to a defined function, but to a body of code. why not just define a function?

gcjr:
wow.

Sorry for being not able to explain more, I'm very new to C++ so I'm just trying different code snippets and put them together to get the expected result.
And, before I got the hint again that I should learn C++ with some good books: I'm already doing, but I also like learning by doing.

gcjr:
but you statically initialize the function pointer, not to a defined function, but to a body of code. why not just define a function?

And now I can prove my sentence from above - I don't understand what you mean?

alve89:
And, before I got the hint again that I should learn C++ with some good books: I’m already doing, but I also like learning by doing.

while i believe we should all practice OOP, i’m not a fan of c++. I’ve learned a lot from kernighan’s books (programming style, c programming language, unix programming environment chap 8)

alve89:
And now I can prove my sentence from above - I don’t understand what you mean?

the C programming language, chap 5.11 describes the use of function pointers where you don’t want to have to conditionally test whether to use a particular function but simply invoked the function that a function pointer is set to. that book illustrates many programming features with very practical examples.

i use function pointers in table driven state machines where the action routines are specified as function pointers in a table for each state and stimuli. using tables makes the state machine easier to understand especially when large

//
// example state machine
//

#include <stdio.h>

#include "stateMach.h"

// ------------------------------------------------
Status
a (void* a)
{
    printf ("%s:\n", __func__);
    return OK;
}

// ------------------------------------------------
Status
b (void* a)
{
    printf ("%s:\n", __func__);
    return OK;
}

// ------------------------------------------------
Status
c (void* a)
{
    printf ("%s:\n", __func__);
    return OK;
}

// ------------------------------------------------
Status
__ (void* a)
{
    printf ("%s:\n", __func__);
    return OK;
}

// --------------------------------------------------------------------

#define N_STATE     3
#define N_STIM      2

typedef enum { S0, S1, S2 } State_t;

typedef Status(*Action_t)(void*) ;

State_t smTransitionTbl [N_STATE] [N_STIM] = {
    {   S1, S2, },
    {   S0, S2, },
    {   S2, S1, },
};


Action_t smActionTbl [N_STATE] [N_STIM] = {
     {  a,  b },
     {  c, __ },
     { __,  a },
};

// ------------------------------------------------
char *msg1 [] = {
    "State machine has 3 states and 2 stimuli.",
    "It has the following state transistion and action routine tables.",
    "A __() represents do nothing and is easily identified in table.",
    "Each row is indexed by a state and each column a stimulus.",
    "Of course, meaningful action routine names are helpful.",
};

char *msg2 [] = {
    "Enter valid stimuli [0-1]:"
};

void
smHelp (void)
{
    for (int i = 0; i < sizeof(msg1)/sizeof(char*); i++)
        printf ("  %s\n", msg1 [i]);

    for (int state = 0; state < N_STATE; state++)  {
        printf ("%8s", "");
        for (int stim = 0; stim < N_STIM; stim++)
            printf (" %d", smTransitionTbl [state][stim]);

        printf ("%8s", "");
        for (int stim = 0; stim < N_STIM; stim++)  {
            if (a == smActionTbl [state][stim])
                printf ("  a()");
            else if (b == smActionTbl [state][stim])
                printf ("  b()");
            else if (c == smActionTbl [state][stim])
                printf ("  c()");
            else
                printf (" __()");
        }

        printf ("\n");
    }

    for (int i = 0; i < sizeof(msg2)/sizeof(char*); i++)
        printf ("  %s\n", msg2 [i]);

}

// ------------------------------------------------
static State_t _smState  = S0;

Status
smEngine (Stim_t stim)
{
    Action_t   func;
    State_t    last = _smState;

    if (N_STIM <= stim)
        return ERROR;

    func        = smActionTbl [_smState] [stim];
    _smState    = smTransitionTbl [_smState] [stim];

    printf ("    stim %d, transition from state %d to %d, exec ",
        stim, last, _smState);

    return (*func) (NULL);
}