'How to build Url dynamically in C
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?
Solution 1:[1]
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 ...
}
Solution 2:[2]
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
paramis too long, theurlarray will be too small and you'll get undefined behaviour. - in the code suggested in this answer: if
paramis 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.
Solution 3:[3]
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.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Jabberwocky |
| Solution 2 | |
| Solution 3 | Fuex Follets |
