Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does printf() function treat the strings returned by functions using global buffers?

I have written a small code that prints the current date with a specific format. To return each data of the date (day of the week, day of the month, name of the month, etc.), I use functions of type const char * that pass the data as a string to a variable that serves as a buffer and then pass the buffer to the main function.

The following code represents the operation of my program in a very simple way:

#include <stdio.h>
#include <string.h>

char
buff[16];

const char
*printStr1 (char *str1)
{
    strncpy(buff, str1, sizeof(str1));
    return buff;
};

const char
*printStr2 (char *str2)
{
    strncpy(buff, str2, sizeof(str2));
    return buff;
};


int
main()
{
    printf("%s%s", printStr1("foo"), printStr2("bar"));
    return 0;
}

My issue is this: when passing each data to the buffer and returning it to the main function, the last two data are the same (the last data is not printed, instead it is printed what was already in the buffer, that is, the second last data).

This only happens when I use a single printf() function to show all the data, as in the example above. If I do not use a buffer to return the data (I directly return the argument passed to the function) or use a printf() for every data , everything is executed correctly.

P.S.: I tried to solve this using functions like memset() to clean the buffer, but it does not work, the only thing I can do is use a different buffer for each data (for each function).

I hope I have expressed my problem well.

like image 831
DonFuhrer Avatar asked Nov 08 '18 09:11

DonFuhrer


People also ask

What is the purpose of using printf () function?

The printf() function sends a formatted string to the standard output (the display). This string can display formatted variables and special control characters, such as new lines ('\n'), backspaces ('\b') and tabspaces ('\t'); these are listed in Table 2.1.

Does the printf () function sends formatted output to stdout?

The C library function int printf(const char *format, ...) sends formatted output to stdout.

What is the purpose of printf () and scanf () in C program?

The printf() and scanf() functions are used for input and output in C language. Both functions are inbuilt library functions, defined in stdio.h (header file).

How does printf work in assembly?

Printf in Assembly To call printf from assembly language, you just pass the format string in rdi as usual for the first argument, pass any format specifier arguments in the next argument register rsi, then rdx, etc.


2 Answers

Besides the sizeof issue (that you're overlooking because your strings are small), your issue isn't related to printf

The code first evaluates the arguments, then passes them to printf. The last evaluated argument "wins" and printf gets the same argument twice.

To use only one local buffer, split your printf call:

printf("%s%s", printStr1("foo"), printStr2("bar"));

could be rewritten to:

printf("%s", printStr1("foo"));
printf("%s", printStr2("bar"));

once printed the value can change it doesn't matter :)

Since C doesn't have a garbage collector or string objects, you cannot just allocate separate buffers and return them to pass to printf else you'd get memory leaks, so in C there's no smart & readable solution for such issues.

That said, in one C project I made, I used a revolving list of strings (several buffers, first in, first out). Make it 10 buffers, and you can use up to 10 arguments in the same function and it will work properly.

like image 74
Jean-François Fabre Avatar answered Oct 22 '22 11:10

Jean-François Fabre


This code:

printf("%s%s", printStr1("foo"), printStr2("bar"));

is equivalent to this:

const char *p1 = printStr1("foo");
const char *p2 = printStr2("bar");
printf("%s%s", p1, p2);

or this (depending on the compiler):

const char *p2 = printStr2("bar");
const char *p1 = printStr1("foo");
printf("%s%s", p1, p2);

Now it should be clear why you're getting the output you get.

like image 38
Jabberwocky Avatar answered Oct 22 '22 10:10

Jabberwocky