Declare string in C without giving size - c

I want to concatenate in a string multiple sentences. At the moment my buffer is with fixed size 100, but I do not know the total count of the sentences to concatenate and this size can be not enough in the future. How can I define a string without defining its size?
char buffer[100];
int offset = sprintf (buffer, "%d plus %d is %d", 5, 3, 5+3);
offset += sprintf (buffer + offset, " and %d minus %d is %d", 6, 3, 6-3);
offset += sprintf (buffer + offset, " even more");
printf ("[%s]",buffer);

This is a fundamental aspect of C. C never does automatic management of dynamically-constructed strings for you — this is always your responsibility.
Here is an outline of four different techniques you might use. You can ask additional questions about any of these that aren't clear.
Run through your string-construction process twice. Make one pass to collect the lengths of all the substrings, then call malloc to allocate a buffer of the computed size, then make a second pass to actually construct your string.
Allocate a smallish (or empty) initial buffer with malloc, and then, each time you're about to append a new substring to it, check the buffer's size, and if necessary grow it bigger using realloc. (In this case I always use three variables: (1) pointer to buffer, (2) allocated size of buffer, (3) number of characters currently in buffer. The goal is to always keep (2) ≥ (3).)
Allocate a dynamically-growing "memstream" and use fprintf or the like to "print" to it. This is an ideal technique, although memstreams are not standard and not supported on all platforms, and dynamically-allocating memstreams are even more exotic and less common. (It's possible to write your own, but it's a lot of work.) You can open a fixed-size memstream using fmemopen (although this is not what you want), and you can open the holy grail, a dynamically-allocating memstream (which is what you want) using open_memstream, if you have it. Both are documented on this man page. (This technique is analogous to stringstream in C++.)
The "better to beg forgiveness than ask permission" technique. You can allocate a buffer which you're pretty sure is amply big enough, then blindly stuff all your substrings into it, then at the very end call strlen on it and, if you guessed wrong and the string is longer than the buffer you allocated, print a big scary noisy error message and abort. This is a blunt and risky technique, not one you'd use in a production program. It's possible that when you overflow the buffer, you damage things in a way that causes the program to crash before it has a chance to perform its belated check-and-maybe-exit step at all. If you used this technique at all, it would be considerably "safer" (that is, considerably less likely to prematurely crash before the check) if you allocated the buffer using malloc, than if you declared it as an ordinary, fixed-size array (whether static or local).
Personally, I've used all four of these. Out in the rest of the world, numbers 1 and 2 are both in common use by just about everybody. Comparing them: number 1 is simple and a bit easier but has an uncomfortable amount of code replication (and might therefore be brittle if new strings are added later); number 2 is more robust but obviously requires you to be comfortable with the way realloc works (and this technique can be less than robust in its own way, if you've got any auxiliary pointers into your buffer which need to be ponderously relocated each time realloc is called).
Number 3 is an "exotic" technique: theoretically almost ideal, but definitely more sophisticated and necessitating some extra support, since nothing like open_memstream is standard.
And number 4 is obviously a risky and inherently not reliable technique, which you'd use — if at all — only in throwaway or prototype code, never in production.

You can use the snprintf function with NULL for the first argument and 0 for the second get the size that a formatted string would be. You can then allocate the space dynamically and call snprintf again to actually build the string.
char *buffer = NULL;
int len, offset = 0;
len = snprintf (NULL, 0, "%d plus %d is %d", 5, 3, 5+3);
buffer = realloc(buffer, offset + len + 1);
offset = sprintf (buffer + offset, "%d plus %d is %d", 5, 3, 5+3);
len = snprintf (NULL, 0, " and %d minus %d is %d", 6, 3, 6-3);
buffer = realloc(buffer, offset + len + 1);
offset += sprintf (buffer + offset, " and %d minus %d is %d", 6, 3, 6-3);
len = snprintf (NULL, 0, " even more");
buffer = realloc(buffer, offset + len + 1);
offset += sprintf (buffer + offset, " even more");
printf ("[%s]",buffer);
Note that this implementation omits checking on realloc and snprintf for brevity. It also repeats the format string and arguments. The following function addresses these shortcomings:
int append_buffer(char **buffer, int *offset, const char *format, ...)
{
va_list args;
int len;
va_start(args, format);
len = vsnprintf(NULL, 0, format, args);
if (len < 0) {
perror("vsnprintf failed");
return 0;
}
va_end(args);
char *tmp = realloc(*buffer, *offset + len + 1);
if (!tmp) {
perror("realloc failed");
return 0;
}
*buffer = tmp;
va_start(args, format);
*offset = vsprintf(*buffer + *offset, format, args);
if (len < 0) {
perror("vsnprintf failed");
return 0;
}
va_end(args);
return 1;
}
Which you can then call like this:
char *buffer = NULL;
int offset = 0;
int rval;
rval = append_buffer(&buffer, &offset, "%d plus %d is %d", 5, 3, 5+3);
if (!rval) return 1;
rval = append_buffer(&buffer, &offset, " and %d minus %d is %d", 6, 3, 6-3);
if (!rval) return 1;
rval = append_buffer(&buffer, &offset, " even more");
if (!rval) return 1;
printf ("[%s]",buffer);
free(buffer);

