strncpy() causes reset

I'm trying to take parse the HTTP reply I get from uploading data to pachube.com. I'm using EhterCard.h and it has a function tcpReply() that returns the HTTP response, which is

HTTP/1.1 200 OK
Date: Fri, 13 Apr 2012 12:17:36 GMT
Content-Type: text/plain; charset=utf-8
Connection: close
X-Pachube-Logging-Key: logging.Lo55opRx5dl5UwAw2NUO
X-PachubeRequestId: 2ea1be6efb47aac0a0f47ec04196b14f721f605c
Cache-Control: max-age=0
Content-Length: 1
Age: 0
Vary: Accept-Encoding

According to strlen() it's 308 bytes long. I want to use strtok (using \n as delimiter) to parse each line, but first I'm using strncpy() to prevent a
a invalid conversion from 'const char*' to 'char*'

But my sketch seems to be failing at the strncpy() function and reboots before I even get to strtok(). Below is my code, can anyone tell me what I am doing wrong?

  const char* reply = ether.tcpReply(session);    // part of EtherCard.h library
  if (reply != 0)
  {
    char reply2[strlen(reply)+1];
    strncpy(reply2, reply, sizeof(reply));  // I think Arduino is rebooting here
    reply2[strlen(reply)] = '\0';
   
    char delims[] = "\n";
    char *result = NULL;
    result = strtok( reply2, delims );
    while( result != NULL ) 
    {
        Serial.println(result);
        result = strtok( NULL, delims );
    }
  }

If reply is 308 bytes and reply2 is 309 bytes, that's 617 bytes of RAM for one operation.

Could you be running out of memory?

const char* reply = ether.tcpReply(session);    // part of EtherCard.h library

Umm reply is a pointer to char, yes?

sizeof(reply) will always be 2 on an Arduino!

(It's not blowing up where you think it is. What does ether.tcpReply() return?)

Edit: added conclusion.

Oops, I should have used:

strncpy(reply2, reply, strlen(reply))

I made this change but it still reboots. I don't know about running out of memory. How do I tell? When I compile it says Binary Sketch: 18,082 bytes (of a 30,720 byte maximum)

I don't know about running out of memory. How do I tell? When I compile it says Binary Sketch: 18,082 bytes (of a 30,720 byte maximum)

That only reports program (flash) memory - the amount of SRAM used is not reported.
My guess is that you have lots of strings consuming RAM.
But without seeing code, it really is just a guess.

I want to use strtok (using \n as delimiter) to parse each line, but first I'm using strncpy() to prevent a
a invalid conversion from 'const char*' to 'char*'

The proper cast would prevent the "problem" without the need to copy the string.

PaulS:

I want to use strtok (using \n as delimiter) to parse each line, but first I'm using strncpy() to prevent a
a invalid conversion from 'const char*' to 'char*'

The proper cast would prevent the "problem" without the need to copy the string.

How do I do that?

How do I do that?

Wouldn't that depend on where the "problem" is occurring? You haven't said.

It looks like I'm running out of RAM. I added a FreeMemory routine I found here: Arduino Playground - AvailableMemory

Before I define reply2, I have less then 200 bytes. reply2 would be 308 bytes. I'd like not have to create reply2 and just use reply with strtok(), but reply is a const char and strtok() doesn't like that. So my solution is to strncpy reply to reply2.

I think I'm running out of ram when I define reply2 on line 451.

I would also like to free up some ram, but I'm not sure how to do that. Attached is the entire sketch, except for PachubeAPIKey.h which is just a #DEFINE with my API key (65 characters).

I'm using a Nanode, which is similar to Arduino Deumilanove.

Water_Detector_Nanode_v6.ino (20.9 KB)

I got it working. I shortened a bunch of strings in my Serial.print() statements and that freed up some RAM.

I also figured out how to cast my const char to char:

char* reply = const_cast<char*> (ether.tcpReply(session));

I'm not changing the reply string, so I felt comfortable doing this.

I'll never understand why Microsoft invented a bunch of complex templates for casting, and why anyone uses them.

char *reply = (char *)(ether.tcpReply(session));

No templates; smaller footprint; easier (for me) to understand.

PaulS:
I'll never understand why Microsoft invented a bunch of complex templates for casting, and why anyone uses them.

char *reply = (char *)(ether.tcpReply(session));

No templates; smaller footprint; easier (for me) to understand.

I like your method better.

You should move your Serial.print strings to PROGMEM.

A lazy way is to use the Serial.print(F("ahaqoihio"));
Unless every output string is unique you are duplicating strings in PROGMEM.

liudr:
You should move your Serial.print strings to PROGMEM.

A lazy way is to use the Serial.print(F("ahaqoihio"));
Unless every output string is unique you are duplicating strings in PROGMEM.

I'm going to do that. I learned a lot about strings and RAM in trying to debug this problem.

If you do need a lot of strings even the PROGMEM can't hold, you can still get an EEPROM to store the strings. There's solutions to these problems :slight_smile:

PaulS:
I'll never understand why Microsoft invented a bunch of complex templates for casting, and why anyone uses them.

Just to set the record straight, the different cast types allow you to perform different types of casting as opposed to the C casting operation that strips all attributes from the cast variable. They also allow proper casting of polymorphic objects.

E.g. static_cast<char *>() will convert a (const void *) pointer to (const char *) pointer without stripping the const attribute. There is no way to do this with C casts unless you know that the original variable is const in every case to start with, and explicitly cast as (const char *).

There is no way to do this with C casts unless you know that the original variable is const in every case to start with, and explicitly cast as (const char *).

If you don't know what the original type is, casting is hardly a good idea. The reason for most casts is to allow a function to accept a const array, when you KNOW that the function is not going to change the contents of the array, but the function doesn't explicitly guarantee that by using the const keyword.

In the case that OP is talking about, I can't figure out why ether.tcpReply() returns a const pointer. Why does it care if you want to point it to something else, or alter the contents that it points to?