strtod() to extract multiple values from string

Hi,

Via a peripheral device I receive a string consisting of 8 temperatures. The string has a leading character (">"), and all temperatures are parsed as 5-digit, 2-decimal float with a leading sign, so something like this:
>+0023.3+0029.3+0650.3+0029.3+0029.3+0029.3+0029.3+0029.3

I'm trying read all values from the string into a double array, see code below. The output I'm getting though is that for each iteration, it prints the first value of temp 47 times (equal to the amount of characters left in ptr). If I print the ptr-string, I can see the first value was taken off correctly before the while-loop, but it doesn't update from there on.
The first double is read correctly when I print it, so it is able to read the doubles from the string.
Using strtok() is not an option since the sign can change (+ or -).

I'm sure it's a simple mistake, but I don't see it. Any ideas why this fails?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
char data[65] = ">+0023.3+0029.3+0650.3+0029.3+0029.3+0029.3+0029.3+0029.3";	// example input string
char * numData = data + 1;	// remove the first character
char * ptr;							// pointer
double temp;
double temperatures[8];			// array of 8 doubles
int n = 0;							// increment counter

temp = strtod(numData, &ptr);
temperatures[n] = temp;

while (ptr != NULL) {
	temp = strtod(numData, &ptr);
	n++;
	temperatures[n] = temp;

	Serial.println(temp); // Arduino command to print output to serial
}
temp = strtod(numData, &ptr);

numData never changes, so you're always reading from the same start position.
See, I knew it was a stupid mistake. Indeed, that solved it, though I didn't spot that in any of the examples. Thanks!

I also altered the code to prevent overflow of the output double array, since I cannot read more values than allocated. The output of my peripheral device is fixed to 8 values anyway, but better safe than sorry.

This works fine now :)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
char data[65] = ">+0023.3+0029.3+0650.3+0029.3+0029.3+0029.3+0029.3+0029.3";	// example input string
double temperatures[8];
char * numData = data + 1;
char * ptr = numData;
double temp;

for (int n = 0; n < NTemperatures; n++) {
	temp = strtod(numData, &ptr);
	numData = ptr;

	if (ptr) {
		temperatures[n] = temp;
	}
}
You can test for success of strtod() by comparing the pointer ptr with the input value. If no conversion was done, the pointers will both point to the same position.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <iostream>

using namespace std;

int convert(char * data, double * temperatures, int size)
{  
    char * numData = data + 1;
    char * ptr     = numData;
    
    int count = 0;
    
    for (int n = 0; n < size; n++)
    {
        double temp = strtod(numData, &ptr);
        
        if (ptr != numData)
        {
            count++;
            temperatures[n] = temp;
            numData = ptr;
        }
        else
            break;
    }
    
    return count;   
}


int main()
{
    // example input string
    char data[] = ">+0023.3+0029.3+0650.3+0029.3+002z9.3+0029.3+0029.3+0029.3";
    //..............................................^ non-numeric deliberately inserted

    const int size = 8;
    double temperatures[size] = { 0.0 };
    
    int count = convert(data, temperatures, size);
    
    for (int i=0; i<count; ++i)
    {
        cout << temperatures[i] << '\n';
    }

}

That's a good call, Chervil. That way I can prevent the code from getting stuck in an infinite loop like before. I'll add that check too!
Topic archived. No new replies allowed.