Related

coverity is throwing overrun-buffer-arg issues

coverity is throwing the following error:
overrun-buffer-arg: Calling "snprintf" with "key_name + len" and "256U" is suspicious because "key_name" points into a buffer of 256 bytes and the function call may access "(char *)(key_name + len) + 255U".
char key_name[256];
u_int32_t len;
snprintf(key_name+len, 256, "%s", student->name);
Please suggest how to fix this
If len is anything but 0, snprintf can write outside the buffer key_name. If student->name is very long, for example. Or if len is close to 256 or over.
Since snprintf was specifically designed to prevent buffer overflows, it's a very helpful warning message.
It should probably be something like this:
char key_name[256];
size_t len = 0;
snprintf(key_name + len, sizeof key_name - len, "%s", student->name);
This should work for every 0 < len < sizeof key_name. Even if len grows, as is typical by e.g. other snprintf calls, this will ensure it will not overflow the buffer.
Edit:
You should also check the return value of snprintf against sizeof key_name - len. If it's equal or larger, the student name was truncated.

How to calculate the length of output that sprintf will generate?

Goal: serialize data to JSON.
Issue: i cant know beforehand how many chars long the integer is.
i thought a good way to do this is by using sprintf()
size_t length = sprintf(no_buff, "{data:%d}",12312);
char *buff = malloc(length);
snprintf(buff, length, "{data:%d}",12312);
//buff is passed on ...
Of course i can use a stack variable like char a[256] instead of no_buff.
Question: But is there in C a utility for disposable writes like the unix /dev/null?
Smth like this:
#define FORGET_ABOUT_THIS ...
size_t length = sprintf(FORGET_ABOUT_THIS, "{data:%d}",12312);
p.s. i know that i can also get the length of the integer through log but this ways seems nicer.
Since C is where simple language, there is no such thing as "disposable buffers" -- all memory management are on programmers shoulders (there is GNU C compiler extensions for these but they are not standard).
cant know beforehand how many chars long the integer is.
There is much easier solution for your problem. snprintf knows!
On C99-compatible platforms call snprintf with NULL as first argument:
ssize_t bufsz = snprintf(NULL, 0, "{data:%d}",12312);
char* buf = malloc(bufsz + 1);
snprintf(buf, bufsz + 1, "{data:%d}",12312);
...
free(buf);
In older Visual Studio versions (which have non-C99 compatible CRT), use _scprintf instead of snprintf(NULL, ...) call.
You can call int len = snprintf(NULL, 0, "{data:%d}", 12312) to test how much space you need.
snprintf will print at most size characters, where size is the second argument, and return how many characters would have been necessary to print the whole thing, not counting the terminating '\0'. Because you pass in 0, it won't actually write anything out (and thus will avoid any null pointer exception that would happen by trying to dereference NULL), but it will still return the length that is needed to fit the whole output, which you can use to allocate your buffer.
At that point you can allocate and print to your buffer, remembering to include one more for the trailing '\0':
char *buf = malloc(len + 1);
snprintf(buf, len + 1, "{data:%d}", 12312);
To just obtain the length you can write:
int length = snprintf(NULL, 0, "{data:%d}", 12312);
Note that the return type is int. It may return -1 in case of some sort of error. Make sure your input data doesn't include long strings that might cause the total length to exceed INT_MAX !
If you check the performance, you will running snprintf without an output buffer will take roughly the same time as a full invocation.
So I recommend you to use a smaller buffer just in case, and only call it a second time if the returned size exceeded the buffer size.
This uses C++'s std::string but I guess you can adapt it for your needs.
std::string format(const char* format, ...) {
va_list args;
va_start(args, format);
char smallBuffer[1024];
int size = vsnprintf(smallBuffer, sizeof smallBuffer, format, args);
va_end(args);
if (size < sizeof smallBuffer)
return std::string(smallBuffer);
char buffer[size + 1]; /* maybe malloc if it's too big */
va_start(args, format);
vsnprintf(buffer, sizeof buffer, format, args);
va_end(args);
return std::string(buffer);
}
This code will run 2x faster for strings under 1k compared to the longer ones.
Calling snprintf(nullptr, 0, ...) does return the size but it has performance penalty, because it will call IO_str_overflow and which is slow.
If you do care about performance, you can pre-allocate a dummy buffer and pass its pointer and size to ::snprintf. it will be several times faster than the nullptr version.
template<typename ...Args>
size_t get_len(const char* format, Args ...args) {
static char dummy[4096]; // you can change the default size
return ::snprintf(dummy, 4096, format, args...) + 1; // +1 for \0
}
Printf supports %n format parameter, which means "write position of %n in output string to int value pointed by x-parameter), so:
int x;snprintf(NULL, 0, "Message: %s%n", "Error!",&x);
Should works!
This isn't strictly an answer to your question, but you may find it helpful nonetheless. It is not portable, but if you're running this on glibc, you can simply use asprintf() instead, which will do the memory allocation for you.

