COCKOS
CONFEDERATED FORUMS
Cockos : REAPER : NINJAM : Forums
Forum Home : Register : FAQ : Members List : Search :
Old 01-13-2024, 04:48 PM   #1
Kite
Human being with feelings
 
Join Date: Apr 2010
Location: Portland OR
Posts: 217
Default 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.)
__________________
alt-tuner: a microtonal midi plug-in: www.TallKite.com/alt-tuner.html
The Kite Guitar, a playable 41-ET guitar: www.KiteGuitar.com
Kite is offline   Reply With Quote
Old 01-13-2024, 07:37 PM   #2
jacksoonbrowne
Human being with feelings
 
jacksoonbrowne's Avatar
 
Join Date: Aug 2017
Location: Ottawa, Canada
Posts: 563
Default

Code:
char * myArray = (char *)originalArray + 128; // an array of chars, not null-terminated
__________________
AKA: Roy Wallingford
jacksoonbrowne is offline   Reply With Quote
Old 01-14-2024, 12:22 AM   #3
Kite
Human being with feelings
 
Join Date: Apr 2010
Location: Portland OR
Posts: 217
Default

Thanks, will test this out soon!
__________________
alt-tuner: a microtonal midi plug-in: www.TallKite.com/alt-tuner.html
The Kite Guitar, a playable 41-ET guitar: www.KiteGuitar.com
Kite is offline   Reply With Quote
Old 01-18-2024, 04:23 AM   #4
Kite
Human being with feelings
 
Join Date: Apr 2010
Location: Portland OR
Posts: 217
Default

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]
}
__________________
alt-tuner: a microtonal midi plug-in: www.TallKite.com/alt-tuner.html
The Kite Guitar, a playable 41-ET guitar: www.KiteGuitar.com

Last edited by Kite; 01-18-2024 at 05:21 AM.
Kite is offline   Reply With Quote
Old 01-18-2024, 05:45 PM   #5
Kite
Human being with feelings
 
Join Date: Apr 2010
Location: Portland OR
Posts: 217
Default

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?
__________________
alt-tuner: a microtonal midi plug-in: www.TallKite.com/alt-tuner.html
The Kite Guitar, a playable 41-ET guitar: www.KiteGuitar.com
Kite is offline   Reply With Quote
Old 01-18-2024, 06:21 PM   #6
jacksoonbrowne
Human being with feelings
 
jacksoonbrowne's Avatar
 
Join Date: Aug 2017
Location: Ottawa, Canada
Posts: 563
Default

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
jacksoonbrowne is offline   Reply With Quote
Old 01-18-2024, 07:01 PM   #7
jacksoonbrowne
Human being with feelings
 
jacksoonbrowne's Avatar
 
Join Date: Aug 2017
Location: Ottawa, Canada
Posts: 563
Default

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.
jacksoonbrowne is offline   Reply With Quote
Old 01-18-2024, 07:25 PM   #8
jacksoonbrowne
Human being with feelings
 
jacksoonbrowne's Avatar
 
Join Date: Aug 2017
Location: Ottawa, Canada
Posts: 563
Default

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
jacksoonbrowne is offline   Reply With Quote
Old 01-18-2024, 08:34 PM   #9
Kite
Human being with feelings
 
Join Date: Apr 2010
Location: Portland OR
Posts: 217
Default

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?
__________________
alt-tuner: a microtonal midi plug-in: www.TallKite.com/alt-tuner.html
The Kite Guitar, a playable 41-ET guitar: www.KiteGuitar.com
Kite is offline   Reply With Quote
Old 01-18-2024, 09:05 PM   #10
jacksoonbrowne
Human being with feelings
 
jacksoonbrowne's Avatar
 
Join Date: Aug 2017
Location: Ottawa, Canada
Posts: 563
Default

Quote:
Originally Posted by Kite View Post
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
jacksoonbrowne is offline   Reply With Quote
Old 01-18-2024, 09:40 PM   #11
jacksoonbrowne
Human being with feelings
 
jacksoonbrowne's Avatar
 
Join Date: Aug 2017
Location: Ottawa, Canada
Posts: 563
Default

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
jacksoonbrowne is offline   Reply With Quote
Old 01-19-2024, 05:03 PM   #12
Kite
Human being with feelings
 
Join Date: Apr 2010
Location: Portland OR
Posts: 217
Default

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]
}
__________________
alt-tuner: a microtonal midi plug-in: www.TallKite.com/alt-tuner.html
The Kite Guitar, a playable 41-ET guitar: www.KiteGuitar.com
Kite is offline   Reply With Quote
Old 01-21-2024, 03:15 AM   #13
Tale
Human being with feelings
 
Tale's Avatar
 
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,645
Default

Quote:
Originally Posted by Kite View Post
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.
Tale is offline   Reply With Quote
Old 01-21-2024, 10:40 PM   #14
Kite
Human being with feelings
 
Join Date: Apr 2010
Location: Portland OR
Posts: 217
Default

The code runs on an arduino.
__________________
alt-tuner: a microtonal midi plug-in: www.TallKite.com/alt-tuner.html
The Kite Guitar, a playable 41-ET guitar: www.KiteGuitar.com
Kite is offline   Reply With Quote
Old 01-22-2024, 12:28 AM   #15
Tale
Human being with feelings
 
Tale's Avatar
 
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,645
Default

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 = &note[3]; // Same address as byteArray[12] or [24]

if (myNote->pitch > 60) {
  myNote->duration = 800;
}
Tale is offline   Reply With Quote
Old 01-22-2024, 03:15 AM   #16
jacksoonbrowne
Human being with feelings
 
jacksoonbrowne's Avatar
 
Join Date: Aug 2017
Location: Ottawa, Canada
Posts: 563
Default

Quote:
Originally Posted by Kite View Post
The code runs on an arduino.
I am very familiar with Arduino

Which board are you using?
Uno, Mega, ESP32 ... etc?
__________________
AKA: Roy Wallingford
jacksoonbrowne is offline   Reply With Quote
Old 01-22-2024, 04:53 PM   #17
Kite
Human being with feelings
 
Join Date: Apr 2010
Location: Portland OR
Posts: 217
Default

Arduino Due ARM chip.
__________________
alt-tuner: a microtonal midi plug-in: www.TallKite.com/alt-tuner.html
The Kite Guitar, a playable 41-ET guitar: www.KiteGuitar.com
Kite is offline   Reply With Quote
Old 01-22-2024, 10:29 PM   #18
jacksoonbrowne
Human being with feelings
 
jacksoonbrowne's Avatar
 
Join Date: Aug 2017
Location: Ottawa, Canada
Posts: 563
Default

Quote:
Originally Posted by Kite View Post
Arduino Due ARM chip.
"int" on DUE is 32 bit.

@Tale provided a viable option
__________________
AKA: Roy Wallingford
jacksoonbrowne is offline   Reply With Quote
Old 01-23-2024, 07:00 AM   #19
Kite
Human being with feelings
 
Join Date: Apr 2010
Location: Portland OR
Posts: 217
Default

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?
__________________
alt-tuner: a microtonal midi plug-in: www.TallKite.com/alt-tuner.html
The Kite Guitar, a playable 41-ET guitar: www.KiteGuitar.com
Kite is offline   Reply With Quote
Old 01-23-2024, 08:54 AM   #20
cfillion
Human being with feelings
 
cfillion's Avatar
 
Join Date: May 2015
Location: Québec, Canada
Posts: 4,937
Default

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.
cfillion is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -7. The time now is 03:42 AM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.