[In-depth analysis of C language] Symbols (full)

1. Comments

Two notations for comments:

  1. // + content
  2. /*+content*/
  3. Explanation: /* will only match the nearest */.
int main()
{
    
    
	//这是一段注释
	/*这是一段注释*/
	return 0;
}

Explanation: Comments are deleted during the preprocessing phase ( precompilation to be precise ), and replaced by spaces, so the essence of comments is actually spaces . The purpose of comments is to improve the readability of the code .
4. Supplement:
1. Space: Space in C language is used as a separator for symbol recognition
2: The basic way for the preprocessor to identify symbols is the greedy method . The so-called greedy means that the compiler will recognize as many symbols as possible character , (that is to say, the way the compiler decomposes the program into symbols is to read in character by character from left to right , if the character may form a symbol, then read another character, and judge the two characters that have been read Whether the string composed of characters may be a part of a character; if possible, continue to read the next character, and judge whether the two characters that have been read may be a part of a symbol; if possible, continue to read the next character , repeat the above judgment until the string of read-in characters is no longer possible to form a meaningful character)—— <<C Traps and Defects>> , this is done to satisfy most cases, and a few cases We need to divide the symbols by ourselves, so how to divide them, of course, use spaces .

Example 1:

#include<stdio.h>
int main()
{
    
    	
	int a = 1;
	int* p = &a;
	int b = a/ *p;//注意:这里的/*之间需加一个空格,否则会被编译器判断为注释符号
	return 0;
}

Example 2:

int main()
{
    
    
	int a = 1;
	int b = 2;
	int c = a-- - b;//是a后置减减再减去b
	printf("%d\n", c);//答案是-1
	a = 1;
	b = 2;
	c = a - --b;//是b前置--,然后a再减去b
	printf("%d\n", c);//答案:0
	return 0;
}

Explanation: Questions like this kind of quasi-ambiguity sometimes bring us trouble.

Bad way of commenting:
Example 1:

#if 0
int main()
{
    
    
	printf("hello world\n");
	return 0;
}
#endif

Example 2:

int main()
{
    
    
	if (0)
	{
    
    
		printf("hello world\n");
	}
	return 0;
}

Explanation: This way of commenting is not obvious, so when reading the code, it is not sure whether this code is a comment , so it is not recommended to comment like this.

2. Continuation character and escape character

1. Line continuation character

Logical expression:

#include<stdio.h>
int main()
{
    
    
	int a = 1;
	int b = 1;
	int c = 0;
	int d = 1; 
	if (a == 1 &&\
		b == 1 &&\
		c == 0 &&\
		d == 1)
	{
    
    
		printf("hello world\n");
	}
	return 0;
}

Explanation: It is also possible to not have a continuation character, but this is like not writing a function parameter, which defaults to int, so it is more strict, and it is recommended to bring a continuation character . Note: no spaces
after the continuation character

String:

int main()
{
    
    
	char* p = "abcd\
efg";//这是为了处理比较长的字符串而准备的,我们这里就暂且用一下。
	printf("%s\n", p);//字符串的续行符是不会被打印出来的
	return 0;
}

2. Escape character

insert image description here

Explanation: \Here is the meaning of changing the original character, specifically there are 14 types above.
Note: A single \ cannot be printed. If you want to print, \ must be escaped, that is, \\.

Example 1:

#include <stdio.h>
int main()
{
    
    
	 printf("c:\code\test.c\n");
	 int len = strlen("c:\code\test.c\n");//这里的\是打不出来的
	 printf("%d",len);//len是13
    return 0;
}

explain:

1——c,
2——:
3——\c (note that in vs 2019, the \ plus character is considered an escape character by the compiler),
4——0,
5——d;
6——e,
7——\t,
8——e,
9——s,
10——t,
11—— . ,
12——c,
13——\n,

Example 2:

#include<stdio.h>
#include<string.h>
int main()
{
    
    
	printf("%d\n",strlen("c:\\code\\test.c\\n"));
	//这样能打印出\了,但是字符的个数比前面多了3个——总共16个字符
	printf("c:\\code\\test.c\\n");
	return 0;
}

Effect:
insert image description here
Example 3:

