I have several projects that use the same set of code and I am attempting to build a library so I don't have to duplicate the code that is the same. My problem is, in the code that I have that works, it makes assumptions about the size of arrays that is not the same in all of the applications.
I've had success using this myself in toy projects; but, I haven't run any sort of longevity tests on it, so I can't speak to how nicely the dynamically allocated memory works over time (this approach won't necessarily give one contiguous block of memory the way your approach would).
I can't speak to how nicely the dynamically allocated memory works over time
Shouldn't be an issue if it is only done in setup(). It is best to avoid it in the loop() though. With limited memory, the heap can easily get fragmented beyond usability.
You're probably running into a disagreement with the compiler on whether the array is organized by columns or by rows... Since you'd rather have a two-dimensional array, I'd suggest dispensing with the idea of doing the indexing yourself, and have the compiler do all the work. For instance (this is a unix program; I compiled it and it seems to do the right thing):
Which dimension in the array changes? If it's both, there is no way to make one piece of code work properly for just a 2 dim array since at least one dimension size must be known at compile time. I would do something similar to what wes suggests but create a structure per device that holds a one dimensional array of device samples. Then create an array of structure pointers that point to the individual malloc'd device structures. This way you can have differing sample set sizes, even in the same program. You could even put the sample size in the structure to do your own bounds checking. That way, it's unambiguous (to a human and the compiler) what's going on. I have to admit - >30 years of c/c++ and I still can't remember if C is row or column major.
The samples array size of 1 is a fiction to allow the compiler to know that it's a linear array. No bounds checking is done. so, tdevices->samples[20] would work just fine assuming there is data there.
@adafruit_support - gotcha, I'm still adapting to the limited memory constraint. Thanks for confirming it should be OK in a setup method.
@philba
there is no way to make one piece of code work properly for just a 2 dim array since at least one dimension size must be known at compile time.
I follow you on needing more data than just the array for the code to work properly, but I'm missing the point you're making about needing to know at least one dimension at compile time. As long as the run time code keeps and respects the lengths (in a struct or otherwise), I'm not seeing where having both dimensions dynamic introduces issues in and of itself (design-wise, I like your approach of bundling the lengths within the struct and allowing flexibility in sample set sizes). Randomly sizing a char array:
Say you declare char a[3][4]; That makes for 3 rows of 4 columns (or is it 4 and 3? doesn't matter for this discussion) and allocates a 12 byte block of memory, So, to index a[j], you need to know at least the number of columns to compute 4*i+j. If the compiler doesn't know the number of columns, it can't figure it out. That value must be know at compile time. There's no way to tell compiled C code the column size. You could overlay the array with a linear array and do the math yourself but that's kind of clumsy
Now, since Arduino libraries get recompiled along with the code that uses them, it is possible to arrange to have a define constant for your array sizes but that feels clumsy, too.
What I like about the solution I outlined is that it's only a short step from that to an object oriented solution where you create a class object "Thermo" and attach a set of methods to it. So you can have things like thermo1.scaleFarenheit(), thermo1.filter(), thermo1.addSample(x) or some such. what ever you want to do. Could be some nicely elegant code and makes a library a lot more user friendly.
I'm afraid we may be talking past each other a bit... I agree with you that the solution you outlined is closer to an object oriented approach and is headed in a cleaner direction than the 2D array (especially when talking about building a library). Also, I'm in agreement with you on the compiler needing the column count for a statically allocated array.
Ignoring larger design issues for a minute, my claim is that we can get something that behaves like a dynamically sized 2D array in code (tho in fact it is an array of references to arrays) and which the compiler will handle correctly. From my code sample above:
define char **a
assign a malloc'ed array of char *'s of length m into a
then assign a malloc'ed array of char of length n into each entry in a.
Later on, the compiler will see a[j] as - take the pointer value in a, add i (pointer math, so really i * sizeof(char *)), dereference the value, add j (pointer math, really j * sizeof(char)), and dereference the value. The compiler won't need to know the value of n since the type of a won't be an array of arrays of size n.
Yes, I see what you are doing. And, it appears to work correctly in GCC. I went looking at the specifications (GCC, c99 and the 2008 ISO draft) and couldn't find it explicitly called out. It seems that it's well embedded in the informal definition of C all the way back to the K&R compiler in the early 70s. main(argv, argc), with argv declared as char **, for example. So, it's probably not going to break anytime soon. Personally, I'd opt for a design that is simpler to understand, especially if newbies will be seeing it.