When learning C language, always remember that “the future is bright” and “look back often.” Looking back often is an important method for learning knowledge. It means that after learning new knowledge, do not forget to review and deepen your understanding of previous knowledge. This is often the hardest thing for students to do, yet it is the most important. Learning C language requires going through several repetitive processes to connect and accumulate the necessary C language knowledge.
1. Mastering C Language Operators and Order of Operations
This is the foundation for mastering “C Programming.” The operations in C language are very flexible and powerful, with a wider variety of operations than other programming languages. In terms of expressions, C is more concise than other programming languages, with self-increment, self-decrement, comma operations, and ternary operations making expressions simpler. However, beginners often find these expressions difficult to grasp due to a lack of understanding of operators and order of operations. When multiple different operations form an expression, the priority order and associativity rules become very important. In learning C language, as long as we classify these reasonably and identify the differences from what we learned in mathematics, remembering these operations will no longer be difficult. Some operators must be memorized after understanding, making them easier to use in the future, while others can be temporarily ignored and remembered when needed.
First, it is essential to clarify that operators are classified according to their priority. In “C Programming,” operators can be divided into 15 priority levels, from high to low, with priorities ranging from 1 to 15. Except for levels 2, 3, and 14, which are right-to-left associative, all others are left-to-right associative, determining the order of operations among operators of the same level.
2. Understanding the Four Program Structures of C Language
1. Sequential Structure
The sequential structure of program design is the simplest; it involves writing corresponding statements in the order to solve the problem. Its execution order is top-down, executing statements in sequence.
For example, if a = 3 and b = 5, to swap the values of a and b, it is like swapping the water in two cups, which requires a third cup. If the third cup is c, the correct program would be: c = a; a = b; b = c; The execution result is a = 5, b = 3. If the order is changed to: a = b; c = a; b = c; the execution result becomes a = b = c = 5, which does not achieve the desired goal. Beginners are most prone to making this error. The sequential structure can be used independently to form a simple complete program, such as the common input, calculation, output triplet. For example, to calculate the area of a circle, the program statements would be to input the radius r, calculate s = 3.14159*r*r, and output the area s. However, in most cases, the sequential structure is part of a program combined with other structures to form a complex program, such as compound statements in branching structures or loops in looping structures.
2. Branching Structure
Although the sequential structure can solve calculation and output problems, it cannot make judgments and choices. For problems that require making a judgment before choosing, a branching structure must be used. The execution of a branching structure is based on certain conditions to choose the execution path, rather than strictly following the physical order of statements. The key to designing a branching structure is to construct appropriate branching conditions and analyze the program flow. Based on different program flows, appropriate branching statements are selected. The branching structure is suitable for calculations involving logical relationships or comparative conditions. When designing such programs, it is often necessary to first draw a flowchart of the program and then write the source code based on the flowchart. This separates program design analysis from the language, simplifying the problem and making it easier to understand. The flowchart is drawn based on the analysis of the problem.
When learning branching structures, do not be confused by nested branches. As long as you correctly draw the flowchart and understand the functions of each branch, nested structures become manageable. Nesting is simply including branch statements within branches, which is not new knowledge. As long as the understanding of dual branches is clear, nested branches are not difficult. Below are a few basic types of branching structures.
① if(condition) { branch body } This branching structure can have a single statement in the branch body, in which case “{ }” can be omitted, or it can be multiple statements forming a compound statement. It has two branch paths: if the condition is true, execute the branch body; otherwise, skip the branch body. For example, to calculate the absolute value of x, based on the definition of absolute value, we know that when x >= 0, its absolute value remains unchanged, while when x < 0, its absolute value is the negative of x. Therefore, the program segment is: if(x < 0) x = -x;
② if(condition) { branch1 } else { branch2 } This is a typical branching structure. If the condition is satisfied, execute branch1; otherwise, execute branch2. Both branch1 and branch2 can consist of one or several statements. For example, to find the roots of ax^2 + bx + c = 0, we analyze: when b^2 – 4ac >= 0, the equation has two real roots; otherwise (b^2 – 4ac < 0), it has two conjugate complex roots. The program segment is as follows: d = b*b – 4*a*c; if(d >= 0) { x1 = (-b + sqrt(d)) / (2*a); x2 = (-b – sqrt(d)) / (2*a); printf(“x1=%8.4f,x2=%8.4f\n”, x1, x2); } else { r = -b / (2*a); i = sqrt(-d) / (2*a); printf(“x1=%8.4f+%8.4fi\n”, r, i); printf(“x2=%8.4f-%8.4fi\n”, r, i); }
③ Nested branch statements: The format is: if(condition1) { branch1 }; else if(condition2) { branch2 } else if(condition3) { branch3 } … else if(conditionn) { branchn } else { branchn+1 } Although nested branch statements can solve problems with multiple entries and exits, the structure becomes very complex after more than three levels of nesting, making it extremely inconvenient for reading and understanding the program. It is recommended to keep nesting within three levels; if more than three levels are needed, use the statements below.
④ switch statement: This statement is also a multi-branch selection statement. Which block is executed depends on the switch settings, i.e., which expression matches the constant expression. Unlike if…else statements, all branches are parallel in a switch statement. During program execution, it starts searching from the first branch; if it matches, it executes the following block, then the second branch, the third branch, and so on, until it encounters a break statement. If it does not match, it searches for the next branch for a match. Special attention should be paid to the reasonable setting of switch conditions and the appropriate use of the break statement when applying this statement.
3. Loop Structure
The loop structure reduces the workload of rewriting source code and is used to describe problems that require repeated execution of a certain algorithm. This is the program structure where computers can best demonstrate their advantages. C language provides four types of loops: goto loop, while loop, do-while loop, and for loop. These four loops can be used to address the same problem and can generally replace each other, but using goto loops is generally not recommended, as forcibly changing the program’s order often leads to unpredictable errors during execution. In our studies, we mainly focus on while, do…while, and for loops. The key to learning these three common loop structures is to clarify their similarities and differences for use in different situations. This requires understanding the format and execution order of each loop thoroughly. Once you understand the flowcharts of each loop, you will know how to replace them, such as rewriting a program using a for statement instead of a while loop example, which will enhance your understanding of their functions. It is especially important to ensure that the loop body includes statements that lead to termination (i.e., changing the value of the loop variable); otherwise, it may become an infinite loop, which is a common mistake for beginners.
After learning these three loops, you should clarify their similarities and differences: when using while and do…while loops, the initialization of the loop variable should occur before the loop body, while for loops generally initialize in statement 1; while and for loops check the expression before executing the loop body, whereas do…while loops execute the loop body first and then check the expression, meaning that the do…while loop body is executed at least once, while while and for loops may not be executed at all. Additionally, all three loops can use the break statement to exit the loop and the continue statement to end the current loop iteration, while loops constructed with goto statements and if cannot be controlled using break and continue statements.
The sequential structure, branching structure, and loop structure are not isolated from each other; loops can include branches and sequential structures, and branches can include loops and sequential structures. In fact, regardless of the structure, we can broadly consider them as a statement. In actual programming, these three structures are often combined to implement various algorithms and design corresponding programs. However, when the programming task is large, the resulting program tends to be lengthy and repetitive, leading to poor readability and difficulty in understanding. The solution to this problem is to structure C programs modularly.
4. Modular Program Structure
The modular program structure in C language is implemented using functions, which divides complex C programs into several modules, each written as a C function. The main function calls these functions, and functions can call other functions to solve a large problem in C programming. Therefore, it is often said: C program = main function + sub-functions. Hence, special attention should be paid to understanding and applying function definitions, calls, and return values, and reinforcing this through debugging.
3. Master Some Simple Algorithms
A significant part of programming involves analyzing problems, finding solutions, and then writing code in the corresponding programming language. This requires mastering algorithms. According to our “C Programming” syllabus, we are only required to master some simple algorithms. Once we grasp these basic algorithms, analyzing problems becomes easier. For example, swapping two numbers, comparing three numbers, selection sort, and bubble sort. This requires us to understand the intrinsic meanings of these algorithms.
Conclusion: Once we master the above aspects, as long as everyone can overcome difficulties, dislike for learning, prepare before class, focus during lectures, and practice with debugging, learning C language is not difficult.
Editor: He Jie
Reviewers: Fu Xu & Liang Yong
Editor-in-Chief: Yang Guang
(Images and text sourced from the internet)