Estimate size of formatted snprintf() string?

I'm considering writing a function to estimate at least the full length of a formatted string coming from the sprintf(), snprintf() functions.
My approach was to parse the format string to find the various %s, %d, %f, %p args, creating a running sum of strlen()s, itoa()s, and strlen(format_string) to get something guaranteed to be big enough to allocate a proper buffer for snprintf().
I'm aware the following works, but it takes 10X as long, as all the printf() functions are very flexible, but very slow because if it.
char c;
int required_buffer_size = snprintf(&c, 1, "format string", args...);
Has this already been done ? - via the suggested approach, or some other reasonably efficient approach - IE: 5-50X faster than sprintf() variants?
Allocate a big enough buffer first and check if it was long enough. If it wasn't reallocate and call a second time.
int len = 200; /* Any number well chosen for the application to cover most cases */
int need;
char *buff = NULL;
do {
need = len+1;
buff = realloc(buff, need); /* I don't care for return value NULL */
len = snprintf(buff, need, "...", ....);
/* Error check for ret < 0 */
} while(len > need);
/* buff = realloc(buff, len+1); shrink memory block */
By choosing your initial value correctly you will have only one call to snprintf() in most cases and the little bit of over-allocation shouldn't be critical. If you're in a so tight environment that this overallocation is critical, then you have already other problems with the expensive allocation and formating.
In any case, you could still call a realloc() afterwards to shrink the allocated buffer to the exact size.
If the first argument to snprintf is NULL, the return value is the number of characters that would have been written.

malloc double datatype with strlen

