HansJack

HansJack

C Language Notes

C Language Notes#

Thanks to Frank for opening the door to modern C language for a wide range of students

C.png 

Table of Contents

[TOC]


The blog posts written in June were too superficial. Starting from this note, the content of the blog articles will be elevated to a higher level!

Content comes from the free course by instructor Micro_Frank, and the notes are specifically derived from the content taught. If there is any infringement, please contact the blogger!

Chapter One#

First Program: C Language Execution Process#

#include <stdio.h>
int main()
{
	printf("Hello World!\n");

	return 0;
}

This program is a basic example of C language, demonstrating 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 the string, and return 0; indicates that the program has ended successfully.

C Language Story · 1#

Selected Textbook: C Primer Plus#

It is recommended to read in both English and Chinese

C primer plus

C Language Story · 2#

Declaration, Definition, Assignment#

#include <stdio.h>
int main()
{	// Declaration
	int number = 123;
	// Definition
	printf("%d\n", number);
	// Assignment
	return 0;
}	// Instructor Frank_PPT also discussed the use of the TAB key and tab characters in this section

The code is mainly a simple C program that includes the concepts of declaration, definition, and assignment. Here is a detailed analysis: c #include // Include standard input-output library - #include : This is a preprocessor directive that includes the standard input-output library, allowing the program to use functions like printf for input and output operations. c int main() { // Main function, entry point of the program - int main(): Defines the main function, where the execution of the C program begins. The return type is int, indicating that this function will return an integer value. c int number = 123; // Define an integer variable and initialize - int number = 123;: Here we declare and define an integer variable named number, initializing its value to 123. In C language, variable declaration and definition are usually done in a single statement. c printf("%d\n", number); // Print the value of variable number - printf("%d\n", number);: This line of code intends to output the value of the variable number, but it has an error. The correct usage should be printf("%d\n", number);. In this statement, %d is a format specifier used to output integer type data, and \n is a newline character. In the erroneous version, the string "number" is treated as plain text output instead of the variable's value. c return 0; // End the main function, returning 0 indicates successful execution of the program } - return 0;: This line of code indicates the end of the main function and returns 0 to the operating system, typically representing successful execution of the program. Corrected Code Based on the above analysis, the correct code should be: c #include int main() { int number = 123; // Define and initialize variable printf("%d\n", number); // Correctly print the value of the variable return 0; // Return 0, indicating the program is successful } ### Summary This code demonstrates the basic structure of C language, including variable declaration and definition, use of standard libraries, output format usage, and the return value of the main program. The only thing to note is the correct usage of the format string in printf.

Identifiers#

identifier:
	nondigit
 	identifier
	digit

nondigit:
 	_ a b c d e f g h i j k l m n o p q r s t u v w x y z
 	A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

digit:
 	0 1 2 3 4 5 6 7 8 9

The compiler treats uppercase and lowercase letters as different characters

add
ADD
Add
aDD

Microsoft Specific

Names that begin with two underscores or with one underscore followed by an uppercase letter.

Microsoft uses underscores and uppercase letters as prefixes for macro names and uses double underscores as prefixes for Microsoft-specific keyword names.

Valid Identifiers

j
count
temp1
top_of_page
skip12
LastNum

Keywords#

image-20240810175108706

image-20240810175028158

Chapter Two Data Types#

Comments#

// Line
    Comment

/*
        Block
    Comment
    Comment
*/

Number Systems#

Variables#

// int variable
#include <stdio.h>

int main(){
	// integer assignment
	int sun_flower = 9673;

	printf("The current value of sunshine: %d\n", sun_flower);

	return 0;
}

Integer Types#

Syntax: Defined Type Identifier = Value

int type storage in memory#

Computer storage units:

1G = 1024MB

1MB = 1024KiB

1KiB = 1024Bytes

1024Bytes = 8Bits

00000000000000000000000000000000int

0 is used to display positive and negative, which can represent $ 2^{32} - 1 $ values

#include <stdio.h>
int main()
{
	int number = 100;
	// Represented in decimal
	printf("Decimal: %d\n", number);

	printf("Octal: %o\n", number);

	printf("Hexadecimal (lowercase): %x\n", number);

	printf("Hexadecimal (uppercase): %X\n", number);

	return 0;
}

Floating Point Numbers#

Floating point numbers include: 2.75, 3.16E7, 2e-8, etc.

How does the computer store floating point numbers?#

Floating point number: Sign (1) + Fraction (23) + Exponent (8) int type 32 bits

One Step : 3.14159=> $ 314159×10^{-5} $ First convert to int type

Two Step : How to store the exponent?$ 2^{8} $ = 256 From 0 to 255, the number to the left of 127 is a negative exponent, and the bias is the exponent value.

The storage of floating point numbers in computers typically follows the IEEE 754 standard, which defines the representation of floating point numbers. A floating point number consists of three main parts: the sign bit, the exponent part, and the mantissa (or significant). Here is the general storage format for floating point numbers: 1. Sign bit: Occupies 1 bit, indicating the sign of the value. 0 represents a positive number, and 1 represents a negative number. 2. Exponent part: Occupies a certain number of bits (for example, 32-bit floating point uses 8 bits, and 64-bit floating point uses 11 bits), indicating the range of the value. The exponent is generally biased (i.e., added with a constant called the bias), allowing for the representation of negative exponent values. 3. Mantissa: Occupies the remaining bits. For standard floating point representation, the mantissa is typically stored in the form of 1.XXXX, implicitly having a leading 1 (called the implicit leading bit). In the storage structure of 32-bit floating point (single precision) and 64-bit floating point (double precision), the specific bit allocation is as follows: - Single precision (32 bits): - Sign bit: 1 bit - Exponent: 8 bits - Mantissa: 23 bits - Double precision (64 bits): - Sign bit: 1 bit - Exponent: 11 bits - Mantissa: 52 bits Using this format, computers can represent a very large range of values and precision for the fractional part, but floating point representation also has rounding errors and range limitations. In computers, floating point numbers are usually stored in binary form, meaning that they are saved and operated on based on binary values rather than decimal. This storage method makes operations on floating point numbers more efficient.

float and double types#

The range of float type is approximately between 3.4E-38 and 3.4E+38.

Decimal numbers are generally >1, so normalized floating point numbers are often greater than 1, Mantissa (occupying the remaining bits). For standard floating point representation, the mantissa is typically stored in the form of 1.XXXX, implicitly having a leading 1 (called the implicit leading bit).

Therefore the implicit length of the mantissa for float is 24 bits, and for double, it is 53 bits.

Single precision (32 bits) - Double precision (64 bits)

Storage > Precision choose double, Storage < Precision choose float

Printing floating point numbers#

#include <stdio.h>

int main() {

	float temperature = 36.5f;

	float humidity = 48.3f;

	float speed_of_sound = 343.5e2f;

	float length = 12.3f, width = 23.45f, height = 34.56f;

	printf("Temperature: %f\n", temperature);
	printf("Humidity: %f\n", humidity);
	printf("Speed of Sound: %f\n", speed_of_sound);
	printf("Length: %f x %f x %f\n", length, width, height);
// Loss of precision
// double %lf, float %f
	return 0;
}

Regulations on floating point numbers in C99#

#include <stdio.h>

int main () {

float num = 123.456;

printf("Using %%f: %f\n", num);

// %e %E scientific notation formatted output
printf("Using %%e: %e\n", num);
printf("Using %%E: %E\n", num);

// %a %A hexadecimal floating point p notation
printf("Using %%a: %a\n", num);
printf("Using %%A: %A\n", num);

return 0;
}

Overflow of floating point numbers#

#include <stdio.h>
#include <float.h>// Open to see

int main() {

	float max_float = FLT_MAX;

	float overflow = max_float * 1000.0f;
	// OverFlow overflow

	float min_float = FLT_MIN;

	float underflow = min_float / 1000.0f;
	// UnderFlow underflow

	printf("Maximum Float: %e\n", max_float);
	printf("OverFloat: %e\n", overflow);
	printf("Minimum Float: %e\n", min_float);
	printf("UnderFloat: %e\n", underflow);

	return 0;
}

Nan & Infinity#

#include <stdio.h>
#include <float.h>
#include <math.h>

int main() {

	// Positive infinity
	float positive_infinity = INFINITY;
	printf("Positive Infinity: %f\n", positive_infinity);

	// Negative infinity
	float negative_infinity = -INFINITY;
	printf("Negative Infinity: %f\n", negative_infinity);

	// Division by 0 results in infinity
	float num = 1.0f;
	float infinity = num / 0.0f;
	printf("0.0 / 0.0 = %f\n", nan);

	// Nan 0/0
	// float nan = 0.0f / 0.0f;
	// printf("0.0f / 0.0f =%f\n", nan)

	// Square root of negative number
	float negative_sqrt = sqrt(-1.0f);
	printf("sqrt(1.0f) = %f\n", negative_sqrt);

	return 0;
}

