1

I'm writing a TCP socket in C to send location data for a project I'm working on.

So far, everything works, but I'm struggling with this seemingly simply problem. I'm trying to build a JSON String that will be sent over the socket. I have a character array (representative of the String) json defined as:

char json[1024];

With a method prototype:

const char* build_json(void);

And method body:

const char* build_json(void) {
    strcpy(json, "{");
    strcat(json, "\"latitude\":");
    sprintf(json, "%0.5f", latitude);
    strcat(json, "}");
    return json;
}

I know that latitude is defined correctly and should be a float of approximately 5 decimal places.

But when I call build_json();, 38.925034} is the only thing that is returned. Why is this the case? It appears that the call to sprintf is overwriting what's already been written in json.

Thanks for your help!

James Taylor
  • 6,158
  • 8
  • 48
  • 74

4 Answers4

10

sprintf will not append to your string; rather, it will overwrite whatever is there. You could do this:

sprintf(json + strlen(json), "%0.5f", 213.33f);

But, to be honest, this is a much better solution:

sprintf(json, "{\"latitude\":%0.5f}", location);

And this solution is still better:

snprintf(json, sizeof(json), "{\"latitude\":%0.5f}", location);
json[sizeof(json) - 1] = '\0';

as long as json is an array visible to the function that calls snprintf, i.e. allocated in that function on the stack, or globally. If it's a char* that you pass to the function, this will fail miserably, so beware.

James Taylor
  • 6,158
  • 8
  • 48
  • 74
user4520
  • 3,401
  • 1
  • 27
  • 50
1

You had better to do this only with sprintf to avoid multiple operations.

const char* build_json(void) {
    sprintf(json, "{\"latitude\":%0.5f}", latitude);
    return json;
}

Moreover if you are writing network code, you had better to allocate your string in your function and not relying on global. Often, network code are done in a multi-thread way.

TrapII
  • 2,219
  • 1
  • 15
  • 15
0

Quick & dirty fix:

char* cptr = json;
...
strcpy(cptr, "{");
cptr += sizeof("{") - 1;

strcat(cptr, "\"latitude\":");
cptr += sizeof("\"latitude\":") - 1;

sprintf(cptr, "%0.5f", latitude);

The proper solution would be put the string literals and their sizes in constant variables instead of the above.

char* cptr = json;
...
strcpy(cptr, STR_START_BRACE);
cptr += STR_START_BRACE_LEN;

strcat(cptr, STR_LATITUDE);
cptr += STR_LATITUDE_LEN;

sprintf(cptr, "%0.5f", latitude);
Lundin
  • 195,001
  • 40
  • 254
  • 396
0

You may write the whole string at once in buffer:

const void build_json(char * json, size_t *len) 
{
    char buff[50];
    sprintf(buff, "{\"latitude\":%0.5f}", latitude);
    *len = strlen(buff);
    strncpy(json, buff, *len);
}

Just provide enough space for buffer, you need to allocate your json outside of the func and free it when out of scope

  • The `strncpy()` misses to copy the `0`-termination. And why (the intermediate) use of `buf` at all? – alk May 22 '15 at 06:53
  • it depends on the usage, we have no clue what is the consumer of the function, From word "json" I assumed it would be net send - then you have length to be able to send and in such case you do not care about zero termination – Hristo Bojkov May 22 '15 at 11:30
  • No need to call `strlen` after you `sprintf` btw, since `sprintf` returns the number of characters written to the buffer. – user4520 May 22 '15 at 15:40