#include<stdio.h>
int main()
{
    
    
	printf("\"");//这里\是改变"的意思,而能被打印出来
	return 0;
}

Description: "will automatically match with the nearest "

3. Carriage return and line feed

1. Enter

Symbol: \r
Description: Refers to returning to the first element of the current line

2. Newline

Symbol: \n
Explanation: It is accurate to return to the same position of the next line of the current line.
Note: The line break implemented by the general compiler is: carriage return + line feed (line break mentioned above)

An interesting implementation of rotating the cursor:

#include<stdio.h>
#include<Windows.h>
int main()
{
    
    
	while (1)
	{
    
    
		printf("\\\r");
		Sleep(100);
		
		printf("|\r");
		Sleep(100);

		printf("-\r");
		Sleep(100);

		printf("/\r");
		Sleep(100);
	}
	return 0;
}

Four. Logical operators

Logical AND: &&
Explanation: One false is false, all trues are true (serial)
Logical OR: ||
Explanation: One true is true, all falses are false (parallel)
Operation sequence: from left to right

#include<stdio.h>
int my_print()
{
    
    
	printf("hello\n");
	return 1;
}
int main()
{
    
    
	int judge = 0;
	scanf("%d", &judge);
	judge && my_print();
	//输入0时,不执行my_print
	//输入1时,执行my_print
	//judge || my_print();
	//输入1时,不执行
	//输入0时,执行
	return 0;
}

Five. Bit operators and shift operators

The bitwise operator is a direct operation on the number in memory (complement code)
bitwise AND: &
Explanation: Only 1 is 1, and the rest are 0
Bitwise OR: |
Explanation: Only 0 is 0, and the rest are
1 Bit XOR: ^
Description: The same is 0, and the difference is 1
Bitwise inversion: ~
Description: 1 becomes 0, 0 becomes 1, including the sign bit.

Simple use:

int main()
{
    
    
	printf("%d\n", 1 & 2);//0
	//  01(二进制)
	//& 10
	//  00
	//答案是:0
	printf("%d\n", 1 | 2);//3
	//  01
	//& 10
	//  11
	//答案:3
	printf("%d\n", 1 ^ 2);//3
	//  01
	//^ 10
	//  11
	//答案:3
	printf("%d\n", ~-1);//0
	//  11111111 11111111 11111111 11111111
	//~
	//  00000000 00000000 00000000 00000000
	//答案:0
	return 0;
}

Shift operator
1. The operand itself will not be affected after the shift operator operation
2. The range of the shift operator operation is an integer

  1. Left shift operator
    Symbol: << (double arrows to the left)
    Function: Shift the whole complement to the left by n bits and discard, and add 0 to the right.
int a =1;
int b = a<<1;//这是将a的补码向左移动一位,

The complement of a: 0000000000000000000000000000001
The complement of b: 00000000000000000000000000000010
insert image description here
2. Right shift operator
Symbol: >> (double arrow to the right)

1. Arithmetic right shift
Function: shift the whole complement code to the right by n bits, the leftmost complement sign bit
Example:

int a =-1;
int b = a>>1:

insert image description here
A complement code of A: 1111111111111111111111111111111111111
Make complement: 1111111111111111111111111111111
1. Logic right shift
function: Move the supplement to the N position overall to the right.
insert image description here

Generally, the right shift is an arithmetic right shift (complement sign bit )

About sizeof's plastic improvement problem:

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

	char a = 0;
	printf("%d\n", sizeof(~a));//4
	printf("%d\n", sizeof(!a));//1
	printf("%d\n", sizeof(a&a));//4
	printf("%d\n", sizeof(a|a));//4
	printf("%d\n", sizeof(a^a));//4
	printf("%d\n", sizeof(a >>1));
	printf("%d\n", sizeof(a <<1));
	return 0;
}

Explanation: The bit operation conforms to the shift operator, which is calculated on the size of the integer.
Note: !a is 1 under VS, and 4 under Linux. Here we recommend understanding it as 4.

Classic application:
1. Use XOR and bitwise AND to realize addition

Explanation: The CPU also performs addition operations through XOR and bitwise AND.

