Pages: [1]   Go Down
Author Topic: Array of strings  (Read 605 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 83
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi all,

I'm building a serial communication library. Long story short, I want to declare a variable length array of variable length strings (uniform across the array of pointers, but variable). Here's what I've got:
Code:
void UComms::init_arg_store(char** arg_store, int max_message_size, int max_param_size) {
  arg_store = (char**) malloc(max_message_size * sizeof(char*));
  
  for(int i=0; i<max_message_size; i++) { // edited from max_param_size
    arg_store[i] = (char*) malloc((max_param_size+1) * sizeof(char*));
  }
}

A computer engineer friend of mine said that using malloc on the Arduino is not preferable if it can be avoided, but I'm not sure how to get around it here.

Furthermore, this code is not working. Does anybody have hints? Thanks.
« Last Edit: June 06, 2011, 04:36:17 pm by johnmchilton » Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 302
Posts: 26332
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Does anybody have hints?
Tell us what it is about the code that you think "is not working".
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 83
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

When I use the function body in my setup() function, it works just fine. When I refactor it into a function like this, my program ceases to work.

Normally, it will use the multi-level array in the loop() function by populating it with parsed packetized data from the serial port. But when I use the initialization function instead of putting the code in setup(), the array is populated with an optional seemingly random character followed by a number of backticks (`).

I'm happy to use malloc, really, but I do want the abstraction of this function. I just don't know why it doesn't work this way.
« Last Edit: June 06, 2011, 04:35:48 pm by johnmchilton » Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 485
Posts: 18807
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Here's what I've got:
Code:
void UComms::init_arg_store(char** arg_store, int max_message_size, int max_param_size) {
  arg_store = (char**) malloc(max_message_size * sizeof(char*));
  
  for(int i=0; i<max_message_size; i++) { // edited from max_param_size
    arg_store[i] = (char*) malloc((max_param_size+1) * sizeof(char*));
  }
}
Furthermore, this code is not working. Does anybody have hints? Thanks.

Somehow this looks wrong. Certainly it's confusing. You have a pointer to a pointer of type char which you are then treating as an array?

Arguments to functions are passed by value, so I am not expecting that anything this function does will change anything outside the function (except use some of your memory).
Logged


0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 83
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The C++ compiler should treat an array access on to a pointer "properly".

That is, if you have a char** myarray, then
Code:
myarray[i]
should equal
Code:
*(myarray + i)
which will evaluate to the value in memory at myarray + i*sizeof(char).

As for the rest, you're right, I should have known that functions pass by value. So I switched it to:
Code:
void UComms::init_arg_store(char*** arg_store, int max_message_size, int max_param_size) {
  *arg_store = (char**) malloc(max_message_size * sizeof(char*));
  
  for(int i=0; i<max_message_size; i++) {
    (*arg_store)[i] = (char*) malloc((max_param_size+1) * sizeof(char*));
  }
}

Called by:
Code:
computer_connection.init(&COMPUTER, COMPUTER_BAUDRATE);
computer_connection.init_arg_store(&arg_store, MAX_MESSAGE_SIZE, MAX_PARAM_SIZE);
And now it works!  smiley Thank you both
« Last Edit: June 06, 2011, 05:20:02 pm by johnmchilton » Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 485
Posts: 18807
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Code:
char*** arg_store

Three asterisks, huh? You don't see that very often.

You could have passed it by reference:

Code:
void UComms::init_arg_store(char** & arg_store, int max_message_size, int max_param_size) {
  arg_store = (char**) malloc(max_message_size * sizeof(char*));
 
  for(int i=0; i<max_message_size; i++) { // edited from max_param_size
    arg_store[i] = (char*) malloc((max_param_size+1) * sizeof(char*));
  }
}

I hope those numbers are small, after all you only have 2048 bytes of RAM, so allocating:

Code:
(max_message_size * 2) + (max_message_size * max_param_size)

... is going to gobble it up pretty fast.

I don't have a problem with dynamic memory allocation per se, but just remember you don't have a lot of it. And fragmentation could be an issue.
Logged


0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 83
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Those numbers are indeed very small. They are each 10 at the moment, which is already exorbitantly large for the messages defined in my protocol so far. I don't imagine they need to be more than 4 and 6, respectively.

Yes I could pass by reference, but I didn't know that trick smiley-wink thank you. I learned C from a very hardware-oriented textbook, so I didn't get all the language candy that I would have with K&R (though that's on my bookshelf...).

And finally, I am using an Arduino Mega smiley so I am playing fast and loose with my 8KB of memory. I thought about using a sequential array instead of a multi-level array, but I can almost envision the machine code that the compiler generates, and I think that it will put all these blocks close to each other anyway.

Thanks for the pass-by-reference tip!
Logged

0
Offline Offline
Sr. Member
****
Karma: 0
Posts: 360
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

In C/C++, multidimensional arrays are sequential arrays:

int arr[2][2] = {{1,2},{3,4}} is stored as {1,2,3,4}.
Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 83
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

That is true, if you use that syntax. But I decided that I didn't care for a multidimensional array. I wanted a multi-level array, which is different. It is an array of pointers to arrays, which are not necessarily contiguous in memory. Although in this case they probably are because the malloc calls are done one after the other, that is generally not the case, and need not be with a multi-level array.
Logged

Pages: [1]   Go Up
Jump to: