Grammar
Statements
C code is made up of lines of statements, which are commands that are executed by a program. C specifies that statements must be terminated by a semicolon, unless it is explicitly stated that the semicolon can be left out.
int x = 1;
The above is a variable declaration statement that declares the integer variable x
and sets the value to 1
.
Multiple statements can be written on one line.
int x; x = 1;
The above example is two statements written on one line. Therefore, line breaks between statements are not necessary, but are simply to make the code easier to read.
A statement can also be written as more than one line, in which case you rely on a semicolon to determine which line the statement ends on.
int x;
x
=
1
;
In the above example, the second statement x = 1;
is split into four lines. The compiler will automatically ignore line breaks in the code.
A single semicolon is also a valid statement, called an "empty statement", although it does nothing.
;
Expressions
C does all kinds of calculations, mainly through expressions. An expression is a computational formula that is used to obtain a value.
1 + 2
The code above is an expression that gets the result of the arithmetic calculation 1 + 2
.
An expression with a semicolon can also be a statement, but has no real effect.
8;
3 + 4;
The above example is two expressions that become statements when a semicolon is added.
Expressions differ from statements in two main ways.
- Statements can contain expressions, but expressions do not themselves constitute statements.
- Expressions have a return value; statements do not necessarily have one. Because statements are used to execute a command, they often do not require a return value, for example, a variable declaration statement (
int x = 1
) has no return value.
Statement blocks
C allows multiple statements to be formed into a block, also known as a compounded statement, using a pair of curly brackets {}
. Syntactically, a block of statements can be thought of as a compound statement made up of several statements.
{
int x;
x = 1;
}
In the above example, the curly brackets form a block of statements.
There is no need to add a semicolon to the end of the curly braces.
Spaces
Spaces in C are mainly used to help the compiler distinguish syntactic units. If syntactic units can be distinguished without spaces, spaces are not necessary, but only to increase the readability of the code.
int x = 1;
// is equivalent to
int x = 1;
In the above example, the assignment sign (=
) can be preceded or followed by a space, because the compiler can distinguish syntactic units here without the help of spaces.
Multiple spaces between syntactic units are equivalent to a single space.
int x = 1;
In the above example, multiple spaces between syntax units have the same effect as a single space.
Spaces are also used to indicate indentation. It makes no difference to the compiler whether the code is indented or not at multiple levels; it works perfectly well without indentation. The emphasis on indentation is simply to enhance the readability of the code and to make it easier to distinguish between blocks of code.
The style requirement for most C languages is that the next level of code is indented by four spaces from the previous level. For compactness of writing, this book uses an abbreviation of two spaces.
// indent four spaces
if (x > 0)
printf("positive\n");
// indent two spaces
if (x > 0)
printf("positive\n");
A line containing only spaces is called a blank line, and the compiler will ignore the line entirely.
Comments
A comment is a description of the code and is ignored by the compiler, i.e. it has no effect on the actual code.
There are two ways of representing comments in C. The first way is to place the comment between /*... */
between them, which can be internally split.
/* comment */
/*
This is a line of comments
*/
This comment can be inserted inside a line.
int open(char* s /* file name */, int mode);
In the above example, /* file name */
is used to specify the function argument, and the code that follows it will still execute effectively.
This comment must not forget to write the closing symbol */
, otherwise it can easily lead to errors.
printf("a "); /* Comment one
printf("b");
printf("c"); /* comment two */
printf("d");
The original intent of the above example was to have two comments at the end of the first and third lines of code. However, the first line comment forgets to write the end symbol, causing comment one to continue to the end of the third line.
The second way to write the comment is to place it after the double slash //
, so that it is a comment from the double slash to the end of the line. This type of comment can only be a single line, either at the beginning of a line or at the end of a statement. This is a new syntax added to the C99 standard.
// This is a line of comments
int x = 1; // This is also a comment
Either way, comments should not be placed inside double quotes. A comment symbol inside double quotes becomes part of the string, interpreted as a normal symbol, and loses its commenting effect.
printf("// hello /* world */ ");
In the above example, all comment symbols inside double quotes are treated as ordinary characters and have no comment effect.
When compiled, the comment will be replaced with a space, so min/* space */Value
will become min Value
instead of minValue
.
printf()
Basic usage
The examples in this book will make extensive use of the printf()
function, so here is a quick introduction to this function.
The purpose of printf()
is to output the text of the argument to the screen. The f
in its name stands for format
, which means that the format of the output text can be customised.
printf("Hello World");
The above command will output the text "Hello World" as a line on the screen.
printf()` does not automatically add a line break at the end of the line, and when it finishes running, the cursor stays at the end of the output and does not automatically break the line. To get the cursor to move to the beginning of the next line, add a line break
n`'' to the end of the output text.
printf("Hello World\n");
If there is a line break inside the text, this is also done by inserting a line break.
printf("Hello\nWorld\n");
The above example outputs a Hello
, then a line break, and at the beginning of the next line outputs World
, followed by another line break.
The above example could also be written as two printf()
s, with exactly the same effect.
printf("Hello\n");
printf("World\n");
printf()` is defined in the standard library's header file
stdio.h`. This header file must be introduced in the header of the source file before this function can be used.
#include <stdio.h>
int main(void) {
printf("Hello World \n");
}
In the above example, the function printf()
is only available if you add #include <stdio.h>
to the header of the source code. For a detailed explanation of the #include
directive, see the chapter on Preprocessors.
Placeholders
printf()
can specify placeholders in the output text. A ``placeholder'' is a position that can be substituted with another value.
// Output There are 3 apples
printf("There are %i apples\n", 3);
In the above example, There are %i apples\n
is the output text, and the %i
inside is a placeholder, indicating that this position is to be replaced by another value. The first character of the placeholder is always the percent sign %
, the second character indicates the type of the placeholder, and %i
means that the value substituted here must be an integer.
The second argument to printf()
is the value of the substituted placeholder, in the above example the integer 3
is substituted for %i
. The result is There are 3 apples
.
In addition to %i
, the common placeholder is %s
to indicate that the string is being substituted.
printf("%s will come tonight\n", "Jane");
In the example above, %s
means that the substitution is for a string, so the second argument to printf()
must be a string, in this case Jane
. The output after execution is Jane will come tonight
.
Multiple placeholders can be used inside the output text.
printf("%s says it is %i o'clock\n", "Ben", 21);
In the above example, the output text %s says it is %i o'clock
has two placeholders, the first being the string placeholder %s
and the second being the integer placeholder %i
, corresponding to the second argument (Ben
) and the third argument (21
) of printf()
respectively. The output after execution is Ben says it is 21 o'clock
.
There is a one-to-one relationship between printf()
arguments and placeholders; if there are n
placeholders, there should be n + 1
arguments to printf()
. If there are fewer arguments than the corresponding placeholders, printf()
may output any value in memory.
There are many different kinds of placeholders for printf()
, corresponding to the C data types. The following is an alphabetical list of commonly used placeholders to make it easier to find them, and the exact meaning is described in later sections.
%a
: floating point numbers.%A
: floating point numbers.%c
: character.%d
: decimal integers.%e
: floating-point numbers using scientific notation, withe
in lower case in the exponent part.%E
: floating point numbers using scientific notation, withE
in upper case for the exponent part.%i
: integers, basically equivalent to%d
.%f
: decimal numbers (containsfloat
types anddouble
types).%g
: a floating point number with 6 significant digits. The integer part is automatically converted to scientific notation once it exceeds 6 digits, ande
in the exponent part is lowercase.%G
: equivalent to%g
, the only difference being thatE
in the exponential part is in upper case.%hd
: decimal short int type.%ho
: octal short int type.%hx
: hexadecimal short int type.%hu
: unsigned short int type.%ld
: decimal long int type.%lo
: octal long int type.%lx
: hexadecimal long int type.%lu
: unsigned long int type.%lld
: decimal long long int type.%llo
: octal long long int type.%llx
: hexadecimal long long int type.%llu
: unsigned long long int type.%Le
: floating point number of type long double in scientific notation.%Lf
: floating point number of type long double.%n
: the number of strings that have been output. The placeholder itself is not output, only the value is stored in the specified variable.%o
: octal integer.%p
: pointer.%s
: string.%u
: unsigned integer (unsigned int).%x
: hexadecimal integer.%zd
:size_t
type.%%
: output a percent sign.
Output format
printf()
allows you to customize the output format of the placeholder.
(1) Delimited width
printf()
allows the minimum width of a placeholder to be qualified.
printf("%5d\n", 123); // output is " 123"
In the above example, %5d
means that the placeholder is at least 5 bits wide. If it is less than 5 bits, a space will be added in front of the corresponding value.
The output value is right-justified by default, i.e. the output will be preceded by a space; if you wish to change to left-justification and add a space after the output, you can insert a -
sign after the %
of the placeholder.
printf("%-5d\n", 123); // the output will be `123 "
In the example above, a space is added after the output 123
.
For decimals, this qualifier will limit the minimum display width of all numbers.
// output " 123.450000"
printf("%12f\n", 123.45);
In the above example, %12f
means that the output floating point number should occupy at least 12 bits. Since the default display precision for decimals is 6 decimal places, 2 spaces will be added to the head of the 123.45
output.
(2) Always display positive and negative signs
By default, printf()
does not display a +
sign for positive numbers, only a -
sign for negative numbers. If you want positive numbers to also output a +
sign, you can add a +
after the %
of the placeholder.
printf("%+d\n", 12); // output +12
printf("%+d\n", -12); // output -12
The above example, %+d
can ensure that the output value, always with a plus or minus sign.
(3) limit the number of decimal places
When outputting decimals, sometimes you want to limit the number of decimal places. For example, if you want to keep only two decimal places after the decimal point, the placeholder can be written as %.2f
.
// Output Number is 0.50
printf("Number is %.2f\n", 0.5);
In the above example, if you want the output to be 3 digits after the decimal point (0.500
), the placeholder should be written as %.3f
.
This can be used in conjunction with the qualified width placeholder.
// output as ` 0.50"
printf("%6.2f\n", 0.5);
In the above example, %6.2f
means that the minimum width of the output string is 6 and the number of decimal places is 2. So, there are two spaces at the head of the output string.
The two qualifying values, minimum width and number of decimal places, can both be replaced by *
, passed in via the printf()
argument.
printf("%*. *f\n", 6, 2, 0.5);
// Equivalent to
printf("%6.2f\n", 0.5);
In the example above, the two asterisks in %*. *f
's two asterisks are passed in through the two arguments 6
and 2
of printf()
.
(4) Outputting partial strings
The %s
placeholder is used to output the string, and by default it is all output. If you only want to output the beginning part, you can use %. [m]s
to specify the length of the output, where [m]
represents a number indicating the length of the desired output.
// Output hello
printf("%.5s\n", "hello world");
In the above example, the placeholder %.5s
means that only the first 5 characters of the string "hello world" are output, i.e. "hello".
Standard libraries, header files
Programs need to use functions that you don't necessarily need to write yourself, C may already come with them. The programmer can simply call these functions and save himself from having to write the code. For example, the function printf()
comes with the C language, so if you call it, you can output the content on the screen.
All these functions that come with the C language are collectively known as the standard library, because they are written in a standard way, and exactly what functions are included and how they should be used are defined, so that the code can be standardised and portable.
Different functions are defined in different files, which are collectively known as header files. If the system comes with a function, it must also come with a header file describing that function, for example, the header file for printf()
is the system's own stdio.h
. The header file is usually suffixed with .h
.
If you want to use a function, you must first load the corresponding header file, which is done with the #include
command. This is why stdio.h
must be loaded before printf()
can be used.
#include <stdio.h>
Note that the #include
statement to load a header file does not need to end with a semicolon, see the chapter on Preprocessors for details.