Course Content#
if Statement, switch Statement#
- (C Language Relational Operators)
- 0 → false; 1 → true
- false 👉 0, NULL(null), '\0'
- <= → =<
- ! Negation (Relational Operator)
- Note the distinction: Bitwise NOT operator ~ (Bitwise Operator)
- ⭐!! Double Negation: Logical Normalization
- Unify all true values to 1, false values remain 0
- Sequential Structure
- Omitted
- Branch Structure
IF Statement#
-
-
(Expression)
- Any expression has a logical return value
- For the assignment expression a = 123;
- The return value is the value of variable a, which is 123
-
{Code Block;}
- Understand what a statement is?
- Single Statement: A statement ending with “;”
- int a = 1, b = 234; // This is a statement, “,” separates into one expression
- Empty Statement: Only a “;”, has no effect
- Compound Statement
- Uses curly braces
- That is the code block👆
- Single Statement: A statement ending with “;”
- Understand what a statement is?
-
if else Statement
- Can be replaced with a ternary expression (conditional operator)
- ...? ...: ...;
- Can be replaced with a ternary expression (conditional operator)
SWITCH Statement#
-
-
Variable a must have a clear unique integer value as a mapping!
- Letters also have such mappings: ASCII code
-
After entering case, execute subsequent code in order
- Until encountering break, continue, or the end of the structure~
- No need to check if the following cases are satisfied
-
Default Branch
- When none of the cases are satisfied, it will enter, equivalent to the else of an if else statement
CPU Branch Prediction#
Introduced from LeetCode problem - Palindrome Integer
The captain's highly efficient code is as follows:
-
-
The red box implements x<0
- Used to filter integers less than 0, negative numbers are definitely not palindrome integers
-
This statement appears in the operating system kernel:
-
-
!!(x) Logical normalization, the result will only be 1 or 0
- The frequency of occurrence will inform the CPU processing the program
⭐CPU Execution Process Analysis
- C Language Program Execution Process: Compiled to generate an executable file → Loaded into memory → CPU executes
- Cache
- Level 1 Cache: Fastest speed, but smallest capacity
- Comparison of CPU Instruction Execution Methods
- Early Serial (Addressing, Instruction Pre-fetching, Writing Data, Executing, Writing Back to Memory)
- Today's Parallel
- The schematic diagram is as follows:
-
-
For 5 instructions
- Serial method requires 5 * 5 = 25 clock cycles
- Parallel method only requires 5 + 4 = 9 clock cycles
-
When there are many instructions, efficiency increases nearly 5 times
-
- Therefore! CPU prefers sequential structures
- Dislikes branch structures (should use if else statements sparingly)
- Branch prediction issues
- For parallel methods, the CPU does not know what the next step of the branch structure is, which step should be pre-loaded?
- The CPU actually loads the next step randomly
- Therefore, if the prediction is wrong, the subsequent work is wasted, and it has to return to reprocess
- The CPU actually loads the next step randomly
- And __builtin_expect() does exactly that: tells the CPU which branch situation is more likely to occur!!!
Loop Structure#
- WHILE Statement
- while () {Code Block;}
- Check first, then execute
- do {Code Block;} while (Expression); ← Pay attention to the semicolon!
- Executes at least once
- while () {Code Block;}
- FOR Statement
- for(Initialization; Loop Condition; Post-Execution Operation) {Code Block;}
- Makes the loop very elegant, consisting of three parts
- All three parts can be omitted
- For example: for(; ; );, which is equivalent to while (1);
- The above is an infinite loop, doing nothing
In-Class Exercise#
-
-
Remember to check for redundant condition checks
-
When input is invalid (e.g., "q"), it falls into an infinite loop problem
- Solutions and thought processes are detailed below: Thought Point 1
-
Code
-
Redundant Version
-
-
❗Here scanf's \n is a hidden danger! It needs to be removed; otherwise, it requires reading one more number
-
Because it reads \n only when inputting the next number
-
⭐Reference Blog: Why does using "%d\n" require reading one more number? — The pitfalls of scanf() function
-
-
-
Simplified Version
-
-
-
①
-
②
- Familiarize yourself with the characteristics of switch statement endings
- Code
-
-
-
Code
-
For the while method, if the first check is true, it is no different from the do...while method
-
-
Code
-
Highlight Notes#
- ⭐Perform redundant checks on conditional statements (trimming), usually can have more concise code
- For all cases checking if an expression is 0, you can directly use if (!Expression)
- For if (Expression) single statement, you can use logical AND
- (Expression) && Single Statement
- For example, i && printf(" "); to output a space in all iterations except the first
- The single statement cannot be {Code Block;}
- For if (Expression) single statement, you can use logical AND
- Replace if...else with a ternary operator
- For all cases checking if an expression is 0, you can directly use if (!Expression)
- Generally, define the loop variable i in the initialization part: int i = 0
- No need to place it in advance
- More standardized and concise: define the variable before using it, do not place it too far away
- Scope issues
- The variable is only used within the loop
- No need to place it in advance
- Is ++i faster than i++?
- Use ++i whenever possible
- From the perspective of the function stack: 👇
- ++i directly pushes the value of i+1 onto the stack
- While i++, first pushes i onto the stack, then pushes i+1
- Use ++i whenever possible
Code Demonstration#
Branch Structure (6.struct_program.cpp)#
-
-
a - b can replace a == b for equality
-
if else can be replaced with a ternary operator
-
-
Output 1: false
- What is the precedence of a++ and &&?
- ++ has a higher precedence than &&
- Why doesn't the () outside a++ raise the precedence of ++ over &&?
- It is prioritized
- The output false here is unrelated~
- For the if check, it should check a first, then go to ++
- The value of the a++ expression is the a without ++
- What is the precedence of a++ and &&?
-
Output 2: a = 1, b = 0
- ⭐Logical AND -- Short-circuit Rule
- As long as there is a false value in front, it will not proceed further [Smart approach]
- ⭐Logical AND -- Short-circuit Rule
-
-
(Continuing from a = 1, b = 0)
-
Output 1: true
-
Output 2: a = 2, b = 0
- ⭐Logical OR -- Long-circuit Rule
- As long as there is one true value in front, it will not proceed further
- To execute the subsequent expression, all preceding expressions must be false
- ⭐Logical OR -- Long-circuit Rule
-
-
Output method with spaces as separators (no space at the end)
- Method 1: If it is not the first loop, output a preceding space
- First better obtained: i == 0
- Can optimize line 43: i && printf(" ");
- Method 2: If it is not the last loop, output a trailing space
- Method 1: If it is not the first loop, output a preceding space
-
rand()
-
Need to include <stdlib.h>
-
Outputs a random unsigned number
- rand() % 100 can randomly output numbers from 0 to 99
-
⭐Actually fixed randomness
-
-
Set the random seed through srand()
-
srand(time(0))
- time(0)
- Get the current time, need to include <time.h>
- Accurate to seconds, the number of seconds since 1970.1.1
- time(0)
-
It can be seen that the value is changing, but there is no true randomness in computers
-
-
-
-
-
Optimized Version
-
The above code has three places that can be simplified! Both if statements can be removed
-
-
⭐~
- Bitwise operations and modulus conversion: % 2 is equivalent to & 1
- % (2 ^ n) is equivalent to & (2 ^ n - 1)
- +1 is equivalent to true value 1
- Short-circuit rule of logical AND
- Bitwise operations and modulus conversion: % 2 is equivalent to & 1
-
Loop Structure (7.cpp)#
Check Palindrome Integer (Decimal)
-
-
Remember to perform special checks for negative numbers!
-
What if you want to check for palindrome integers in binary?
-
Just change the circles to 2
- Computers actually store data in binary at the lowest level
- Regardless of the base, palindrome can be checked
-
Palindrome integer check in base
-
-
Calculate Integer Digits (Decimal)
- Subtle differences between while loop and do...while loop
- The key is whether the condition holds for the first loop~
-
- When inputting a non-zero number, digit and digit2 have no difference
-
- When inputting the number 0, there is a difference
-
-
So for the case of 0, check the number of digits
* Use do...while
* Or special check
-
- The key is whether the condition holds for the first loop~
Additional Knowledge Points#
-
switch Statement
- Variables cannot be declared after case
- Does the end of default also need to add break?
- Optional, adding break is for uniform style
- Python does not support switch statements
-
In C language, what will happen if there is no return statement at the end of the main function?
- Starting from C99, it has little effect; the standard requires it to be equivalent to automatically adding return 0;
- Before C99, if control reaches the end of the main function without return, it is undefined behavior.
-
Floating-point number comparison
- Do not directly use ==, it will be inaccurate; use the difference being less than a certain small value to compare
-
__builtin_expect() has more than 6 siblings
-
-
Bit weight determines the multiple of left and right shifts
- In decimal, left shift by one position, *10
- In binary, left shift by one position, *2
Thought Points#
-
💡 (Solution) For 5.if.cpp, i.e., in-class exercise 1. Inputting invalid values, such as the letter ‘q’, will lead to an infinite loop
-
Is it related to the ASCII code of ‘q’?
- No relation~
- Outputting ‘q’ in %d form looks like an address, and the fixed value during a single run should be a value randomly allocated when initializing n
- If a valid value is input first and then an invalid value, this value is the previous n value
- Because no value has actually been read in to change n
-
Cannot read the value ‘q’
- The return value of scanf is 0
- However, it will not move to the next input, similar to the infinite loop event of %[^\n] encountered in the first lecture
-
⭐Of course! You can also use getchar() to swallow this invalid value
- Is inputting qw invalid?
- Yes, it needs getchar() to swallow twice
- Is inputting qw invalid?
-
Revised Code
-
-
Placing getchar() inside if(!ret) is better, only swallowing characters when reading invalid characters
-
The code above: getchar** will swallow whitespace and invalid characters**
-
The code below: will only swallow invalid characters
-
- To demonstrate that the swallowed characters contain no whitespace, only invalid characters, a printf function is added
-
-
-
-
-
-
💡 Similarly, for 5.if.cpp (with loops, needs manual stop), when redirecting standard output using >output, there will be issues with output not being written to the redirected file
- The specific situation has been asked in the Pirate QA, looking forward to discussion: Under what conditions does output redirection write output to a file? (stdout, ./a.out > output, Ctrl+C/Ctrl+D)
- Ctrl+C does not write, Ctrl+D writes
Ctrl+C: The default interrupt key in Linux; when this key is pressed, the system sends an interrupt signal to the running program and shell.
Ctrl+D: The standard input/output EOF in Linux. When this symbol is encountered in standard input/output devices, the program considers it has reached the end of the file, thus ending input or output.
- If there is invalid input leading to a large amount of output, Ctrl+C can also write
- Question: Is this because the buffer is insufficient, forcing output to the output file in advance?
- This is the correct understanding
- Question: Then is the output written to the output file just the overflow output, or all output before Ctrl+C?
- Overflow output
- Question: Is this because the buffer is insufficient, forcing output to the output file in advance?
- Code 5.switch.cpp: Why does inputting letters cause an infinite loop?
- Same as 5.if.cpp, see Thought Point 1
Tips#
- OJ Problem Solving Method
- Write code in vim
- Use cat to display and copy the code
- Submit
- Classic Problem: Given year, month, day, determine if it is reasonable
- Is it necessary to use so many if else?
- You can use space to exchange time: store the number of days in each month in an array
- Refer to the textbook Chapter 6 Section 6.4