10 years, 6 months ago.

Dereferencing an array of pointers to arrays

I'm stumped again. In a prior post (http://mbed.org/questions/1581/Array-of-pointers-to-byte-arrays/), the kind people of this forum help me out. Now, I'm trying to take it to the next level and running into problems again. My project uses an 8-position DIP switch to select one of 256 patterns for blinking LEDs. I am trying to understand why the patterns don't appear as expected. If I remove the sequence pointer dereferencing attempt and simply point to a sequence, the sequence runs. Can any of you see what I am missing?

Many thanks.

main program

#include "mbed.h"
#include "bits.h"
#include "types.h"
#include "sequences.h"

/* Determines the fastest and slowest sequence step timing. Times are in
    1/60th of a second (one clock).*/    
#define FASTEST_TIME 12.0        /* about 100ms */
#define SLOWEST_TIME 360.0      /* about 3000ms */
/* The AnalogIn function scales the voltage input to a float 0.0-1.0. */
#define SLOPE (SLOWEST_TIME - FASTEST_TIME)

/* Setup a serial debug port on the USB interface. */
//Serial pc(USBTX, USBRX); // tx, rx

/* Setup the dipswitch input port. */
BusIn dipswitch(P0_7, P0_8, P0_9, P0_10, P0_11, P0_12, P0_13, P0_14);
/* Setup the pattern output port. */
//BusOut lights(P0_16, P0_17, P0_18, P0_19, P0_20, P0_21, P0_22, P0_23);
BusOut lights(P0_20, P0_22);

/* The potentiometer input port to select the speed of the sequence steps. */
AnalogIn potentiometer(P0_15);

Ticker heartbeat;       /* Simulates the 1/60th of a second clock from the future ZCD. */
DigitalOut led1(P0_21); /* For debugging inside the interrupt routine. */

byte *ptrSequence;      /* A pointer to the desired sequence. */
word sequenceLength;    /* The length of the desired sequence. */
byte pattern;           /* The current output pattern. */
word sequence;          /* The current sequence. */
float speed;            /* The selected speed. */
int speed_clks;         /* speed in clocks (1/60th sec). */
word clocks;            /* Incremented everytime the 1/60th sec interrupt is called. */
int i;

void HB() {
    clocks++;   
    if((clocks % speed_clks) == 0) {
        i++;
        if(i >= sequenceLength) {
            i = 0;
        }
        led1 = !led1;
        pattern = ptrSequence[i];
        lights = pattern;
    }
}

int main() {
 
    /* Basic initialization. */
    led1 = 1;
    clocks = 0;
    speed_clks = 100;
    i = 0;
    /* Simulate the 1/60th sec interrupt from the zero crossing detector. */
    heartbeat.attach(&HB, 0.0083333);
    
    /* Loop through the sequence forever. */
    while(1) {
        
        /* Obtain the inputs. */
        /* Read the dipswitch */
        //sequence = dipswitch; 
        sequence = 0;
        /* Read the potentiometer. */
        speed = potentiometer;
       
        /* Use the inputs to determine internal values. */
        /* Set the sequence number and length. */
        __disable_irq();    // Disable Interrupts
     /* This line doesn't work. */   
        //ptrSequence = (byte *) ptrSequences[sequence];
     /* This line does. */
        ptrSequence = (byte *) sequence0;
        sequenceLength = sequenceLengths[sequence];
        /* Changes the analog speed voltage to a time in clocks. */
        speed_clks = SLOPE * speed + FASTEST_TIME;
        __enable_irq();     // Enable Interrupts
        //pc.printf("sequence: %i, Length: %i\r\n", sequence, sequenceLength);

        
//        pc.printf("clocks: %i, speed_clks: %i\r\n", clocks, speed_clks);
//        pc.printf("i: %i, pattern = %d\r\n", i, pattern);
  
        wait(0.4);
    } 
}

types.h

typedef unsigned char       byte;
typedef unsigned int        word;
typedef unsigned long       dword;
typedef int                 sword;
typedef long                sdword;

