JimG:
...
Why aren't these equivalent?
Serial.print( pgm_read_float( &coeff2[0][0] + i ) );// Index from the address of the first array element
Serial.print( pgm_read_float( coeff2 + i ) );// Index from the address of the first array element
Both should evaluate to an address that is offset by i elements from coeff2[0][0]. Wouldn't they be equivalent for a non-PROGMEM array?
...
No, they would not. See Footnote
Here's the thing: In C and C++ (and, therefore, in Arduino) there is actually no such thing as a 2-D array. Well, from a notational point of view there is, but it's actually treated by the compiler as an array of arrays. This is a Big Deal for cases like this.
I'll try again:
So, coeff2[3][10] is an array of three arrays of floats. Each of the three is an array of ten floats.
Used as an identifier in an expression, coeff2 is a pointer to an array of ten floats. The value of coeff2 is the address of coeff2[0], which is the same numerically as the address of coeff2[0][0].
The value of coeff2 + 1 is greater than the value of coeff2 by the size of an array of ten floats (40 bytes). That's the whole idea behind pointer arithmetic and that's why, in general, that array indexing and pointer arithmetic can be equivalent.
In "normal" programs, the programmer doesn't care about the actual values of pointers and just uses array notation or pointer arithmetic to access whatever the pointers are pointing to, but when trying to nail home a point like this, maybe it would be helpful to print out some of them:
#include <avr/pgmspace.h>
#include <WProgram.h>
PROGMEM float coeff2[3][10] = {
{ 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9 },
{ 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9 },
{ 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9 }
};
void setup()
{
Serial.begin(9600); // Or whatever...
// Make sure the size of a pointer is the same as the size of an unsigned int
// so that we can see the decimal values of the pointers:
Serial.print("sizeof(float *) = ");Serial.print(sizeof(float *));
Serial.print(" and sizeof(unsigned) = ");Serial.println(sizeof(unsigned));
if (sizeof(float *) != sizeof(unsigned)) {
Serial.println("Hmmm---I really thought they were the same size in avr-gcc.");
while (1)
;
}
Serial.println();
Serial.print("&coeff2[0][0] = ");Serial.println((unsigned)&coeff2[0][0]);
for (int i = 0; i < 3; i++) {
Serial.print("&coeff2[");Serial.print(i);
Serial.print("] = ");Serial.println((unsigned)&coeff2[i]);
}
Serial.println();
Serial.print("coeff2 = ");Serial.println((unsigned)coeff2);
for (int i = 0; i < 3; i++) {
Serial.print("coeff2 + ");Serial.print(i);
Serial.print(" = ");Serial.println((unsigned)(coeff2+i));
}
Serial.println();
for (int i = 0; i < 3; i++) {
Serial.print("&coeff2[");Serial.print(i);
Serial.print("][0] = "); Serial.println((unsigned)(&coeff2[i][0]));
}
Serial.println();
for (int i = 0; i < 3; i++) {
float *fp1 = &coeff2[0][0] + i; // coeff2[0][0] is a float
float *fp2 = (float *)(coeff2 + i); // coeff2 is a pointer to an array of ten floats
Serial.print("i = ");Serial.print(i);
Serial.print(": fp1 = ");Serial.print((unsigned)(fp1));
Serial.print(", fpp2 = ");Serial.println((unsigned)fp2);
Serial.print("*fp1 = ");Serial.print(pgm_read_float(fp1));
Serial.print(", *fp2 = ");Serial.println(pgm_read_float(fp2));
Serial.println();
}
}
void loop(){}
Output:
sizeof(float *) = 2 and sizeof(unsigned) = 2
&coeff2[0][0] = 104
&coeff2[0] = 104
&coeff2[1] = 144
&coeff2[2] = 184
coeff2 = 104
coeff2 + 0 = 104
coeff2 + 1 = 144
coeff2 + 2 = 184
&coeff2[0][0] = 104
&coeff2[1][0] = 144
&coeff2[2][0] = 184
i = 0: fp1 = 104, fpp2 = 104
*fp1 = 0.00, *fp2 = 0.00
i = 1: fp1 = 108, fpp2 = 144
*fp1 = 0.10, *fp2 = 1.00
i = 2: fp1 = 112, fpp2 = 184
*fp1 = 0.20, *fp2 = 2.00
Regards,
Dave
Footnote:
Arrays not in program memory:
'
float coeff2[3][10] = {
{ 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9 },
{ 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9 },
{ 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9 }
};
void setup()
{
Serial.begin(9600); // Or whatever...
// Make sure the size of a pointer is the same as the size of an unsigned int
// so that we can see the decimal values of the pointers:
Serial.print("sizeof(float *) = ");Serial.print(sizeof(float *));
Serial.print(" and sizeof(unsigned) = ");Serial.println(sizeof(unsigned));
if (sizeof(float *) != sizeof(unsigned)) {
Serial.println("Hmmm---I really thought they were the same size in avr-gcc.");
while (1)
;
}
Serial.println();
Serial.print("&coeff2[0][0] = ");Serial.println((unsigned)&coeff2[0][0]);
for (int i = 0; i < 3; i++) {
Serial.print("&coeff2[");Serial.print(i);
Serial.print("] = ");Serial.println((unsigned)&coeff2[i]);
}
Serial.println();
Serial.print("coeff2 = ");Serial.println((unsigned)coeff2);
for (int i = 0; i < 3; i++) {
Serial.print("coeff2 + ");Serial.print(i);
Serial.print(" = ");Serial.println((unsigned)(coeff2+i));
}
Serial.println();
for (int i = 0; i < 3; i++) {
Serial.print("&coeff2[");Serial.print(i);
Serial.print("][0] = "); Serial.println((unsigned)(&coeff2[i][0]));
}
Serial.println();
for (int i = 0; i < 3; i++) {
float *fp1 = &coeff2[0][0] + i; // coeff2[0][0] is a float
float *fp2 = (float *)(coeff2 + i); // coeff2 is a pointer to an array of ten floats
Serial.print("i = ");Serial.print(i);
Serial.print(": fp1 = ");Serial.print((unsigned)fp1);
Serial.print(", fpp2 = ");Serial.println((unsigned)fp2);
Serial.print("*fp1 = ");Serial.print(*fp1);
Serial.print(", *fp2 = ");Serial.println(*fp2);
Serial.println();
}
}
void loop(){}
Output:
sizeof(float *) = 2 and sizeof(unsigned) = 2
&coeff2[0][0] = 407
&coeff2[0] = 407
&coeff2[1] = 447
&coeff2[2] = 487
coeff2 = 407
coeff2 + 0 = 407
coeff2 + 1 = 447
coeff2 + 2 = 487
&coeff2[0][0] = 407
&coeff2[1][0] = 447
&coeff2[2][0] = 487
i = 0: fp1 = 407, fpp2 = 407
*fp1 = 0.00, *fp2 = 0.00
i = 1: fp1 = 411, fpp2 = 447
*fp1 = 0.10, *fp2 = 1.00
i = 2: fp1 = 415, fpp2 = 487
*fp1 = 0.20, *fp2 = 2.00