-
String Pointers
I'm not quite sure how to explain this.
I've got some string pointers which need to be filled with an unknown length string at run-time. What I'm having trouble with, is the best way to populate those strings.
For example, I have a string pointer, which I'd like to populate thusly:
sprintf(strptr2,"this string: %s is my %dth attempt at this", strptr1, int1);
I know I need to Malloc or realloc to set the size of strptr2 before I sprintf to it. But how do I get the size?
strlen ("this string: %s is my %dth attempt at this", strptr1, int1); doesn't work, though it's be nice if it did.
I know I could make a fixed length string and sprintf to it, but in my application, the necessary length will be wildly variable.
Is there an automatic way to make my own functions handle getting passed ("%d", int1) type of stuff?
I know I'm missing something.
Thanks.
-
There are implementation-specific functions that can actually get the total size needed for that to work (I know Visual Studio has one), but otherwise it isn't possible without a manual method unfortunately.
The best thing to do is to check the size of each strings, assume the maximum length for integers (like 20 chars or so) and then allocate enough space beforehand.
You could, of course, also convert those numbers to strings and then check their length.
Don't forget to add space for the whole formatting string you're passing, as well.
-
Of course, it's not hard to produce a "close enough to work" estimate for this particular type of example: %d takes up a max of 12 characters, %s takes up as much as the string is long, and then the format string's length.
You could write a parser that takes the arguments, like this:
Code:
int sprintfalloc(const char *fmt, ...)
{
va_list argp;
const char *s = fmt;
char *str;
size_t size = 0;
va_start(argp, fmt);
while(*s)
{
if (*s == '%')
{
switch(s[1])
{
case 's':
size += strlen((va_arg(argp, char *));
break;
case 'd':
size += 12; // We could calculate the size of course.
(void) va_arg(argp, int);
break;
case 'c':
size++;
break;
default:
// Do something here, perhaps?
}
}
}
va_start(argp, fmt);
str = malloc(size + 1);
vsprintf(str, fmt, argp);
va_end(argp);
}
Of course, it would get a whole lot more complicated if you needed to cope with more exotic variants of formatting, e.g "%10d" or "%10.19f", or worse yet "%*d". It can be dealt with, but at that point, it may make more sense to use a really large buffer, sprintf() to that buffer, and then copy to a smaller buffer if you need to keep the string around.
--
Mats
-
If you have some kind of snprintf() function, you can get it to tell you how long the string would need to be.