Pages: [1]   Go Down
Author Topic: Manipulating an array of ram strings (how to?)  (Read 588 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 33
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi..

If I define an array of fixed length text items like...

char* temps[] = {" 000.00"," 000.01"," 000.02"," 000.03"," 000.04"," 000.05"," 000.06"," 000.07"," 000.08"," 000.09",};  // ascii string of temperature

I can display one of the entries by...
Serial.print (temps[3]);
which shows  000.03 as I'd expect.

as stuff happens in my program I try and update an entry
ie elsewhere I have a string of the correct length called 'temptemp', this hold different values on each pass of a loop

How do I change the contents one of the items in the 'temps' array to the new value?

If I do temps[3]=temptemp , then temps[1]=temptemp next time round, all the values I try and display always show the same (latest) value.
I suspect I'm just changing the pointers to the latest value but how do I modify the actual data?

I have read stuff about strings and pointers but cant figure out how to apply it to this case  smiley-sad
Any help would be welcome..
Logged

East Anglia (UK)
Offline Offline
Faraday Member
**
Karma: 114
Posts: 4257
May all of your blinks be without delay()
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Please post your whole code or a small example of the problem
Logged

Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 614
Posts: 49343
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

temps[n] points to a fixed length array of characters. As long as the new string is not longer than the old string, you can use strcpy() to copy the new string over the old string.

What you are doing now is changing where temps[n] points to, so that, eventually, all the temps[n] elements point to the same place.
Logged

Offline Offline
Edison Member
*
Karma: 58
Posts: 2078
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You can change the pointer to another variable. That is no problem.
You can even change the original characters themself.
Try these two little sketches.

Code:
// tested example
// Create array of pointers that can point to something else

// ascii strings of temperature
char *temps[] = {
  " 000.00",
  " 000.01",
  " 000.02",
  " 000.03",
  " 000.04",
  " 000.05",
  " 000.06",
  " 000.07",
  " 000.08",
  " 000.09"
};

char stringX[] = " 999.99";

void setup() {
  Serial.begin(9600);
  Serial.println("Hello pointers") ;
}

void loop()
{
  for (char c = 'A'; c<='Z'; c++)
  {
    Serial.print("temps[2] = ");
    Serial.println( temps[2]);
  
    // Change the stringX
    stringX[3] = c;
    
    // Set pointer to stringX
    temps[2] = stringX;
    
    delay(1000);
  }
}

The next example changes the string itself.
Also strcpy could be used, but that is dangerous.
strcpy could overwrite the zero terminator and even the next string.

Code:
// tested example
// Create array of strings, and the strings themself can be changed.

// ascii strings of temperature
// The string is 7 characters, with the zero-terminater makes it 8
char temps[][8] = {
  " 000.00",
  " 000.01",
  " 000.02",
  " 000.03",
  " 000.04",
  " 000.05",
  " 000.06",
  " 000.07",
  " 000.08",
  " 000.09"
};

void setup() {
  Serial.begin(9600);
  Serial.println("Hello strings") ;
}

void loop()
{
  for (char c = 'A'; c<='Z'; c++)
  {
    Serial.print("temps[2] = ");
    Serial.println( temps[2]);
  
    // Change the string itself
    temps[2][3] = c;
    
    delay(1000);
  }
}

The code is not the problem, but I wonder why you declare those strings.
Sadly the sprintf() if not fully implemented for float numbers in the Arduino,
but with dtostrf() you can get that format you want.
Code:
// tested example
// Use dtostrf for the " 000.00" format string.
// For negative numbers, the first character is a '-'.

float temperature;

void setup() {
  Serial.begin(9600);
  Serial.println("Hello dtostrf") ;
}

void loop()
{
  char buffer[10];

  // use random temperature to test.
  temperature = (float) random( -99999L, 99999L) / 100.0;

  // The sprintf is not fully implemented in the Arduino.
  // So the dtostrf is used.
  // Some code is needed to get the format we need.
  if (temperature < 0.0)
    buffer[0] = '-';
  else
    buffer[0] = ' ';
  dtostrf( abs( temperature), 6, 2, buffer + 1);
  for( int i=1; i<=3; i++)
  {
    if( buffer[i] == ' ')
      buffer[i] = '0';
  }
  
  Serial.println( buffer);
  
  delay(1000);
}
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 33
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks everyone for the extremely rapid help!

I tried both the 2-dimentional array and the strcpy() and they both achieve what I need.
I was just confusing myself with & (reference) and * (dereference) of pointers and getting nowhere.
The reason for the strange initialization values was just so I could see if what I was printing for diagnostics was what I thought it was. They are fixed length ascii temperatures that arrive by RS485 for storage and web-page viewing and logging.
I just start them off at zero rather than have nothing in them.
I'll opt for the 2-dimentional array and see how it all goes smiley
Thanks again....
Stewie
Logged

Pittsburgh, PA, USA
Offline Offline
Faraday Member
**
Karma: 98
Posts: 4807
I learn a bit every time I visit the forum.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ahhhhh, I type WAY too slow! There's some repeated info here.

Quote
How do I change the contents one of the items in the 'temps' array to the new value?

LOL! Here are some options. You can use strcpy(), or strncpy() which does not add a terminating zero, or you can change individual chars. You can access using indexes (like
  • or [3]) or using pointers or (I won't show this, it's bad practice) direct memory addressing.

First, you want to fix this:
Code:
char* temps[] = {" 000.00"," 000.01"," 000.02"," 000.03"," 000.04"," 000.05"," 000.06"," 000.07"," 000.08"," 000.09",};  // ascii string of temperature

to this to eliminate waste space. Add the space as a print( " " ) and save memory.
Code:
char* temps[] = {"000.00","000.01","000.02","000.03","000.04","000.05","000.06","000.07","000.08","000.09",};  // ascii string of temperature
That doesn't -have- to be but note that it makes coding easier when they're all the same layout.

That char * array is equivalent to
Code:
const byte tempsLen = 7;
char tempstrs[][tempsLen] = {"000.00","000.01","000.02","000.03","000.04","000.05","000.06","000.07","000.08","000.09",};  // ascii string of temperature

char *tempPtr = tempstrs[0]; // points to the 1st string
*char *tempPtr = tempstrs; // same as above without the [0] index
tempstrs += 3 * tempsLen; // now points to the 4th string without using an index
tempstrs++;
*tempstrs = 3; // so now tempstrs[3] is "030.03"

Just to show the difference between a 1D array of char pointers and a 2D array of chars is only how you access them using indexes. With the latter you can index to any char in the array. With pointers you can point to any char in the array whether there's an index or not.

You could just define a buffer ( char buff[ buffLen ] ) and fill it with strings by offsetting a char * and using strcpy() to write the data as long as you control the length of what you write. You can even lose the terminating zeros if you don't use string commands that require them. Yes, there are a few but doing that is messy and requires either an array to move chars to and add the zero to that to print() or to print 1 char at a time which is s-l-o-w-e-r. But... it can be done and it can save memory if you have _enough_ strings. Ordinarily though it's not good practice.

BTW, using char *temps[] = .... will let you have unequal length char strings. Sure then you can't use a constant offset to advance a pointer from string to string, using the index becomes necessary unless you read every char in turn looking for the NULL (==0) chars all the way, which is messier than indexes. But... you can.

I like using pointers more than IMO messy indexes. Writing to use pointers means your functions don't have to know about indexes or dimensions of indexes. Learn the power of pointers and you will be able to write tighter code that total novices will complain is obfuscated! Funny how they're an integral part of the language, how many functions take and return pointers? We -all- start as noobs but only some -stay- noobs.

This is more than worth learning, it may change your coding-life:
http://pw1.netcom.com/~tjensen/ptr/pointers.htm

Very useful page link for C string array commands:
http://www.nongnu.org/avr-libc/user-manual/group__avr__string.html

I have the page 'above' that one (string.h page) bookmarked for easy access.
http://www.nongnu.org/avr-libc/user-manual/modules.html

Lastly for all your constant strings and values, learn about PROGMEM to keep those in flash and save your RAM for things you change and stack space to run on.


Logged

I find it harder to express logic in English than in Code.
Sometimes an example says more than many times as many words.

Pages: [1]   Go Up
Jump to: