Struct as parameter (again#2)

Hello,

I did quite some googling on this but not able to find out what's going wrong. I followed the guidelines in this post: http://forum.arduino.cc/index.php?topic=44890.0 I have this function that extracts the HTTP-status and -version from a GET-response that I received from a webserver.

This is the actual parse-function (which is in a CPP-file where the rest of the class is also defined):

void xBee::parseHTTPResponse(struct httpresponse* response) {
char* statusLine;
char* cr = "\13";

    // First, extract only the part until the first CRLF
    statusLine = strtok(_respBuffer, cr);

    char* httpVersion;
    httpVersion = strtok(statusLine, " ");          // This is like "HTTP/1.1"
    response->status = atoi(strtok(NULL, " "));     // This should be like 200, 403 or such

    // Parse the version
    strtok(httpVersion, "/");                       // This is "HTTP", ignore
    strcpy(response->version, strtok(NULL, "/"));   // Get the version
}

The struct is defined in a H-file with the same name as the CPP-file. The struct is defined as:

typedef struct httpresponse {
    char version[3];
    int status;
}

Everything compiles OK.

When I put debug-breaks in I get the right results (inside the function), eg. status=200 and version="1.1". However, the calling program gets only zero's. (The variable "_respBuffer" is a private 64-char in the class where the response from the webserver is stored).

In the calling program I have:

httpresponse httpResult; 
xb->parseHTTPResponse(&httpResult); 
Serial.print("Version:"); Serial.println(httpResult.version);
Serial.print("Statuscode:); Serial.println(httpResult.status);

Both the Serial.println's wil show 0 in the Serial-monitor.

gkempen: When I put debug-breaks in...

"Debug-breaks"?

Why not use pass by reference:

void xBee::parseHTTPResponse(struct httpresponse &response)

?

Or just return the struct:

struct httpresponse xBee::parseHTTPResponse()

?

Or, since the function parses a global variable, there really is nothing to be gained by not writing to a global variable.

strcpy(response->version, strtok(NULL, "/"));

The version field is 3 characters long, but you are copying four chafacters into it - "1.1" followed by a nul terminator. This will cause all sorts of problems.

Make the version 4 characters, and get into the habit of using strncpy rather than strcpy.

@paulMurrayCbr

I would tend not to agree with getting the habit of using strncpy(). It has its use but you also need to know its shortcomings.

The problem to know with this function is that it does not always null-terminate the destination String and This happens when there is no null byte in the fist n bytes of src to copy and will make any function that assumes that the string dst is null-terminated misbehave.

Of course strcpy() is vulnerable to buffer overflows.

So my point is don't get into habits - know what you do, use the functions that are best suited for your needs and understand their shortcomings and handle those if you are unsure about your char buffers.

If only there was a string copy function that worked correctly in all cases.

https://www.sudo.ws/todd/papers/strlcpy.html https://www.google.com/search?q=strlcpy

@Coding badly

Yes - that is what I mean use the right tool for the right case.

If you don’t know the conditions of your strings, test for bounds and use those. If you have knowledge then other functions are fine too.

[quote author=Coding Badly link=msg=2974179 date=1477344238] "Debug-breaks"? [/quote] Yeah, in Visual Micro you can add breakpoint. Then you don't need Serial.println to show the contents of your var's.

Soooo… I changed the char to be 4 long (as @PaulMurrayCbr) suggested.
Then it started working. Life can be so simple, when you look in the right place… :confused:

Thnx guys for all your responses.

PaulS: Why not use pass by reference:

void xBee::parseHTTPResponse(struct httpresponse &response)

?

Or just return the struct:

struct httpresponse xBee::parseHTTPResponse()

?

Or, since the function parses a global variable, there really is nothing to be gained by not writing to a global variable.

I'm under the impression that I already AM passing by reference?! Since I'm using a pointer in the parameter and referencing it in the call using "&".

I was thinking that passing an entire struct as parameter of returning it as a function result would require more memory. And since I'm trying to develop good coding-behaviour that came to me as the not-so-good option.