C Language Notes
Thanks to Frank for opening the door to modern C language for so many students
The blog post I wrote in June was too shallow; starting from this note, the content of my blog posts will all be raised to a new level!
The content comes from the free course by instructor Micro_Frank, and the notes are specifically based on what was taught in the lessons. If there is any infringement, please contact the blogger!
Chapter 1
First Program: C Language Execution Process
This program is a basic example in C that demonstrates how to output a line of text. The #include <stdio.h> statement includes the standard input/output library, int main() is the entry point of the program, printf("Hello World!\n"); is used to print a string, and return 0; indicates that the program ended successfully.
C Language Story · 1
Chosen Textbook: C Primer Plus
Recommended to read in English and Chinese side by side
C Language Story · 2
Declaration, Definition, Assignment
Identifiers
The compiler treats uppercase and lowercase letters as different characters
Microsoft Specific
Names that begin with two underscores or with one underscore followed by an uppercase letter.
Microsoft uses an underscore and an uppercase letter at the beginning of macro names, and uses double underscores at the beginning of Microsoft-specific keyword names.
Valid Identifiers
Keywords
Chapter 2 Data Types
Comments
Number Systems
Variables
Integers
Syntax: defined type identifier = value
How int Is Stored in Memory
Storage units in a computer:
1G = 1024MB
1MB = 1024KiB
1KiB = 1024Bytes
1024Bytes = 8Bit
|00000000|00000000|00000000|00000000|int|
0 is used to indicate sign, and in total it can represent values.
Floating-Point Numbers
Examples of floating-point numbers: 2.75, 3.16E7, 2e-8, etc.
How Does a Computer Store Floating-Point Numbers?
Floating-point number: sign (1) + fraction (23) + exponent (8), 32-bit int-like structure.
One Step: 3.14159 => , first convert it to an int-like form.
Two Step: How to store the exponent? = 256. From 0 to 255, numbers to the left of the bias 127 represent negative exponents, and the biased value is the exponent value.
float and double Types
The range of float is approximately between 3.4E-38 and 3.4E+38.
Decimals are usually > 1, so normalized floating-point numbers are often greater than 1. The mantissa (occupying the remaining bits) in standard floating-point representation is usually stored in the form 1.XXXX, with an implicit leading 1 (called the implicit leading bit).
Therefore the implicit mantissa length of float is 24 bits, and that of double is 53 bits.
Single precision (32-bit) - Double precision (64-bit)
If storage > precision required, choose double; if storage < precision requirement, choose float.
Printing Floating-Point Numbers
Floating-Point Rules in C99
Overflow of Floating-Point Numbers
NaN & Infinity
Round to Nearest Even (Banker’s Rounding)
double, long double: Difference Between Research and Industry
Comparison of Effective Precision of float and double: Principle and Calculation
float (single-precision floating-point): usually takes 4 bytes (32 bits), of which 1 bit is the sign bit, 8 bits are the exponent, and 23 bits are the mantissa (significant digits). The typical effective precision is about 7 decimal digits.
double (double-precision floating-point): usually takes 8 bytes (64 bits). 1 bit is the sign bit, 11 bits are the exponent, and 52 bits are the mantissa. The typical effective precision is about 15 to 16 decimal digits.
Floating-point representation follows the IEEE 754 standard. Its value can be expressed by the following formula:
sign: the sign bit, determines positive or negative. fraction: the mantissa, determines precision. exponent: the exponent, determines magnitude. bias: the offset; for float it is 127, and for double it is 1023.
Banks use fixed-point numbers (in MySQL databases).
char & ASCII
Escape Sequences and the Backslash \
| Escape sequence | Meaning |
|---|---|
| \a | Bell (alert) |
| \b | Backspace |
| \f | Form feed |
| \n | New line |
| \r | Carriage return |
| \t | Horizontal tab |
| \v | Vertical tab |
| ' | Single quote |
| " | Double quote |
| \ | Backslash |
| ? | Literal question mark |
| ** ooo | ASCII character in octal notation |
| \x hh | ASCII character in hexadecimal notation |
| \x hhhh | Unicode character in hexadecimal notation (when this escape sequence is used in a wide-character constant or Unicode string literal). For example, WCHAR f = L'\x4e00' or WCHAR b[] = L"The Chinese character for one is \x4e00". |
Boolean Type bool
Constants: const and #define Macros
Closing Remarks of Chapter 2
Chapter 3 Operators
Introduction to Operators
1. Arithmetic operators
2. Relational operators
| Operator | Relation Tested |
|---|---|
< | First operand is less than the second operand |
> | First operand is greater than the second operand |
<= | First operand is less than or equal to the second operand |
>= | First operand is greater than or equal to the second operand |
== | First operand is equal to the second operand |
!= | First operand is not equal to the second operand |
Data Objects: Lvalues and Rvalues
Multiple Assignment
Prefix and Postfix Increment/Decrement
Bitwise Shift Operators
Multiplication: Why are shift operators faster than direct multiplication?
Shift operators are faster than directly using the multiplication operator (*) mainly because of differences in their low-level implementation.
For int types you must be careful: left shift may cause overflow.
Logical True and False, C Relational Operators
Conditional (Ternary) Operator
Bitwise Operators & ^ |
| Operator | Description |
|---|---|
& | The bitwise AND operator compares each bit of its first operand to the corresponding bit of its second operand. If both bits are 1, the corresponding result bit is set to 1. Otherwise, the corresponding result bit is set to 0. |
^ | The bitwise XOR operator compares each bit of its first operand to the corresponding bit of its second operand. If one bit is 0 and the other bit is 1, the corresponding result bit is set to 1. Otherwise, the corresponding result bit is set to 0. |
| |
& bitwise AND
| bitwise OR
^ bitwise XOR
Bitwise NOT ~
Masks and Circuit-Controlled LED Practice
Logical Operators && ||
| Operator | Description |
|---|---|
&& | The logical AND operator produces the value 1 if both operands have nonzero values. If either operand equals 0, the result is 0. If the first operand of the logical AND operation equals 0, the second operand is not evaluated. |
|| | The logical OR operator performs an inclusive OR on its operands. If both operands are 0, the result is 0. If either operand has a nonzero value, the result is 1. If the first operand of the logical OR operation has a nonzero value, the second operand is not evaluated. |
Compound Assignment Operators
The operands of compound assignment operators can only be integer and floating-point types.
Comma Operator
Microsoft Learn
Output:
In the function call to func_one above, three arguments separated by commas are passed: x, y + 2, and z. In the function call to func_two, the parentheses force the compiler to interpret the first comma as the sequencing comma operator. This function call passes two arguments to func_two. The first argument is the result of the sequencing operation (x--, y + 2), which has the value and type of the expression y + 2; the second argument is z.
Precedence and Order of Evaluation
| Symbol ^1^ | Operation Type | Associativity |
|---|---|---|
[ ] ( ) . ->++ -- (postfix) | Expressions | Left to right |
sizeof & * + - ~ !++ -- (prefix) | Unary | Right to left |
| typecasts | Unary | Right to left |
* / % | Multiplicative | Left to right |
+ - | Additive | Left to right |
<< >> | Bitwise shift | Left to right |
< > <= >= | Relational | Left to right |
== != | Equality | Left to right |
& | Bitwise AND | Left to right |
^ | Bitwise XOR | Left to right |
| | Bitwise OR | Left to right |
&& | Logical AND | Left to right |
|| | Logical OR | Left to right |
? : | Conditional expression | Right to left |
= *= /= %=+= -= <<= >>= &=^= |= | Simple and compound assignment ^2^ | Right to left |
, | Sequencing | Left to right |
^1^ Operators are listed in order of decreasing precedence. If multiple operators appear on the same line or in one group, they have the same precedence.
^2^ All simple and compound assignment operators have the same precedence.
Expressions can contain multiple operators of the same precedence. When multiple such operators of the same precedence appear in an expression, evaluation is performed from right to left or from left to right, depending on the associativity of the operator. The direction of evaluation does not affect the result of expressions that contain multiple multiplicative (*), additive (+), or binary bitwise (&, |, or ^) operators at the same level. The language does not define the order of evaluation. If the compiler can guarantee consistent results, it may evaluate such expressions in any order.
Only sequencing (,), logical AND (&&), logical OR (||), conditional expressions (? :), and function-call operators constitute sequence points, ensuring that their operands are evaluated in a specific order. A function-call operator consists of a set of parentheses immediately following a function identifier. The sequencing operator (,) guarantees that its operands are evaluated from left to right. (The comma within a function call is not the sequencing comma operator and does not provide such guarantees.) For more information
Logical operators also guarantee left-to-right operand evaluation. However, they evaluate only the minimum number of operands needed to determine the result of the expression. This is called “short-circuit” evaluation. As a result, some operands in an expression may not be evaluated. For example, in the following expression
x && y++
Only if y++ is true (nonzero) is the second operand (x) evaluated. Therefore, if y is false (0), x is not incremented.
Examples
The following list shows how the compiler automatically groups several example expressions:
Expand table
| Expression | Automatic Grouping |
|---|---|
a & b ||c | (a & b) ||c |
a = b ||c | a = (b ||c) |
q && r ||s-- | (q && r) ||s-- |
In the first expression, the bitwise AND operator (&) has higher precedence than the logical OR operator (||), so a & b forms the first operand of the logical OR.
In the second expression, the logical OR operator (||) has higher precedence than the simple assignment operator (=), so b || c is grouped as the right operand in the assignment. Note that the value assigned to a is either 0 or 1.
The third expression shows a syntactically correct expression that may produce unexpected results. The logical AND operator (&&) has higher precedence than the logical OR operator (||), so q && r is grouped as an operand. Because logical operators guarantee left-to-right evaluation of operands, q && r is evaluated before s--. However, if q && r evaluates to a nonzero value, s-- is not evaluated and s is not decremented. If the fact that s is not decremented causes issues in the program, then s-- should appear as the first operand in the expression, or s should be decremented in a separate operation.
The following expression is illegal and will produce a diagnostic message at compile time:
| Illegal Expression | Default Grouping |
|---|---|
p == 0 ? p += 1: p += 2 | ( p == 0 ? p += 1 : p ) += 2 |
In this expression, the equality operator (==) has the highest precedence, so p == 0 is grouped as an operand. The conditional operator (? :) has the next highest precedence. Its first operand is p == 0, and its second operand is p += 1. However, the last operand of the conditional operator is treated as p instead of p += 2, because p matches the conditional operator more tightly than the compound assignment operator. Since += 2 has no left operand, a syntax error occurs. You should use parentheses to prevent such errors and to produce more readable code. For example, you can correct and clarify the previous example using parentheses as follows:
( p == 0 ) ? ( p += 1 ) : ( p += 2 )
See Also
Among unary operators, the prefix
&,-,+, etc. and*is the dereference operator
& in bitwise AND and the & prefix operator are different; the latter has higher precedence!
Chapter 3 Branching and Control
Decision Control
If the weather is fine — choose to go out and have fun;
Logical && ||;
Humans have decision-making ability; logical judgments let programs make choices!
The premise is: let the program judge whether the “weather condition” is true or false.
For example, a weather application:
Temperature < 30° Temperature > 30°
Programming language:
- Needs to be applied to real-world scenarios
- Flexibility, randomness
- It can’t be perfect; if something is claimed to be perfect, it must be a lie
if Statements and if-else
Short-Circuit Behavior of Logical AND/OR
State Machine: Managing Complex State Transitions
Difference Between switch-case and if-else
The Role of Loops in Daily Life
Difference Between do-while and while
Practical Use of do-while
Guess-the-Number Game with Random Numbers
continue Statement
Combined Use of continue and break in Conditional Judgments
First Look at the for Loop
Sum of Squares of Integers
Counting Down the Last Five Numbers
Factorial
Square Root
Prime Numbers
p118: Array Subscripts Must Be Constants at Definition Time
p119: Notes on Arrays
The following introduces common mistakes when using arrays:
p119: Notes on Arrays
The following introduces common mistakes when using arrays:
Error 1: Out-of-bounds access
Error 2:
Array Case: Scores
Unicode Character Encoding and Wide Character wchar
wchar.h\ Unicode character encoding and wide characterwchar\ The Chinese character set is GBK\ The specific storage principle is beyond the scope of discussion\ \n ASCII code\ Correspondingly, different languages, etc. use different encodings
locale.h Header File
Currency formats, time formats, etc., for example MM/DD/YYYY, DD/MM/YYYY
String collation and comparison differ in some languages.
p126 Two-Dimensional Arrays and Initialization with Implicit Size
p124 Array Case: Letter Frequency Count
Enhanced version: