tags:

views:

283

answers:

5

Hi all,

Wrote a very simple C function to illustrate what I would like to simplify:

void main(int argc, char *argv[]){
    char *me="Foo";
    char *you="Bar";
    char us[100];
    memset(us,100,0x00);

    sprintf(us,"You: %s\n",you);
    sprintf(us+strlen(us),"Me: %s\n",me);
    sprintf(us+strlen(us),"We are %s and %s!\n",me,you);
    printf(us);
}

It seems like there should be a standard library function to handle what I'm doing with sprintf and advancing the pointer, no? Has been years since I've done any amount of C...

Thanks, -aj

+1  A: 

You are probably looking for strcat (or even better strncat).

kgiannakakis
Hrrm...for a formatted string...?
AJ
Format it first, then do the concatenation.
kgiannakakis
So, using multiple buffers then...right?
AJ
@AJ, no, you can use the same buffer, just keep catting onto the end of it (although, this is a little inefficient, because each time you invoke `strcat`/`strncat` it needs to rescan the entire string again).
dreamlax
+7  A: 

sprintf returns the number of non-NUL characters written.

int len = 0;
len += sprintf(us+len, ...);
len += sprintf(us+len, ...);
...
ephemient
Ha, I guess that is a bit more brief, but still accomplishing the same way.
AJ
No. Your example calls strlen() for every iteration, which makes it O(N^2) in the number of sprintf() calls. This takes advantage of the fact that the printf family of functions return the number of characters printed to get the strlen result for free. This is, in fact, the standard idiom for this sort of thing. And as always: make sure you're testing your buffer length and using snprintf if this is anything that will handle untrusted data!
Andy Ross
@Andy, great thoughts, thanks!
AJ
+1  A: 
char *me="Foo";
char *you="Bar";
char us[100];

char* out = us;
out += sprintf(out,"You: %s\n",you);
out += sprintf(out,"Me: %s\n",me);
out += sprintf(out,"We are %s and %s!\n",me,you);
printf("%s", us);
Hans Passant
Please don't `printf(us)`: `printf("%s", us)` and `fputs(us, stdout)` are much safer.
ephemient
Not germane to the question, sprintf() is evil too. Updated, thanks.
Hans Passant
`sprintf` is fine as long when you're confident in the size of your buffers. On the other hand, `printf(us)` spends extra work scanning for `%` even when it's safe and there shouldn't be any.
ephemient
+2  A: 

Hmm...couldn't you just use something like:

sprintf(us, "You: %s\nMe: %s\nWe are %s and %s!\n, you, me, me, you);
Jerry Coffin
or for SUS-compliant systems: `sprintf(us, "You: %1$s\nMe: %2$s\nWe are %2$s and %1$s!\n", you, me);`
dreamlax
+1  A: 

Never use a non-constant string as the first argument to printf (or second argument to fprintf. This is bad practice. Try changing the me variable to "Muahaha %n%d%n%d%n%d%n%d%n" and say goodbye to your stack and say hello to SEGFAULT. printf will try and format the string but you haven't provided any arguments for it to deal with, and even though there are format specifiers in the string printf has no idea that you haven't given it any arguments.

If you want to output a 'pre-formatted' string, use fputs(str,stdout). There is rarely a case to use printf with a non-constant format string.

dreamlax
@hhafez, no, dreamlax is saying that using a string other than a literal is dangerous, because it could contain format specifiers you haven't passed arguments for, invoking undefined behavior. This is a bigger concern when dealing with user input, because it opens you to attacks (never call printf(str) on user input) but also a problem if your program generates the wrong format string.
Nick Meyer
@hhafez: `printf` is used to print a formatted string **based on a format description string and supplied arguments**. When you provide a pre-formatted string and no arguments, you aren't using `printf` correctly. When you want to output a string verbatim, use a function dedicated for that purpose, such as `fputs`. If you use `printf` to output non-constant pre-formatted strings, you run the risk of telling `printf` to format parts of the string again. A malicious user can provide format specifiers as input (such as `%n` and `%d`) and your application would most certainly crash.
dreamlax
completely misread the answer, thanks for the explanation
hhafez