Round to nearest even (bankers' rounding)#

#include <stdio.h>

int main() {

	// Round half away from zero
	// IEEE 754
	// Round to nearest, ties to even
	// Banker's rounding

	// 3.14159
	float number = 3.14159f;
	printf("%.4f\n", number);

	// 3.15
	// 3.25
	return 0;
}

Difference between double and long double in research and enterprise#

#include <stdio.h>

int main() {

	// double

	// float loss of precision

	// 3D rendering

	// Interest NASA

	// Floating point constant 3.14
	// 3.14 defaults to double type, specifically noted as 3.14f

	return 0;

}

In computer science and programming, double and long double are two floating point data types used to represent numbers with decimals. Their usage in research and enterprise may sometimes have different focuses, mainly reflected in the following aspects:

  1. Precision Requirements:
  • Research: Scientific research often involves highly precise calculations, such as physical and chemical simulations. In such cases, long double may be prioritized to improve calculation accuracy and avoid errors in floating point operations.
  • Enterprise: In commercial applications, the precision requirements for floating point numbers are usually not as strict, and double can meet most needs, especially in financial calculations and statistical analyses.
  1. Performance Considerations:
  • Research: Research calculations may focus more on the accuracy of calculations rather than speed, but in some high-performance computing scenarios, it is still necessary to weigh the relationship between precision algorithms and computational performance.
  • Enterprise: Enterprise applications often pursue performance, response time, and resource utilization efficiency, so they may lean towards using double to improve computational speed while ensuring a certain level of precision.
  1. Platform Dependency:
  • Research: In the research field, researchers consider differences between different hardware platforms and take cross-platform compatibility into account when choosing floating point types.
  • Enterprise: Enterprises may focus more on software maintainability and development efficiency, typically choosing more commonly used and standardized double types to gain better development support and community resources.
  1. Language and Tool Support:
  • Research: Researchers may use specialized scientific computing libraries (such as NumPy, SciPy, etc.) that consider support for various floating point types in their design.
  • Enterprise: In enterprise environments, development teams may prefer to use generic data types, relying on standard libraries and storage processes, making double types more common.

In summary, although both double and long double are floating point types, their specific usage in research and enterprise may vary due to differences in requirements, performance, and platforms.

Comparison of effective precision between float and double: principles and calculations#

#include <stdio.h>

int main() {
 
	float float_num = 1.0 / 3.0;
	double double_num = 1.0 / 3.0;

	printf("Float precision: %20f\n", float_num);
	printf("Double precision: %.20lf\n", double_num);
	// Comparison of effective precision between float and double
	printf("Defined max precision for double: %d\n", FLT_DIG);
	printf("Defined max precision for float: %d\n", DBL_DIG);

	// 53 divided by log₂10  24 divided by log₂10  is the precision

}

float (single precision floating point): Typically occupies 4 bytes (32 bits) with 1 bit for the sign, 8 bits for the exponent, and 23 bits for the mantissa (significant digits). Typically, effective precision is about 7 decimal digits.

double (double precision floating point): Typically occupies 8 bytes (64 bits). 1 bit for the sign, 11 bits for the exponent, and 52 bits for the mantissa. Typically, effective precision is about 15 to 16 decimal digits.

The representation of floating point numbers follows the IEEE 754 standard. Its value can be represented by the following formula: [ \text = (-1)^{sign} \times (1 + fraction) \times 2^{exponent} ]

sign: Sign bit, determines positive or negative. fraction: Mantissa, determines the precision of the value. exponent: Exponent, determines the size of the value. bias: Bias, for float it is 127, for double it is 1023.

In banking, fixed-point numbers (database MySQL) are used.

char & ASCII#

#include <stdio.h>

int main() {

	char mych = 'a'; // Actually stored as int type, converting A to int type int(97)

	printf("mych: %c\n");

	// ASCII American Standard Code for Information Interchange generally uses 7 bits including 128 characters

}

Escape Sequences Backslash \#

Escape SequenceRepresents
\aBell (alarm)
\bBackspace
\fForm feed
\nNew line
\rCarriage return
\tHorizontal tab
\vVertical tab
\'Single quote
\"Double quote
\\Backslash
\?Text question mark
\ oooOctal representation of ASCII character
\x hhHexadecimal representation of ASCII character
\x hhhhHexadecimal representation of Unicode character (if this escape sequence is used for wide character constants or Unicode string text). For example, WCHAR f = L'\x4e00' or WCHAR b[] = L"The Chinese character for one is \x4e00".
Clear screen print("\033[2J");
Move cursor print("\033[%d;%dH", 3, 3);

Boolean Type bool#

#include <stdio.h>
#include <stdbool.h>

int main() {
	// true or false
	// Convert to 1 or 0

	bool is_game_win = true;
	bool is_game_over = false;

	return 0;
}

Constants const and #define macros#

#include <stdio.h>
#define PI 3.14

int main() {
	// Constants

	const double MAX_USER = 100;

	printf("PI: %lf\n", PI);

	return 0;

}

Conclusion of Chapter Two#

Chapter Three Operators#

Introduction to Operators#

1. Arithmetic Operators

2. Relational Operators

OperatorRelationship Tested
<The first operand is less than the second operand
>The first operand is greater than the second operand
<=The first operand is less than or equal to the second operand
>=The first operand is greater than or equal to the second operand
==The first operand is equal to the second operand
!=The first operand is not equal to the second operand

Data Objects Lvalue and Rvalue#

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main() {

	// Data objects
	// Lvalue
	// Rvalue
	// Operators
	uint32_t apple_box = 5;

	uint32_t orange_box = 5;

	printf("There are %" PRIu32 " apples in the apple box\n", apple_box);
	printf("There are %" PRIu32 " oranges in the orange box\n", orange_box);

	uint32_t total_fruit = apple_box + orange_box;

	printf("There are %" PRIu32 " fruits in the box\n", total_fruit);
 
	return 0;

}

Multiple Assignments#

Prefix and Postfix Increment and Decrement#

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main() {

	int32_t value = 5;
	int32_t result_1;
	int32_t result_2;

	// Postfix increment, assign first, then ++
	result_1 = value++;
	// Prefix decrement, -- first, then assign
	result_2 = --value;
	printf("After postfix increment, result_1 = %" PRIu32 ", result_2 = %" PRIu32 ", value = %" PRIu32 "\n", result_1, result_2, value);

	return 0;

}

Bitwise Shift Operators#

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdbool.h>

int main() {

	uint8_t num = 22;
	num >> 2; // High bits are filled with zero, low bits are pushed out

	return 0;
}
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdbool.h>

int main() {

	uint8_t num = 22;
	// num >> 2; High bits are filled with zero, low bits are pushed out

	uint8_t num = 22;
	printf("Original number: %" PRIu8 " (binary: 00010110)\n", num);

	uint8_t left_shifted = num << 2;
	printf("Left shifted by 2: %" PRIu8 " (binary: 01011000)\n", left_shifted);

	uint8_t right_shifted = num >> 2;
	printf("Right shifted by 2: %" PRIu8 " (binary: 00000101)\n", right_shifted);

	return 0;
}

Why are shift operations faster than direct multiplication?

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdbool.h>

int main() {

	uint8_t num = 25;

	// uint32_t result = num * 1024;
	printf("Result: %" PRIu32 "\n", result);
	// ALU is responsible for basic operations

	return 0;
}

The reason shift operations are faster than direct multiplication operations is mainly due to differences in their underlying implementations.

Here are some specific reasons:

Underlying Operations: Multiplication operations at the computer's low level are usually more complex than addition and shift operations. Multiplication requires more hardware resources and time because it involves multiple additions and possibly storing intermediate results. In contrast, shift operations only require simple adjustments of binary bit positions, which is typically a very fast operation.

CPU Instruction Set Optimization: Many modern CPUs provide dedicated instructions for performing shift operations, which are highly optimized at the hardware level. In contrast, multiplication instructions, while also optimized, generally have higher latency due to their complexity.

Specific Scenarios: For multiplication by powers of 2, such as multiplying by 2, 4, 8, etc., shift operations can replace multiplication. For example, multiplying by 2 can be done by left shifting by 1 bit, and multiplying by 4 can be done by left shifting by 2 bits. This substitution can significantly improve performance in specific cases.

Compiler Optimization: Many programming language compilers automatically replace certain multiplication operations (especially those by powers of 2) with corresponding shift operations during the optimization phase, thereby improving code execution efficiency.

In summary, while we typically do not need to worry about these details at a high level, understanding the efficiency differences of these operations can be helpful in performance-sensitive applications.

Note that left shifting an int type may lead to overflow.

Logical Truth and Falsehood, C Relational Operators#

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdbool.h>

int main() {

	int a = 10;
	int b = 20;
	// xxx ? xxx : xxx to determine true or false
	bool greater = a > b;
	printf("a > b: %d\n", greater);
	printf("a > b: %s\n", greater ? "true" : "false");

	bool less = a < b;
	printf("a < b: %d\n", less);
	printf("a < b: %s\n", less ? "true" : "false");

	bool not_equal = a != b;
	printf("a != b: %d\n", not_equal);
	printf("a != b: %s\n", not_equal ? "true" : "false");

	bool equal = a == b;
	printf("a == b: %d\n", equal);
	printf("a == b: %s\n", equal ? "true" : "false");

	bool greater_or_equal = a >= b;
	printf("a >= b: %d\n", greater_or_equal);
	printf("a >= b: %s\n", greater_or_equal ? "true" : "false");

	bool less_or_equal = a <= b;
	printf("a <= b: %d\n", less_or_equal);
	printf("a <= b: %s\n", less_or_equal ? "true" : "false");

	return 0;
}

Conditional Expression Operator#

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdbool.h>

int main() {

	int score = 89;

	printf("Your score level: %s\n", score >= 60 ? "Pass" : "Fail");

	return 0;
}
#include <stdio.h>
int main() { 
	int score = 85; 
	// You can modify this score as needed 
	const char* result = (score >= 90) ? "Excellent" : (score >= 85) ? "Good" : (score >= 60) ? "Pass" : "Fail"; 
	printf("%s\n", result); 

	return 0; 
}

Bitwise Operators & ^ |#

OperatorDescription
&The bitwise "and" operator compares each bit of its first operand with the corresponding bit of its second operand. If both bits are 1, the corresponding result bit is set to 1. Otherwise, it is set to 0.
^The bitwise "xor" operator compares each bit of its first operand with the corresponding bit of its second operand. If one bit is 0 and the other is 1, the corresponding result bit is set to 1. Otherwise, it is set to 0.
**``**

& Bitwise AND

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdbool.h>

int main() {

	int a = 12;
	int b = 25;

	// & Binary bit comparison, only outputs 1 if both are 1, for example
	printf("%d\n", 12 & 25);
	// Clear specific bits, check if a certain bit is 1

	return 0;
}

| Bitwise OR

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdbool.h>

int main() {

	int a = 2;
	int b = 5;

	// | Binary bit comparison, outputs 1 if there is a 1, for example 0111 
	printf("%d\n", a | b);
	// Set specific bits, combine flag bits

	return 0;
}

^ Bitwise XOR

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdbool.h>

int main() {

	int a = 2;
	int b = 10;

	// ^ Binary bit comparison, outputs 1 if one is 1 and the other is 0, for example 1000 
	printf("%d\n", a ^ b);
	// Logical XOR operation
	// Flip specific bits, swap two variable values, check differences

	return 0;
}

Bitwise NOT ~#

Masks and Circuit Remote Control LED Light Practice#

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdbool.h>

void print_binary(uint8_t num);

int main() {

	uint8_t status = 0b00001100;	// Initial status

	printf("Initial status: 0b");
	print_binary(status);
	printf("\t(Binary)\n");

	status = status & 0b11111011;	// Mask control
	printf("Final status: 0b");
	print_binary(status);
	printf("\t(Binary)\n");
	return 0;
}

void print_binary(uint8_t num) {
	for (int index = 7; index >= 0; index--) {
	    printf("%d", (num >> index) & 1);
	}
}

Logical Operators && ||#

OperatorDescription
&&The logical "and" operator produces a value of 1 if both operands are non-zero. If either operand is equal to 0, the result is 0. If the first operand of the logical "and" operation is equal to 0, the second operand is not evaluated.
`

Compound Assignment Operators#

The operands of compound assignment operators can only be of integer and floating-point types

#include <stdio.h>
/*
struct BigStruct {
	//..
	//..
};

void update(BigStruct& bs) {
	BigStruct temp = someExp();

	bs = bs + temp;

	bs += temp;

}
*/


int main() {

	int base_number = 8;
	int add_number = 2;
	int sub_number = 3;
	int mul_number = 2;
	int div_number = 5;
	int mod_number = 4;

	base_number += add_number;
	// In-place Modification

	base_number -=
	base_number *=
	base_number /=
	base_number %=
	base_number <<=
	base_number >>=
	base_number &=
	base_number |=
	base_number ^=

	return 0;

}

Comma Operator#

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdbool.h>

int main() {

	uint32_t a = 1, b = 2, c = 4;

	uint32_t result = (a += 1, b -= 1, c += 3);

	printf("a = %d, b = %d, c = %d, result = %d", a, b, c, result);

	return 0;

}

Microsoft Learn

// cpp_comma_operator.cpp
#include <stdio.h>
int main () {
   int i = 10, b = 20, c= 30;
   i = b, c;
   printf("%i\n", i);

   i = (b, c);
   printf("%i\n", i);
}

Output:

20
30

[collapse status="false" title="Microsoft Learn Explanation"]

The comma operator has left-to-right associativity. Two expressions separated by a comma are evaluated from left to right. The left operand is always evaluated, and all side effects are completed before evaluating the right operand.

In some contexts (such as function argument lists), the comma can be used as a separator. Do not confuse this use of the comma as a separator with its use as an operator; the two usages are entirely different.

Consider the expression e1, e2. The type and value of this expression are the type and value of e2; the result of evaluating e1 is discarded. If the right operand is an lvalue, the result is an lvalue.

In the usual cases where the comma is used as a separator (for example, in function or aggregate initializer argument lists), the comma operator and its operands must be enclosed in parentheses. For example:

C++ copy

func_one( x, y + 2, z );
func_two( (x--, y + 2), z );

In the function call to func_one, three parameters are passed, separated by commas: x, y + 2, and z. In the function call to func_two, the parentheses force the compiler to interpret the first comma as a sequencing operator. This function call will pass two parameters to func_two. The first parameter is the result of the sequencing operation (x--, y + 2), which has the value and type of the expression y + 2; the second parameter is z.

[/collapse]

Order of Operations and Precedence#

Symbol ^1^Operation TypeAssociativity
[ ] ( ) . ->
++ -- (postfix)
ExpressionLeft to Right
sizeof & * + - ~ !
++ -- (prefix)
UnaryRight to Left
typecastsUnaryRight to Left
* / %MultiplicationLeft to Right
+ -AdditionLeft to Right
<< >>Bitwise ShiftLeft to Right
< > <= >=RelationalLeft to Right
== !=EqualityLeft to Right
&Bitwise "and"Left to Right
^Bitwise "xor"Left to Right
``Bitwise "or"
&&Logical "and"Left to Right
``
? :Conditional ExpressionRight to Left
= *= /= %=
+= -= <<= >>= &=
^= `
=`Simple and Compound Assignment ^2^
,SequenceLeft to Right

^1^ Operators are listed in descending order of precedence. If multiple operators appear on the same line or in a 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 level appear in an expression, the evaluation will be performed according to the associativity of that operator, either from right to left or from left to right. The direction of evaluation does not affect the result of expressions that include multiple multiplications (*), additions (+), or binary bitwise (&, |, or ^) operators at the same level. The order of operations is not defined by the language. If the compiler can guarantee consistent results, it may evaluate such expressions in any order.

Only the sequence point operators (,), logical "and" (&&), logical "or" (||), conditional expression (? :), and function call operators constitute sequence points, ensuring that their operands are evaluated in a specific order. The function call operator is a set of parentheses immediately following the function identifier. The sequence point operator (,) ensures that its operands are evaluated in left-to-right order. (The comma operator in function calls is different from the sequence point operator and does not provide any such guarantees.) For more details, see Sequence Points.

Logical operators also ensure that their operands are evaluated in left-to-right order. However, they evaluate the minimum number of operands necessary to determine the result of the expression. This is called "short-circuit" evaluation. Therefore, some operands of the expression may not be evaluated. For example, in the expression

x && y++

the second operand (y++) is only evaluated if x is true (non-zero). Thus, if y is false (0), x does not increment.

Example

The following list shows how the compiler automatically binds multiple example expressions:

Expand Table

ExpressionAutomatic Binding
`a & b
`a = b
`q && r

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" operation.

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 will be either 0 or 1.

The third expression shows a correctly formatted expression that may generate 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 ensure that their operands are evaluated in left-to-right order, q && r is evaluated before s--. However, if the result of q && r is non-zero, s-- is not evaluated, and s does not decrement. If not decrementing s would cause problems in the program, s-- should be shown as the first operand of the expression, or s should be decremented in a separate operation.

The following expression is illegal and will generate a diagnostic message at compile time:

Illegal ExpressionDefault 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 expression operator (? :) has the next highest precedence. Its first operand is p == 0, the second operand is p += 1. However, the last operand of the conditional expression operator is treated as p rather than p += 2, because the match for p is more tightly bound to the conditional expression operator than the compound assignment operator. Since += 2 has no left operand, a syntax error occurs. You should use parentheses to prevent such errors and produce more readable code. For example, you can use parentheses to correct and clarify the previous example as follows:

( p == 0 ) ? ( p += 1 ) : ( p += 2 )

See Also

C Operators

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdbool.h>

int main() {

	int32_t result;

	result = a * b + c << d > e ? b : c * sizeof(++e) / sizeof(int32_t);

	printf("Result: %" PRId32 ", result);

	return 0;
}

Among unary operators, & - + etc. prefix * is the dereference operator

& Bitwise AND and prefix & are different, the latter has higher precedence!

Chapter Three Branching and Control#

Decision Control#

If the weather is nice — choose to go out;

Logic && || ;

Humans have decision-making abilities, and logical judgments allow programs to choose!

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 languages:

  • Must be applied to real environments
  • Flexibility, randomness
  • It is impossible to be comprehensive; if there is perfection, it must be a lie.

if Statement and if-else#

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdbool.h>

int main() {

	uint32_t number = 100;

	// if statement
	if (number > 10) {
		printf("This number is greater than 10!\n");
		printf("This number is greater than 10!\n");

	}

	if (number >= 100) {
		printf("This number is greater than or equal to 100!\n");

	} 
	else {
		printf("This number is less than 100!\n");

	}


	return 0;
}

Short-circuit Behavior of Logical AND and OR#

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdbool.h>

int main() {

	bool is_weather_sunny = false;
	bool is_venue_available = true;

	if (is_weather_sunny && is_venue_available) {
		printf("The event will proceed as scheduled!\n");
	}
	else {
		printf("The event cannot proceed as scheduled!\n");
		if (!is_weather_sunny) {
			printf("Reason: The weather is not sunny!\n");
		}
		if (!is_venue_available) {
			printf("Reason: No venue available!\n");
		}
	}

	return 0;
}
// Vending machine
// Only supports coins
#include <stdio.h>
#include <stdbool.h>
#include <inttypes.h>

int main(void)

{

	const uint32_t PRICE = 3;	// drink's price

	uint32_t balance = 0;		// now total_coin

	uint32_t coin;				// every coin in it

	puts("Drink's price is $5 please!");

	while (balance < PRICE)	// Before enough amount is entered
	{
		puts("Don't!");	// Refuse transaction

		scanf_s("%" PRIu32, &coin);


		if (coin == 1 || coin == 2 || coin == 5) // Determine coin type
		{
			balance += coin;	// Assign and add

			printf("You have inserted $%" PRIu32 "\n", balance);
		}
		else {

			printf("Sorry! We do not accept $%" PRIu32 " coins\n", coin);
		}
	}

	if (balance > PRICE) {
		printf("Change: %" PRIu32 "\n", balance - PRICE);
	}
	return 0;
}

#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <inttypes.h>

int main(void)
{

	// Player enters different conditions of rooms

	uint32_t coins = 15;
	bool is_vip = true;
	bool have_special_tool = false;

	if (is_vip) {
		puts("VIP Enter!\n");
	}
	else {
		puts("Not VIP Exit!\n");
	}

	if (coins >= 10 || have_special_tool) {
		puts("Enter!\n");
	}
	else {
		puts("Exit!\n");
	}
	return 0;
}

#include <stdio.h>
#include <stdbool.h>
#include <inttypes.h>

int main(void)
{
	const uint32_t all_laps = 100;

	uint32_t current_laps = 0;

	puts("Start!");

	while (current_laps < all_laps)
	{
		current_laps++;

		printf("Completed lap %" PRIu32 ".\n", current_laps);
	}
	return 0;
}

// Vending machine
// Only supports coins
#include <stdio.h>
#include <stdbool.h>
#include <inttypes.h>

int main(void)

{

	const uint32_t price = 10;	// drink's price

	uint32_t balance = 0;		// now total_coin

	uint32_t coin;				// every coin in it

	puts("Drink's price is $5 please!");

	while (balance < price)	// Only start the loop when enough amount is entered
	{
		puts("Don't!");	// Refuse transaction

		// Simulate coin insertion
		scanf_s("%" PRIu32, &coin);


		if (coin == 1 || coin == 2 || coin == 5) // Determine coin type
		{ 
			balance += coin;	// Assign and add
			printf("You have inserted $%" PRIu32 "\n", balance);
		}
		else {
			printf("Sorry! We do not accept $%" PRIu32 " coins\n", coin);
		}
	}

	if (balance > price) {
		printf("Change: %" PRIu32 "\n", balance - price);
	}
	return 0;
}

// Be sure to write printf to see the effect.

// When encountering loop problems
// Do not apply multiple times in the loop to avoid unnecessary errors



// Write a program to calculate the sum

#include <stdio.h>
#include <inttypes.h>

int main(void)
{
	uint32_t sum = 0;	// Set initial sum to 0

	uint32_t number = 1;	// First value of number

	while (number != 0)	// Set 0 as the method to exit the loop
	{
		scanf_s("%" PRIu32, &number);	// scanf reassigns number, the first value of number is actually not used.
		sum += number;
	}

	printf("The sum is %" PRIu32 "\n", sum);

	return 0;
}







#include <stdio.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdlib.h>
#include <limits.h>
#include <errno.h>

int main()
{
	uint32_t sum = 0;	// Set initial sum to 0

	char input[50];	// We will convert the user's input character to a number

	char* end;

	puts("Please enter a series of numbers, separated by enter, we will calculate their sum, output q to end");

	while (true)	// Set 0 as the method to exit the loop
	{
		errno = 0;

		puts("Enter a number:");

		scanf_s(" %49s", &input, 50);

		if (input[0] == 'q' && input[1] == '\0') {
			break;
		}

		long number = strtol(input, &end, 10);
		// Convert the input character to a number and add it to the total sum
		// The ASCII for 0 is 48
		if (end == input || *end != '\0') {
			printf("Invalid input, please enter a number or character q\n");

		}
		else if (errno == ERANGE || number < 0 || number > UINT32_MAX){
			printf("Number out of range! Please enter a positive integer less than or equal to %u\n", UINT32_MAX);
		}
		else {
			sum += (uint32_t)number;
		}

	}

	printf("The sum is %" PRIu32 "\n", sum);

	return 0;
}
#include <stdio.h>
#include <inttypes.h>
#include <stdbool.h>

int main()
{
	uint32_t sum = 0;	// Set initial sum to 0

	uint32_t number;	// First value of number

	puts("Please enter a series of numbers, separated by enter, we will calculate their sum, output 0 to end");

	while (true)	// Set 0 as the method to exit the loop
	{

		scanf_s(" %" PRIu32, &number);

		if (number == 0) {
			break;
		}

		sum += number;
	}

	printf("The sum is %" PRIu32 "\n", sum);

	return 0;
}

// Use of guard clauses: car rental case
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <inttypes.h>

void check_car_rent(uint8_t age, uint8_t driving_exp_years);

int main(void) 
{
	check_car_rent(22, 3);

	return 0;
}

void check_car_rent(uint8_t age, uint8_t driving_exp_years) {
// Guard clause
	if (age < 21) {
		puts("Does not meet the criteria, age is insufficient!");
		return;
	}

	if (driving_exp_years < 1) {
		puts("Does not meet the criteria, driving experience is insufficient!");
		return;
	}
}

// Simplifying logical expressions
#include <stdbool.h>
#include <inttypes.h>

int main(void) 
{
	// Logical expressions should be simplified!
	bool is_weekend = true;
	bool has_enter = true;

	if (!has_enter) {
		return 0;
	}

	return 0;
}

State Machine: Managing Complex State Transitions#

#include <stdbool.h>
#include <inttypes.h>

int main(void)
{
	// State machine: managing complex state transitions using switch case

	uint8_t traffic_state = 0;

	switch (traffic_state)
	{
	case 0:
		puts("red");
		traffic_state = 1;
		break;
	case 1:
		puts("yellow");
		traffic_state = 2;
		break;
	case 2:
		puts("green");
		traffic_state = 0;
		break;
	default:
		puts("???");
		break;
	}

	return 0;
}

Difference Between switch-case and if-else#

// Difference Between switch-case and if-else
#include <stdio.h>
#include <stdbool.h>
#include <inttypes.h>

int main(void)
{


	return 0;
}

The Role of Loops in Life#

// The Role of Loops in Life

#include <stdio.h>
#include <stdbool.h>
#include <inttypes.h>

int main(void)
{
	int32_t number;

	scanf_s("Please enter: %d %d %d", &number, &number, &number);// Do not use scanf in actual development
	// not write \n in it
	printf("The numbers you entered are: %d %d %d\n", number, number, number);

	return 0;
}


The Difference Between do-while and while#

// The Difference Between do-while and while

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdbool.h>

int main(void)
{
	uint32_t total_laps = 10;

	uint32_t current_laps = 0;

	puts("Penalty running starts!");

	do {

		current_laps++;
		printf("The runner completed lap %" PRIu32 "\n", current_laps);
	} while (current_laps < total_laps);

	return 0;
}




The Practical Role of do-while#

// The Practical Role of do-while

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdbool.h>

int main(void)
{

	uint32_t choice;

	do 
	{

		puts("**** Main Menu ****");
		puts("1. New Game");
		puts("2. Load Game");
		puts("3. Exit");
		scanf_s("%" PRIu32, &choice);

		switch (choice) 
		{
		case 1:
			puts("**** Creating a new game!");
			break;
		case 2:
			puts("**** Loading saved game!");
			break;
		case 3:
			puts("**** Exiting the game!");
			break;
		}

	} while (choice != 3);

	return 0;

}




Random Number Guessing Game Case#

// Random Number Guessing Game Case
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <time.h>
#include <stdlib.h>

int main(void)
{
	uint32_t secret_num, guess, status;
	char buffer[50];

	srand(time(NULL));
	// Generate a random number between 1-100
	secret_num = rand() % 100 + 1;

	puts("Take a guess!");

	do {
		puts("Please enter your guess:");

		fgets(buffer, sizeof(buffer), stdin);
		status = sscanf_s(buffer, "%d", &guess);
		// Guard clause
		if (status != 1) {
				puts("Invalid input!");
				continue;
		}

		if (guess < secret_num) {
			puts("Too low!");
		}
		else if (guess > secret_num) {
			puts("Too high!");
		}

	} while (guess != secret_num);

	printf("Congratulations, you guessed it right!");

	return 0;
}


Continue Statement#

// Continue Statement
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

int main(void) {

	uint32_t sum = 0;
	int32_t number;

	puts("Please enter a series of positive integers, you can enter a negative number, enter 0 to end");

	while (1) {
		puts("Please enter a number");

		scanf_s("%d", &number);

		if (number == 0) {
			break;
		}
		if (number < 0) {
			continue;	// Continue directly skips this loop
		}
		sum += number; // Count
	}
	printf("The result is: %" PRIu32 "\n", sum);

	return 0;

}

Using continue and break with Conditional Judgments#

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main() {
    uint32_t number;
    
    puts("Please enter a number (0-100), enter -1 to end the program");
    
    while (1) {
        puts("Please enter a number:");
        scanf_s("%d", &number);
        // Guard clause! Check condition to end
        if (number == -1) {
            break;
        }
        if (number < 0 || number > 100) {
            continue; // Skip the remaining part of this loop.
        }
        sum += number;
    }
    
    return 0;
}

Introduction to for Loop#

// Introduction to for Loop
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

int main(void)
{
	// for loop
	const uint32_t total_laps = 10;	// Target laps

	// uint32_t current_lap = 0;	Initialize current lap

	puts("The runner starts running");

	for (uint32_t current_lap = 0; current_lap <= total_laps; current_lap++) {
		printf("The runner completed lap %" PRIu32 " \n", current_lap);
	}

	return 0;

}

Sum of Squares of Integers#

// Sum of Squares of Integers
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

int main(void)
{
	 /*
		To calculate the sum of squares of all integers from 1 to n (n entered by the player)

	 */
	uint32_t number;

	uint32_t sum_of_squares = 0;

	puts("Enter integer n");

	scanf_s("%u", &number);

	for (uint32_t index = 1; index <= number; index++) {
		sum_of_squares += index * index;
	}

	printf("%" PRIu32 "\n", sum_of_squares);
	return 0;
}

Countdown from Five#

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

int main(void) {

	/*
		Star Avenue
		Countdown from five
	*/

	uint32_t start_number;
	
	puts("Please enter a positive integer");
	scanf_s("%" SCNu32, &start_number);

	puts("The countdown begins");
	for (uint32_t index_number = start_number; index_number > 0; index_number--)
	{
		printf("%" SCNu32 "\n", index_number);
	}
	puts("The countdown stops");
	return 0;
}
// Extended sleep
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <windows.h>

int main(void) 
{

	/*
		Star Avenue
		Countdown from five
	*/

	uint32_t start_number;
	
	puts("Please enter a positive integer");
	scanf_s("%" SCNu32, &start_number);

	puts("The countdown begins");
	for (uint32_t index_number = start_number; index_number > 0; index_number--)
	{
		printf("%" SCNu32 "\n", index_number);
        Sleep(1000);
	}
	puts("The countdown stops");
	return 0;
}

Factorial#

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <windows.h>
// Factorial

int main(void) {

	uint32_t number;
	uint32_t factorial = 1;

	puts("Please enter a positive integer:");
	scanf_s("%" SCNu32, &number);

	for (uint32_t index = 1; index <= number; index++) {
		factorial *= index;
	}

	printf("%" PRIu32 "! = %" PRIu32 "\n", number, factorial);

	return 0;
}

Square Root#

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <math.h>
#include <stdbool.h>

int main(void)
{
	double number = 4.00;

	printf("%lf\n", sqrt(121));

	return 0;
}

Prime Numbers#

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <math.h>
#include <stdbool.h>

int main(void)
{
	uint32_t num;

	bool is_prime = true;

	puts("Please enter a positive integer, except for 1, we will check if it is prime:");

	scanf_s("%" SCNu32, &num);

	if (num <= 1) {
		is_prime = false;
	}
	else {
		// for, check factors other than 1 and itself
		for (uint32_t i = 2; i * i <= num; i++) {
			if (num % i == 0) {
				is_prime = false;
				break;
			}
		}
	}
	return 0;
}
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <math.h>
#include <stdbool.h>

int main(void)
{
	uint32_t size;
	puts("Please enter the size of the pattern: ");
	scanf_s("%" SCNu32, &size);

	// Characteristics: length and width are the same
	puts("Printing square pattern");

	for (uint32_t i = 0; i < size; i++) {
		for (uint32_t j = 0; j < size; j++)
		{
			printf("* ");
		}
		printf("\n");
	}
	return 0;
}

This article is synchronized and updated to xLog by Mix Space
The original link is https://hansblog.top/posts/study-book/c-study


Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.