#include<stdio.h>
int main()
{
    
    
	int begin = 0;
	int process = 0;
	int end = 0;
	scanf("%d%d", &begin, &end);
	process = end;
	while (process)//当没有进位信息,就停止循环
	{
    
    
		//先进行异或不保留进位信息
		end = begin ^ process;
		//获取进位信息,左移之后是进位
		process = (begin & process) << 1;
		//更新下一轮的加数信息
		begin = end;
	}
	printf("%d\n", end);
	return 0;
}

2. Use XOR to exchange two numbers

#include<stdio.h>
int main()
{
    
    
	int a = 1;
	int b = 2;
	printf("a==%d,b==%d\n", a, b);
	a = a ^ b;
	b = a ^ b;
	// b =a^(b^b)=a^0=a
	a = a ^ b;
	//a = b^(a^a)=b^0=b
	printf("a==%d,b==%d\n", a, b);
	return 0;
}

Explanation:
1. XOR supports commutative law and associative law
2.0 XOR with any number is equal to itself
3. Two identical numbers XOR is 0

3. Use bitwise AND to output the binary sequence

void ShowBites(int x)
{
    
    
	for (int i = 31; i >= 0; i--)
	{
    
    
		if (((x>>i) & 1)== 1)
		{
    
    
			printf("1");
		}
		else
		{
    
    
			printf("0");
		}
	}
}

4. Use XOR to change the specified number to 1

#include<stdio.h>
#define SPECIALBIT(x,y) ((x)|=(1<<(y-1))) 
int main()
{
    
    
	int a = 0;
	SPECIALBIT(a, 5);
	ShowBites(a);
	return 0;
}

5. Use bitwise AND to change the specified position to 0

#include<stdio.h>
#define SPECIALBITS(x,y) ((x)^=(1<<(y-1)))
int main()
{
    
    
	int a = 0xFFFFFFFF;
	SPECIALBITS(a, 5);
	ShowBites(a);
	return 0;
}

6. Front ++ and post ++

We generally say that pre- increment ++ first, and then use it , and post-increment ++ first use, and then add 1 , is this true?
Answer: It should be said that this is the case in most cases . This is just for the convenience of our memory. This situation is not absolute.
Examples of satisfied situations:

int main()
{
    
    
	int a = 0;
	int b = 1;
	b = a++;
	return 0;
}

Disassembly code of b=a++

insert image description here

int main()
{
    
    
	int a = 0;
	int b = 1;
	b = ++a;
	return 0;
}

insert image description here
Examples of unsatisfactory situations:

int main()
{
    
    
	int a = 0;
	++a;
	a++;
	return 0;
}

insert image description here
A typical question expression:

The so-called problem expression does not mean that there is a problem with the syntax of the expression, but that the calculation path of the expression is ambiguous, that is, there are multiple calculation paths.

#include<stdio.h>
int main()
{
    
    
	int a = 1;
	a = (++a) + (++a) + (++a);
	printf("%d\n", a);
	return 0;
}

Explanation: Here is the problem of the calculation order and priority of ++ and +.
There are two possibilities:
1. Calculate all ++ first, that is, first increment the value of a three times, and then add the value of a after auto-increment , the answer is 12, which is the result of running under VS
2. First calculate the first two ++, that is, first increment a twice, then add the first two a after the auto-increment, and finally calculate the value of a Increment by one, and then add the results of the previous two additions to the result of a self-increment at this time, that is, 3+3+4=10
This is the result of running under Linux.

7. Characters and strings

1. String
Description: C language does not have a string type , but a character type .

Strings mainly exist in two forms in C language:
1. Arrays
2. Character pointers
But strings are used in many scenarios.