how do I allocate memory for strlen(esc) in a proper way? The temp and str are char datatypes.
double esc = t1.tv_sec+(t1.tv_usec/1000000.0);
strAll = malloc(strlen(temp) + strlen(str) + strlen(esc) + 1);
You cannot take strlen(esc). As I am sure the compiler has already told you, the argument to strlen() must be char *, you are passing it a double. Try first converting the double to array of char with snprintf().
You can find the length you need using snprintf. Passing '0' as the size will prevent is from writing any bytes, and it returns the number of bytes it would have needed.
size_t length = snprintf(0, 0, "%lf%s%lf", esc, temp, esc) + 1;
strAll = malloc(length);
snprintf(strAll, length, "%lf%s%lf", esc, temp, esc);
You'll need to convert esc to a string, probably with sprintf(). Then use the length from that in the malloc():
char buffer[32];
int n = snprintf(buffer, sizeof(buffer), "%.6f", esc);
if (n >= sizeof(buffer))
...handle overlong string problems (bail out)...
char *strAll = malloc(strlen(temp) + strlen(str) + n + 1);
if (strAll == 0)
...handle out of memory problem (bail out)...
sprintf(strAll, "%s%s%s", temp, str, buffer);
(I didn't check the length returned by sprintf() because 'it cannot go wrong'. You calculated the length of the component strings, and therefore, it will fill exactly the allocated space. If you do decide to check it, then preserve the length that is the argument to malloc() and test against that.)
Your code don't compile. strlen expects a string argument, that is a pointer to a sequence of char (like an array).
Perhaps you want something like
char buf[30];
double esc = somedoublefunction();
snprintf (buf, sizeof(buf), "%f", esc);
return strdup(buf);
of course you should care to later free the resulting pointer.
Try using one of the following if you're just trying to save all the data in one buffer:
sizeof(esc) or sizeof(double)
If you want to turn esc into a string. Otherwise, I would suggest using a fixed point format when converting to a string e.g. snprintf(buffer, 7, "%03.3f", esc);

C string definition of unknown length

I need to store data (Of previously unknown format/size) inside a string for processing later (To be stored in an XML file)
How do I do this?
As you can see, the code below will generate a segfault.
char * type;
char * output;
for (i=0; i< 10; i++){
if(strcmp(GTK_OBJECT_TYPE_NAME(g_hash_table_lookup(widgetbuffer,allocate[i])), "GtkAdjustment") == 0){
type = "spin";
sprintf(output, "%f", gtk_adjustment_get_value(GTK_ADJUSTMENT(g_hash_table_lookup(widgetbuffer,allocate[i]))));
}else if(strcmp(GTK_OBJECT_TYPE_NAME(g_hash_table_lookup(widgetbuffer,allocate[i])), "GtkCheckButton") == 0){
type = "check";
sprintf(output, "%d", gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(g_hash_table_lookup(widgetbuffer,allocate[i]))));
}else if(strcmp(GTK_OBJECT_TYPE_NAME(g_hash_table_lookup(widgetbuffer,allocate[i])), "GSList") == 0){
type = "radio"; // Loop through grouped buttons and find active one
sprintf(output, "%d", g_slist_position(g_hash_table_lookup(widgetbuffer,allocate[i]),
g_slist_find_custom(g_hash_table_lookup(widgetbuffer,allocate[i]),
NULL, (GCompareFunc) searchRadio)));
}else if(strcmp(GTK_OBJECT_TYPE_NAME(g_hash_table_lookup(widgetbuffer,allocate[i])), "GtkComboBox") == 0){
type = "combo";
sprintf(output, "%d", gtk_combo_box_get_active(GTK_COMBO_BOX(g_hash_table_lookup(widgetbuffer,allocate[i]))));
}else if(strcmp(GTK_OBJECT_TYPE_NAME(g_hash_table_lookup(widgetbuffer,allocate[i])), "GtkEntry") == 0){
type = "entry";
output = (char *) gtk_entry_get_text(GTK_ENTRY(g_hash_table_lookup(widgetbuffer,allocate[i])));
}
[...]
In general, to "store data of an unknown size" in a C string, you have two choices:
Allocate a buffer large enough to hold any expected size (which means you would truncate the data if it exceeds that size), or
Dynamically allocate a buffer (using malloc()) that is large enough to hold the data. Don't forget to free() it, too.
Your code is using an uninitialised pointer output and that is why it is segfaulting. You will need to do one of the above.
If your platform has snprintf or similar (most do), then you want something like this:
int n = snprintf( NULL, 0, "%s is %d", somestring, someinteger );
char * p = malloc( n + 1 );
sprintf( p, "%s is %d", somestring, someinteger );
The first call to snprintf returns how many chars would be needed to store the formatted output, but doesn't actually do any formatting. Then you allocate the space needed and do the real formatting.
You are not allocating output and that is precisely why you are getting segmentation faults. As it is in the code provided, output has not been initialized. Your compiler should warn you of this.
If you know a safe maximum size, you can simply allocate it on the stack:
char output[512];
...if the maximum size was 512 bytes. Otherwise, you can look at malloc to allocate memory off the heap.
In addition to pre-allocate a big enough buffer or to truncate the output to size:
Pre-process the generation (no writes, just count the lengthes) and allocate a suitable buffer for the second (really write) pass
Write to 'unlimited' storage: a file

Resources