tags:

views:

133

answers:

5

Learning C at University. This is not a homework, but I was trying to do something (some "creative" part of the assignment) and got stuck.

I understand that this is possible

printf("%d\n", printf("23.4")); // -> 23.44 (i.e. 23.4 + 4 bytes written)

but how can I use sprintf() as first argument of printf() ?

something like :

char * getFormatString(int n) {
   char * buffer;

   sprintf(buffer, "Value with %%d decimals is %%.%df", n);

   return buffer; 
}

void foo() {
   int decimals = 2;
   float pi = 3.141592;

   printf(getFormatString(decimals), decimals, pi);  // should output "Value with 2 decimals is 3.14"
}

Is this even possible ? So far, I get a seg fault when executing it.

+2  A: 

You should at least allocate memory for your buffer first (and free it at the end):

char * buffer;
int decimals = 2;
float pi = 3.141592;

buffer = (char *) malloc(256); /* big enough buffer */
sprintf(buffer, "Value with %%d decimals is %%.%df", decimals);
printf(buffer, decimals, pi);

free(buffer);
SirDarius
alright, I understand. But if sprintf() and printf() are located in different functions ? One function returns a char * for the first argument of the printf function?
Yanick Rochon
@Yanick `sprintf()` returns an int.
Ruel
@Yanick I think you're using the word "returns" wrong. printf/sprintf both *return* ints. But they *take* char* as their first argument.
paleozogt
I'll edit the question to clarify (I do understand what the functions return, but I think there's a misunderstanding nevertheless)
Yanick Rochon
http://ideone.com/XW8Kt
pmg
If you're going to use a fixed-size buffer, there's no need for `malloc`; you can use `char buf[256]` (unless you're concerned about stack usage). One always should use `snprintf` over `sprintf` anyway, though.
jamesdlin
+2  A: 

printf returns the number of characters printed, so your first example would actually be

printf("%d", printf("23.4")); // -> 23.44

sprintf also returns the number of characters printed, so having it be an argument of printf probably isn't what you want.

The reason you're seg-faulting is that your buffer string isn't pointing to anything. You want to change your code to something like this:

char buffer[1024];    // buffer has to be an actual string (or you could use malloc)
int decimals = 2;
float pi = 3.141592;

sprintf(buffer, "Value with %%d decimals is %%.%df", decimals);

printf(buffer, decimals, pi);
paleozogt
+6  A: 

Using sprintf for this purpose is perverse. Instead try:

printf("Value with %d decimals is %.*f", decimals, decimals, pi);
R..
excellent! You have my respect and I stand corrected :) I never heard about that behavior (reading http://www.acm.uiuc.edu/webmonkeys/book/c_guide/2.12.html)
Yanick Rochon
A: 

printf() and sprintf() both return an int value. Which is the total number of characters.

int sprintf ( char * str, const char * format, ... );
int printf ( const char * format, ... );

You can only use sprintf() as an argument to printf() if you are to print the number of characters written by sprintf().

Ruel
+1  A: 

You are getting a segfault, because sprintf writes data to some place in memory which is pointed to by garbage (in the pointer buffer). You need to allocate some memory using malloc, like:

buffer = malloc(100);

before you use sprintf in function getFormatString. Then, remember to free this memory after using your string. In this particular code there is a memory leak, because you don't store the pointer returned from getFormatString anywhere.

Corrected code:

char *getFormatString(int n) {
    char *buffer = malloc(100);
    sprintf(buffer, "Value with %%d decimals is %%.%df", n);
    return buffer;
}

void foo() {
    int decimals = 2;
    float pi = 3.141592;
    char *fmtstr = getFormatString(decimals);
    printf(fmtstr, decimals, pi);  // should output "Value with 2 decimals is 3.14"
    free(fmtstr);
}
Michał Trybus