C Programming: Why printf Format Specifier %s Is Invalid For The Number "123"?

Viewed 699

I am quite a C programming newbie.

With answers for other question, I could understand the term "character" could point to vary elements; e.g. letters and numbers.

I am regarding "string" as characters.

Then, please take a look at the lines below:

#include <stdio.h>

main()
{
    int numbers = 123;
    printf("%c%s\n", "N", numbers); 
}

When I tried to compile this code, error messages were displayed and compiling failed.

The textbook "The C Programming Language" page 13 says like below about printf format specifiers;

"%c for character"

"%s for character string".

First Question:

Although "N" is a character, why is %c specifier invalid?

Second Question:

Although the value of variable "numbers" is "123", they are numbers, which are included in the character.

I have thought characters equal "string."

Then, although I have used %s for "123", why is it invalid?

I know my code will work, if I revise them like one below:

#include <stdio.h>

main()
{
    int numbers = 123;
    printf("%s%d\n", "N", numbers); 
}

but I would want to understand why the code above is invalid.

4 Answers

"Although "N" is a character, why is the %c specifier invalid?"

"N" isn't a character constant. It is a string literal. 'N' is a character constant and matching to %c. The difference between single and double quotation marks is important.

Also the specifier is never invalid. Only the argument type can be.

"Then, although I have used %s for "123", why is it invalid?"

You did not used "123", which is a string literal and emit a char *. You use 123. 123 is an integer value stored in an object of type int numbers. An int argument is not permissible for the %s format specifier which requires an argument of type char *, not int.

That is the difference.

The instruction

printf("%c%s\n", "N", numbers); 

contains two mistakes.

  1. Format specifier %c expects that a single character is passed. The way we define a character constant in C is using single quotes 'N'.
    By using double quotes "N" you are using a syntactic sugar way C offers to represent a string, that is an array of characters closed by the string terminator '\0'

  2. 123 is an integer, and like you correctly wrote the %d format specifier is expected

Talking about the last mistake, you gave an original interpretation

Although the value of variabale "numbers" is "123", they are numbers, which are included in the character.

I have thought characters equal "string."

Then, although I have used %s for "123", why is it invalid?

Though it is obviously a wrong interpretation, I find it interesting and it deserves an explanation.

Is 123 a string, that is a sequence of characters? Sure it is! But it is a string within the source code. The compiler will parse this sequence of characters, will recognize an integer, and will make sure that this value is stored within a memory location containing an integer. In most modern computers it will translate into a sequence of 0/1 representing the number 123 in 4 bytes.

0b01111011

Isn't "123" the same from the source code perspective? Well, no. The number is surrounded by double quotes, so the compiler will interpret it as an actual string, stored in memory as a nul-terminated sequence of characters

--------------------------
| '1' | '2' | '3' | '\0' |
--------------------------

and in memory the ASCII values representing those numbers (assuming the ASCII encoding is used) will be stored

-----------------------------
| 0x31 | 0x32 | 0x33 | 0x00 |
-----------------------------

I'll go straight to your questions.

First Question:

The C programming language distinguishes between double quotes and single quotes. double quotes will create string literals, while single quotes will create character literals. So, for example 'N' is a character, while "N" is a string containing only a single character, which is N. So, the reason why %c doesn't work, is that it expects a character, but you're giving it the string "N".

Second Question:

The value of the variable numbers is NOT "123". Using the C language's notation, "123" would be a string containing the characters '1', '2', and '3', whereas the variable numbers contains the integer 123 right now, and that is the reason why %s won't work for numbers. Although you could convert the value of variable 123 to a string like this:

#include <stdio.h>

main()
{
    int numbers = 123;
    char numbers_string[4];
    sprintf(numbers_string, "%d", numbers); // conversion happens here
    printf("%s\n", numbers_string); 
}

Also, there appears to be a confusion between the two types "string" and "character" in your question. It is important to understand that these two types are different. a character is a single Byte that (usually) holds the ASCII-code for the character you want. For example, the character 'A' (ASCII-code = 65). But a "string" is a collection of characters, like "Apple", and in the C language, a "string" is usually implemented using a char* which points to a location in memory that has the characters stored in sequence. (this is the reason why I used a character array to hold the results of converting numbers into "string")

Although "N" is a character, why is %c specifier invalid?

"N" is a string, not a single character - double quotes indicate a string literal. 'N' (single quotes) would be a character constant1, so

printf( "%c\n", 'N' );

would work correctly. To print "N", you need to use the %s conversion specifier:

printf( "%s\n", "N" );

The %s conversion specifier expects its corresponding argument to have type char * (pointer to char), and it will tell printf to print the sequence of characters starting at the specified address until it sees the string terminator.

The expression "N" has type "2-element array of char" (char [2]), and the contents of the array are {'N', 0}. In C, a string is a sequence of character values including a 0-valued terminator to mark the end of a string. Strings (including string literals) are stored in arrays of character type.

Under most circumstances, an expression of type "N-element array of T" (T [N]) will be converted ("decay") to an expression of type "pointer to T" (T *) and the value of the expression will be the address of the first element of the array.

In the printf statement above, the expression "N" is converted from type char [2] to char *, and the value of the expression is the address of the first character.

Although the value of variable "numbers" is "123", they are numbers, which are included in the character.

Let's look at the declaration of numbers:

int numbers = 123;

First of all, the type of the numbers variable is int, not char *. It doesn't matter what value it contains, it is not the type that %s expects. Secondly, 123 is not a string - it's not surrounded by quotes. Instead it's an integer constant.

numbers is not a string - it's not the right type to store a string, and it doesn't contain a sequence of characters with a 0 terminator. It's an integer, storing the binary representation of the decimal value 123. To print it out (that is, to produce the text representation of that integer value on your output device), you'd use %d or %i.


  1. In C, character constants like 'N' have type int, while in C++ they have type char.
Related