int main()
{
    
    
	char* p ="abcdef";//p是字符串首字符的地址
	//说明:这里的字符串是不能进行修改的。
	char arr[]="abcdef";//字符串被放在数组中,字符串里面的字符是能修改的
	char c = "0123456"[1];//这是字符指针的形式。
	printf("%d\n",sizeof("abcdef");//这是以数组形式存在的,其大小是
	//字符串的字符个数
	printf("%d\n", sizeof(""));//里面有一个字符\0,所以是1
	return 0;
}

2. Character
Description: Character constants exist as integers , and character constants will be truncated if they are placed in character variables .
Note:
1. A character contains at most 4 characters ('abcd'), corresponding to 4 bytes
2. A character cannot be empty !

int main()
{
    
    
	printf("%d\n", sizeof('c'));//这是4个字节
	char c = 'c';
	printf("%d\n", sizeof(c));//这是1个字节
	printf("%d\n",sizeof(+c));//整形提升,4个字节
	//CPU运算是以整形大小的
	return 0;
}

Why does the ASCII code table exist?

Because the code was invented by foreigners, foreign characters are composed of 26 English characters, which also corresponds to the ASCII code table, why there are 26 uppercase and lowercase characters, and how to exchange information with the computer? Naturally, it is a character translated from the ASCII code table!

Eight./ and %

1. Four rounding methods

1. Round to 0
insert image description here

Function: trunc()
Parameter: double
Return value: double

#include<stdio.h>
#include<math.h>
int main()
{
    
    
	printf("%f\n", trunc(5.4));//5.0
	return 0;
}

2. Round towards negative infinity
insert image description here

#include<stdio.h>
#include<math.h>
int main()
{
    
    
	printf("%f\n", floor(5.4));//5.0
	return 0;
}

3. Round towards positive infinity
insert image description here

Function: ceil()
Parameter: double
Return value: double

#include<math.h>
int main()
{
    
    
	printf("%f\n", ceil(5.4));//6.0
	return 0;
}

4. Rounding off

Function: round()
Parameter: double
Return value: double

#include<math.h>
int main()
{
    
    
	printf("%f\n", round(5.4));//5.0
	return 0;
}

2. The difference and connection between modulus and remainder

The definition of remainder in mathematics is :

If a and d are two natural numbers and d is non-zero, it can be proved that there are two unique integers q and r satisfying a = q*d + r and 0 ≤ r < d . Among them, q is called the quotient and r is called the remainder.
Note: The remainder r here is greater than or equal to 0 .

Definition of remainder in computer

If a and d are two natural numbers and d is non-zero, it can be proved that there are two unique integers q and r that satisfy a = q d + r where q is called the quotient and r is called the remainder. Note: The remainder
here can be less than 0 , and the result of the quotient is rounded to 0. For example: 5/-2=-2.5, rounded to 0 is -2, and the / here is exactly the remainder Finding method: r=aq

d=5-(-2)*(-2)=5-4=1, which is to use the formula to find.

The / in C language is the remainder

Definition of modulo in computer

If a and d are two natural numbers and d is non-zero, it can be proved that there are two unique integers q and r that satisfy a = q d + r where q is called the quotient and r is called the remainder.
Explanation: a/d=q remainder r, the / here is exactly the modulo Note: the remainder
here can be less than 0 , and the result of the quotient is rounded towards negative infinity . For example: 5/-2=-2.5 , round to negative infinity to find the remainder of -3

: use the formula to find, r=aq d=5-(-3)*(-2)=5-6=-1.

Python's / is modulo

3. The case of different signs on both sides of /

1. Left positive right negative

Here r=aq d, a is the dividend, q is the quotient, and d is the divisor,
that is, a>0, d<0, q<0, q * d > 0, so you can write r=|a|-| q*d|,
1. When taking modulus, the quotient will actually be relatively small (negative number), and the absolute value will be relatively large, so |q*d|>|a|, so r is less than 0. 2. When
taking In other cases, the quotient will actually be relatively large (negative number), and the absolute value will be relatively small, so |q
d|<|a|, r is greater than 0.

2. Left minus right plus

Here r=aq d, a is the dividend, q is the quotient, and d is the divisor,
that is, a<0, d>0, q<0, q*d<0, so you can write r=|q*d| -|a|
1. When taking the modulus, the quotient will actually be relatively small (negative number), and the absolute value will be relatively large, so |q*d|>|a|, so r is greater than 0. 2. When taking the
remainder When , the quotient will actually be relatively large (negative number), and the absolute value will be relatively small, so |q
d|<|a|, r is less than 0.

Nine. Operator precedence

insert image description here

Guess you like

Origin blog.csdn.net/Shun_Hua/article/details/129595326