mike65535
mike65535

Reputation: 509

sprintf doesn't seem to grab zeroth string

I have the following code:

#include <stdio.h>

int main(void) {
char list[3][7] = { "One", "Two", "Three"} ;
char item[7];    // originally I had posted "char item[3];" by mistake
int i;

for( i=0; i<2; i++ ) {
    sprintf(item, "%-7s",  list[i]);
    printf( "%d %s", i, item );
}
printf("\n\r");
for( i=0; i<2; i++ ) {
    sprintf(item, "%-7s",  list[i]);
    printf( "%d %s", i, item );
}
printf("\n\r");

return 0;
}

I expect the following output

0 One    1 Two    
0 One    1 Two 

However, instead I get:

0 One    1 Two    
0        1 Two 

Note the missing text "One" the second time it prints.

Can someone explain what's happening here?

Thanks!

Upvotes: 0

Views: 287

Answers (2)

axiac
axiac

Reputation: 72226

With item declared as:

char item[7];

the code exposes undefined behaviour because sprintf(item, "%-7s") attempts to write at least 8 characters into item.

The documentation of sprintf() explains (the emphasis is mine):

Writes the results to a character string buffer. The behavior is undefined if the string to be written (plus the terminating null character) exceeds the size of the array pointed to by buffer.

-7 in the format string "%-7s" is interpreted as:

(optional) integer value or * that specifies minimum field width. The result is padded with space characters (by default), if required, on the left when right-justified, or on the right if left-justified. In the case when * is used, the width is specified by an additional argument of type int. If the value of the argument is negative, it results with the - flag specified and positive field width. (Note: This is the minimum width: The value is never truncated.)

In order to avoid the undefined behaviour, the size of item must be at least 8 but keep in mind that if the string to format is longer than 7 characters it is not truncated, the result becomes longer than 8 characters and it overflows item again.


Why you get the output you get?

The calls to sprintf(item, "%-7s", list[i]); in the first loop write 8 characters in a buffer of 7 characters. The extra character (which is \0) incidentally happens to overwrite the first character of list[0] changing it into an empty string. This is just one random behaviour, compiling the code with a different compiler or different compiling options could produce a different behaviour.

Upvotes: 1

Stephen P
Stephen P

Reputation: 14800

When you do the sprintf(item, "%-7s", list[i]); you are, essentially, copying the string from list[i] into your char array item. So list[2] -> "three" is 5 chars plus the nul terminator, but item is only 3 chars long -- you are overflowing item and writing over some other memory, which could very well be part of list.

Change item to be char item[7] so it matches the length of 7 declared in your 2nd dimension in list[3][7]. When I did that I got your expected output.
(I used https://repl.it/languages/C to test)

Upvotes: 1

Related Questions