#define TRUE            1
#define FALSE           0

sequences.h

const byte sequence0[] = {
    B10000000,
    B01000000,
    B00100000,
    B00010000,
    B00001000,
    B00000100,
    B00000010,
    B00000001
};

const byte sequence1[] = {
    B10000001,
    B10000001,
    B11000001,
    B10100001,
    B10010001,
    B10001001,
    B10000101,
...

bits.h

#define B00000000 0x00
#define B00000001 0x01
#define B00000010 0x02
#define B00000011 0x03
#define B00000100 0x04
...

4 Answers

10 years, 6 months ago.

Hello Kevin Callan,

the next time please highlight code which works and not, I almost overlooked it in your pasted code

     /* This line doesn't work. */   
  1.      //ptrSequence = (byte *) ptrSequences[sequence];
     /* This line does. */
  2.      ptrSequence = (byte *) sequence0;

What does 1. do? Cast a value which is designated by the address ptrSequences[sequence] to a pointer to byte. This pointer will point to the address which is equal to the value stored at the address (ptrSequences + sequence). An example

ptrSequences[sequence] = 10;
ptrSequence = (byte *) ptrSequences[sequence]; /* ptrSequence points to the 10 */

What does 2. do? Stores an address of the sequence0 beginning (&sequcence[0])

I believe if you want to point to an address of an item inside an array, use this syntax &ptrSequences[index]

Regards,
0xc0170

No, in the example ptrSequence is a pointer to the byte at address 10. The pointer has the value 10, it does not point to the value 10.

posted by Ad van der Weiden 08 Oct 2013

Correct. I haven't written it points to the value but in the code example to the 10 (I mean the address, which is also in the sentence above it). I'll be more precise the next time ;)

posted by Martin Kojtal 08 Oct 2013
10 years, 6 months ago.

What you apparently like to have is an array of sequences. When all sequences have the same length you can use a two-dimensional array. When not you can use an array of pointers to sequences (arrays of bytes). for instance:

byte seq1[] = {1,2,3};
byte seq2[] = {1,2,3,4};
byte seq3[] = {1,2,3,4,5};
int sizes[] = {sizeof(seq1), sizeof(seq2), sizeof(seq3)};
byte* seqs[] = {seq1, seq2, seq3}; //make sure that seqs and sizes have the same number of elements

for (int s = 0; s < sizeof(seqs)/sizeof(byte*); s++)
{ if (s < sizeof(sizes)/sizeof(int)) //paranoid precaution in case sizes has less elements than seqs
  for (int i = 0; i < sizes[s]; i++)
  { byte val = seqs[s][i];
  }
}

Don't try to be clever and circumvent the use of the sizes array

byte seq1[] = {1,2,3};
byte seq2[] = {1,2,3,4};
byte seq3[] = {1,2,3,4,5};
byte* seqs[] = {seq1, seq2, seq3};

for (int s = 0; s < sizeof(seqs)/sizeof(byte*); s++)
{ int size = sizeof(seqs[s]); //will give the size of a byte* (4)
  int size = sizeof(*seqs[s]); //will give the size of a byte (1)
  for (int i = 0; i < size; i++)
  { byte val = seqs[s][i];
  }
}

10 years, 6 months ago.

I think Kevin is trying to say that the code lines 1 and 2 are supposed to do the same thing. Line 1 doesn't work, line 2 does. I don't see why line 1 shouldn't work.

     /* This line doesn't work. */   
  1.      //ptrSequence = (byte *) ptrSequences[sequence];
     /* This line does. */
  2.      ptrSequence = (byte *) sequence0;

10 years, 6 months ago.

Thank you all for your help. I still don't have it working. I'm afraid that I'll have to do something ugly for now just to get it working. Like this:

ugly code

switch(dipswitch) {
    case 0: {
        ptrSequence = (byte *) sequence0;
        break;
    }
    case 1: {
        ptrSequence = (byte *) sequence1;
        break;
    }
    case 2: {
        ptrSequence = (byte *) sequence2;
        break;
    }
...