I need to build an url in with Query Params and different API Endpoints. I don't like to use a char array with a fixed sized because memory is wasted and I rely on hoping that the size will be big enough.
#define BASE_URL "https//mydomain.com/api/"
#define ID "ID1"
char* do_endpoint_request(const char* param)
{
char url[500];
snprintf(url, sizeof(url), BASE_URL "endpoint?id=%s¶m1=%s", ID, param);
// do request with url ...
}
How can I improve this code, that memory is allocated dynamically with exact size of the string and params injected?
CodePudding user response:
You can use the fact that snprintf()
may be called with NULL instead of an actual buffer and that it returns the length of the string that would have been created if there was enough space. So:
#define BASE_URL "https//mydomain.com/api/"
#define ID "ID1"
char* do_endpoint_request(const char* param)
{
int len;
len = snprintf(NULL, 0, BASE_URL "endpoint?id=%s¶m1=%s", ID, param);
char url[len 1]; // len excludes NULL; use malloc() if you can't use VLA
// sprintf() is ok now, url is guaranteed to be large enough
sprintf(url, BASE_URL "endpoint?id=%s¶m1=%s", ID, param);
// do request with url ...
}
CodePudding user response:
Maybe you need something like this:
char* do_endpoint_request(const char* param)
{
int sizeneeded = snprintf(NULL, 0, BASE_URL "endpoint?id=%s¶m1=%s", ID, param);
char url[sizeneeded 1];
sprintf(url, BASE_URL "endpoint?id=%s¶m1=%s", ID, param);
// do request with url ...
}
But if the string param
is of "reasonable" size, a local variable like in your example is good enough.
However you probably should do a sanity check on param
, to ensure that it's length is of reaonable/plausible size. Otherways all methods might end up in undefined behaviour:
- in your original code: if
param
is too long, theurl
array will be too small and you'll get undefined behaviour. - in the code suggested in this answer: if
param
is too long (maybe longer that a few thousands, depends on your platform and other factors),char url[sizeneeded];
might not end well and you'll get undefined behaviour.
CodePudding user response:
In this case, we would need the size of the parameter.
char* do_endpoint_request(const char* param, int param_size)
{
char* url = calloc(param_size <size of base url>, sizeof(char));
snprintf(url, sizeof(url), BASE_URL "endpoint?id=%s¶m1=%s", ID, param);
// do request with url ...
}
Something such as this should work as it but the allocated size might need to be changed.