|
01-13-2024, 04:48 PM
|
#1
|
Human being with feelings
Join Date: Apr 2010
Location: Portland OR
Posts: 217
|
C++ question - overlapping arrays?
I need to do something rather unorthodox in C++. Can't find the answer anywhere online.
I need to define an array that overlaps another array, so both arrays read from and write to the same memory locations. Related, I also need to define an array of chars that overlaps an array of strings.
Something like this:
Code:
byte originalArray[256];
byte myArray = originalArray + 128; // an array of bytes, it starts halfway in
if (myArray[0] == myArray[1]) { // read from originalArray[128] and [129]
myArray[2] = 3; // write to originalArray[130]
}
Do I need to define the length of myArray? If so, how?
2nd example, for strings:
Code:
char originalArray [10][32]; // 10 null-terminated strings, length <= 31
char myArray = originalArray + 128; // an array of chars, not null-terminated
if (myArray[0] == ' ') { // read/write 1st char of 5th string
myArray[0] = '!';
}
I know this is not good programming practice. But I absolutely positively have to do it this way! (Long story.)
|
|
|
01-13-2024, 07:37 PM
|
#2
|
Human being with feelings
Join Date: Aug 2017
Location: Ottawa, Canada
Posts: 563
|
Code:
char * myArray = (char *)originalArray + 128; // an array of chars, not null-terminated
__________________
AKA: Roy Wallingford
|
|
|
01-14-2024, 12:22 AM
|
#3
|
Human being with feelings
Join Date: Apr 2010
Location: Portland OR
Posts: 217
|
Thanks, will test this out soon!
|
|
|
01-18-2024, 04:23 AM
|
#4
|
Human being with feelings
Join Date: Apr 2010
Location: Portland OR
Posts: 217
|
Works great!
Next question, what if I want to access myArray[i][j]? Something like this:
Code:
byte originalArray[200];
byte * myArray[0] = (byte *)originalArray + 100;
byte * myArray[1] = (byte *)originalArray + 108;
if (myArray[0][2] == myArray[1][2]) { // read from originalArray[102] and [110]
myArray[0][3] = 4; // write to originalArray[103]
}
or maybe this:
Code:
byte originalArray[2][200];
byte * myArray[0] = (byte *)originalArray + 100;
if (myArray[0][2] == myArray[1][2]) { // read from originalArray[0][102] and [1][102]
myArray[0][3] = 4; // write to originalArray[0][103]
}
Last edited by Kite; 01-18-2024 at 05:21 AM.
|
|
|
01-18-2024, 05:45 PM
|
#5
|
Human being with feelings
Join Date: Apr 2010
Location: Portland OR
Posts: 217
|
Also, is it possible for a data structure to overlap an array of bytes?
Code:
byte originalArray[200];
struct note {
byte pitch; // midi note number
byte duration; // measured in 16th notes
};
note * Notes[61] = (byte *)originalArray;
n = 10;
if (Notes[n].pitch > 60) { // read from originalArray[20]
Notes[n].duration = 8; // write to originalArray[21]
}
And is it possible to mix data types?
Code:
byte originalArray[200];
signed char * myArray1 = (byte *)originalArray;
boolean * myArray2 = (byte *)originalArray + 20;
int * myArray3 = (byte *)originalArray + 60;
In my use case, I would never ever read from or write to originalArray directly. I would only read/write myArray. So I wouldn't be attempting to interpret a byte as a boolean, or four bytes as an int.
And finally, what about just accessing one element of originalArray as a simple variable, via an alias? Something like:
Code:
byte originalArray[200];
byte * myVar1 = originalArray + 10;
byte * myVar2 = originalArray + 11;
if (myVar1 == 0) { // read from originalArray [10]
myVar2 = 3; // write to originalArray [11]
}
Perhaps there is some general method of making a variable or an array or a data structure (or an array of structures, a structure of arrays, etc. etc.) overlap an array of bytes?
|
|
|
01-18-2024, 06:21 PM
|
#6
|
Human being with feelings
Join Date: Aug 2017
Location: Ottawa, Canada
Posts: 563
|
Quote:
And is it possible to mix data types?
Code:
byte originalArray[200];
signed char * myArray1 = (byte *)originalArray;
boolean * myArray2 = (byte *)originalArray + 20;
int * myArray3 = (byte *)originalArray + 60;
|
Yes but you need to properly cast like this example.
Rule is that the right side (cast) must match the left side type.
Code:
char originalArray[200];
signed char * myArray1 = (signed char *) originalArray;
bool * myArray2 = (bool *) originalArray + 20;
int * myArray3 = (int *) originalArray + 60;
unsigned char * myArray4 = (unsigned char *) originalArray + 80;
__________________
AKA: Roy Wallingford
|
|
|
01-18-2024, 07:01 PM
|
#7
|
Human being with feelings
Join Date: Aug 2017
Location: Ottawa, Canada
Posts: 563
|
Quote:
Code:
byte originalArray[2][200];
byte * myArray[0] = (byte *)originalArray + 100;
if (myArray[0][2] == myArray[1][2]) { // read from originalArray[0][102] and [1][102]
myArray[0][3] = 4; // write to originalArray[0][103]
}
|
That won't work. It won't even compile without error.
__________________
AKA: Roy Wallingford
Last edited by jacksoonbrowne; 01-18-2024 at 07:43 PM.
|
|
|
01-18-2024, 07:25 PM
|
#8
|
Human being with feelings
Join Date: Aug 2017
Location: Ottawa, Canada
Posts: 563
|
I am not sure how familiar you are with c++.
Pointers to objects are only easy to use once you have a good grasp of C++ pointers, casting them, and then using them to access data.
Perhaps it would be better to pose 1 question at a time.
That would make it easier for me to provide a working example and an explanation of it.
I am here to help you as needed,
Cheers,
Roy
__________________
AKA: Roy Wallingford
|
|
|
01-18-2024, 08:34 PM
|
#9
|
Human being with feelings
Join Date: Apr 2010
Location: Portland OR
Posts: 217
|
Thanks again for your help, Roy! I'm not very familiar with C++, but I am very familiar with jesusonic. I find I can mostly teach myself C++ from online tutorials. That doesn't work when I'm doing something this unorthodox, of course.
So, as you say, one question at a time. Can I set up a 2D array that overlaps a 1D array? Obviously this code wouldn't work:
Code:
byte originalArray[200];
byte * myArray = (byte *)originalArray + 100;
if (myArray[0][2] == myArray[1][2]) { // read from originalArray[102] and [110]
myArray[0][3] = 4; // write to originalArray[103]
}
Because the compiler doesn't know how long the rows of myArray are. Supposing I want rows of 8 bytes, how would I declare myArray?
|
|
|
01-18-2024, 09:05 PM
|
#10
|
Human being with feelings
Join Date: Aug 2017
Location: Ottawa, Canada
Posts: 563
|
Quote:
Originally Posted by Kite
Thanks again for your help, Roy! I'm not very familiar with C++, but I am very familiar with jesusonic. I find I can mostly teach myself C++ from online tutorials. That doesn't work when I'm doing something this unorthodox, of course.
So, as you say, one question at a time. Can I set up a 2D array that overlaps a 1D array? Obviously this code wouldn't work:
Code:
byte originalArray[200];
byte * myArray = (byte *)originalArray + 100;
if (myArray[0][2] == myArray[1][2]) { // read from originalArray[102] and [110]
myArray[0][3] = 4; // write to originalArray[103]
}
Because the compiler doesn't know how long the rows of myArray are. Supposing I want rows of 8 bytes, how would I declare myArray?
|
I did this a few years ago in my production code.
Need to refresh my memory and look at my old code.
Standby ...
__________________
AKA: Roy Wallingford
|
|
|
01-18-2024, 09:40 PM
|
#11
|
Human being with feelings
Join Date: Aug 2017
Location: Ottawa, Canada
Posts: 563
|
Ok,
Here's an example of using a 2d array pointing into a 1d array
Code:
byte originalArray[200];
byte (*myArray)[2][100] = (byte(*)[2][100]) (originalArray + 16);
if ((*myArray)[0][2] == (*myArray)[1][2]) { // read from originalArray[102] and [110]
(*myArray)[0][3] = 4; // write to originalArray[103]
}
Beware that if you use indices are outside the boundaries of either the 1d or 2d arrays you will get a memory violation.
For example: if you reference the following (based on the above example) you will get a memory violation:
Code:
byte x = (*myArray)[2][101]
I
__________________
AKA: Roy Wallingford
|
|
|
01-19-2024, 05:03 PM
|
#12
|
Human being with feelings
Join Date: Apr 2010
Location: Portland OR
Posts: 217
|
Great! Next question, how would I make a data structure overlap an array of bytes?
Code:
byte originalArray[400];
struct note {
byte pitch; // midi note number
int duration; // measured in milliseconds
};
note myNote;
(somehow make myNote start on originalArray[10])
if (myNote.pitch > 60) { // read from originalArray[10]
myNote.duration = 800; // write to originalArray[11-44]
}
|
|
|
01-21-2024, 03:15 AM
|
#13
|
Human being with feelings
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,645
|
Quote:
Originally Posted by Kite
Great! Next question, how would I make a data structure overlap an array of bytes?
|
Well, you could do something like:
Code:
byte originalArray[400];
struct note {
byte pitch; // midi note number
int duration; // measured in milliseconds
};
note* myNote = (note*)&originalArray[10];
if (myNote->pitch > 60) { // read from originalArray[10]
myNote->duration = 800; // write to originalArray[14]
}
However, depending on your CPU architecture you might not want to do that, unless you are sure that originalArray is properly aligned. Standard C/C++ rules say that the int type should be 4-byte aligned, and for some architectures (like ARM) this actually is important, but for others (e.g. x86) it doesn't really matter.
|
|
|
01-21-2024, 10:40 PM
|
#14
|
Human being with feelings
Join Date: Apr 2010
Location: Portland OR
Posts: 217
|
The code runs on an arduino.
|
|
|
01-22-2024, 12:28 AM
|
#15
|
Human being with feelings
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,645
|
I don't know what the alignment is on an Arduino. A quick Google search says that the int type could be either 16 or 32-bit (i.e. 2 or 4 bytes), further complicating things. Maybe it would be better to allocate your array as type note, and then cast it to byte when needed i.e.:
Code:
struct note {
byte pitch; // midi note number
int duration; // measured in milliseconds
};
note originalArray[400 / sizeof(note)]; // 100 or 50 elements, depending on sizeof(int)
byte* byteArray = (byte*)&originalArray[0]; // 400 elements
note* myNote = ¬e[3]; // Same address as byteArray[12] or [24]
if (myNote->pitch > 60) {
myNote->duration = 800;
}
|
|
|
01-22-2024, 03:15 AM
|
#16
|
Human being with feelings
Join Date: Aug 2017
Location: Ottawa, Canada
Posts: 563
|
Quote:
Originally Posted by Kite
The code runs on an arduino.
|
I am very familiar with Arduino
Which board are you using?
Uno, Mega, ESP32 ... etc?
__________________
AKA: Roy Wallingford
|
|
|
01-22-2024, 04:53 PM
|
#17
|
Human being with feelings
Join Date: Apr 2010
Location: Portland OR
Posts: 217
|
Arduino Due ARM chip.
|
|
|
01-22-2024, 10:29 PM
|
#18
|
Human being with feelings
Join Date: Aug 2017
Location: Ottawa, Canada
Posts: 563
|
Quote:
Originally Posted by Kite
Arduino Due ARM chip.
|
"int" on DUE is 32 bit.
@Tale provided a viable option
__________________
AKA: Roy Wallingford
|
|
|
01-23-2024, 07:00 AM
|
#19
|
Human being with feelings
Join Date: Apr 2010
Location: Portland OR
Posts: 217
|
Making sure I understand, I think this code will work?
Code:
maxStringLen = 30; // including the null at the end
char originalArray[10][maxStringLen];
struct note {
byte pitch; // midi note number
byte duration; // in 16th notes
signed char tuning; // range is ±50 cents
boolean hasStem[2]; // [0] = up-stem, [1] = down-stem
};
// overlap starting on the 20th char of the 3rd message
note* myNote = (note*) &originalArray + 2*maxStringLen + 20;
if (myNote->pitch > 60) { // read from originalArray[80]
myNote->duration = 8; // write to originalArray[81]
}
BTW, sorry for the newbie question, but what does "->" mean? I can't manage to google it haha. Does myNote->pitch mean the same as myNote.pitch?
|
|
|
01-23-2024, 08:54 AM
|
#20
|
Human being with feelings
Join Date: May 2015
Location: Québec, Canada
Posts: 4,937
|
No, for starters both originalArray[80] and myNote are out of bounds and originalArray[81] is 30 bytes after [80]. originalArray[80] is 2400 bytes after the start of originalArray and myNote is 400 bytes after the start. (note*)&originalArray+n adds n*sizeof(note) bytes.
What do you need this for exactly? What are the real input and expected output? This sounds like a XY problem.
Tale's suggestion of having an array of notes for working with then casting it for viewing is way better. But is seems like you need each note to be null-terminated?
-> is the "member of pointer" operator. myNote->pitch is equivalent to (*myNote).pitch and myNote.pitch is invalid. (It can also be overloaded to implement it on non-pointer objects.)
Last edited by cfillion; 01-23-2024 at 01:33 PM.
|
|
|
Thread Tools |
|
Display Modes |
Linear Mode
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
All times are GMT -7. The time now is 03:42 AM.
|