[C Language Elementary] ❤️ Teach you to use various operators in C language (proficient use + must be collected) ❤️

Kind tips

Hello everyone, I am Cbiltps. In my blog, if there are sentences that are difficult to understand or key points that are difficult to express in words , I will have pictures . So my blog with pictures is very important ! ! !

If you are interested in me please see my first blog !

Key points of this chapter

  1. Introduction to various operators.
  2. expression evaluation

start of text


1. Classification of operators


  • arithmetic operator
  • shift operator
  • bitwise operator
  • assignment operator
  • unary operator
  • relational operator
  • logical operator
  • conditional operator
  • comma expression
  • Subscript references, function calls, and structure members

2. Arithmetic operators


Arithmetic operators are: + - * / %
In addition to %the operator, several other operators can act on integers and floating-point numbers.

2.1 /Operators

#include <stdio.h>

int main()
{
    
    
	int ret = 9 / 2;//对于 /(除号) 两边都是整数,执行的整数除法
	double ret2 = 9 / 2;//它的值是什么?
	double ret3 = 9 / 2.0;//它的值是什么?
	printf("%d\n", ret);
	printf("%lf\n", ret2);
	printf("%lf\n", ret3);

	return 0;
}

The running results are as follows:
insert image description here
the second result is still 4.0, why?
因为操作数中有浮点数,才执行浮点数除法。

2.2 %Operators

%The operator is the modulo operator , also known as the remainder operator .

int ret4 = 10 % 4;
printf("%d", ret4);//打印出来是2

Note: %The operator can only be used for integer types


3. Bit shift operators


<< 左移操作符
>> 右移操作符

3.1 <<Left shift operator

int a = 5;
int b = a << 1;
printf("%d\n", b);//打印出来的是 10

    //要看懂下面的图解,要明白一些知识点:
    
    //移位操作符,移动的是二进制位
	//对于整数的二进制有3中表示形式:原码、反码、补码
	
	//正整数 - 原码、反码、补码相同
	//负整数
	
	//原码 - 直接按照数字的正负写出的二进制序列
	//反码 - 原码的符号位不变,其他位按位取法得到的
	//补码 - 反码+1
	
	//整数 在内存中存储的是二进制的补码

insert image description here
If it is a negative number, look at the code:

int c = -1;
int d = c << 1;
printf("%d\n", d);//打印的是原码的值,打印出来是 -2

	//10000000000000000000000000000001 - 原码
	//11111111111111111111111111111110 - 反码
	//11111111111111111111111111111111 - 补码

insert image description here
Shift rules:左边抛弃、右边补0

Regarding the original code, inverse code, and complement code , please read another advanced blog I wrote !

3.2 >>Left shift operator

Shift rules:
1. Logical shift: 左边用0填充,右边丢弃
2. Arithmetic shift:左边用原该值的符号位填充,右边丢弃

Example:

int a = 5;
int b = a >> 1;
printf("%d\n", b);//打印出来的是 2

insert image description here
Here's another example with negative numbers :

int c = -1;
int d = c << 1;
printf("%d\n", d);//打印出来还是 -1

insert image description here
Here, the original sign bit is added, so VS2019 uses arithmetic right shift!

Warnings ⚠:
1: For the shift operator, 不要移动负数位, this is undefined by the standard.
2: Either 被移动数or 移动的位数must be an integer.

For example ( wrong demo):

int num = 10;
num>>-1;//error

4. Bitwise operators


Bitwise operators are:

  • &bitwise AND
  • |bitwise or
  • ^bitwise XOR

Note: Their operands must be integers.

4.1 &Bitwise AND operator

Calculation rules:
1: As long as there is 0 on the binary bit, it is 0
2: Two of the binary bits are 1 at the same time, that is 1

	int a = 3;
	int b = -2;
	int c = a & b;
	printf("%d\n", c);//打印出来是 2
	
	//%d - 说明我们要打印c的值,以有符号的形式
	
	//00000000000000000000000000000011 -3的原码
	//11111111111111111111111111111110 -2的补码
	//00000000000000000000000000000010 这个数是2

4.2 |Bitwise OR operator

Calculation rules: as long as there is 1 in the binary bit, it is 1

int a = 3;
int b = -2;
int c = a | b;
printf("%d\n", c);//打印 -1

	//00000000000000000000000000000011 -3的原码
	//11111111111111111111111111111110 -2的补码
	//11111111111111111111111111111111

	//11111111111111111111111111111111 补码
	//11111111111111111111111111111110 反码
	//10000000000000000000000000000001 原码 它的值是-1

4.3 ^Bitwise XOR operator

Calculation rules: the same binary bit is 0, and the difference is 1

int a = 3;
int b = -2;
int c = a ^ b;//打印出来是 -3
printf("%d\n", c);

	//00000000000000000000000000000011 -3的原码
	//11111111111111111111111111111110 -2的补码
	//11111111111111111111111111111101

	//11111111111111111111111111111101 补码
	//11111111111111111111111111111100 反码
	//10000000000000000000000000000011 原码 它的值是-3

A perverted interview question:

A temporary variable (the third variable) cannot be created to exchange two numbers.

#include <stdio.h>

int main()
{
    
    
	int a = 3;
	int b = 5;
	printf("交换前:a=%d b=%d\n", a, b);

	a = a ^ b;
	b = a ^ b;
	a = a ^ b;

	printf("交换后:a=%d b=%d\n", a, b);
	return 0;
}

Idea diagram:
insert image description here

Note: The readability of the code written in this way is not good enough, and it only applies to integer types


5. Assignment operator


The assignment operator allows you to get a value that you were not satisfied with before, that is, you can reassign yourself .

int weight = 120;//体重
weight = 89;//不满意就赋值

double salary = 10000.0;
salary = 20000.0;//使用赋值操作符赋值

Assignment operators can be used consecutively, for example:

int a = 10;
int x = 0;
int y = 20;
a = x = y + 1;//连续赋值

How does this code feel?

Then write like this:

x = y + 1;
a = x;

Much cleaner and easier to debug .

Compound assignment operator:

  • +=
  • -=
  • *=
  • /=
  • %=
  • <<=
  • &=
  • |=
  • ^=

These operators can be written as composite effects, such as:

int x = 10;
x = x + 10;

x += 10;//复合赋值

6. Unary operators


A unary operator is an operator with only one operand

6.1 Various unary operators

!logical inversion

-negative value

+positive value

&take address

&arr[0];//数组首元素的地址
&arr[9];//取出的是第10个元素的地址
&arr;//取出数组的地址

sizeofthe type length of the operand in bytes

  • sizeof is an operator, not a function
  • sizeof is to calculate the memory size (unit: byte) of a variable or type created variable, and the unit has nothing to do with what data is stored in the memory
//以下几种写法都是一样的
printf("%d\n", sizeof(a));//4
printf("%d\n", sizeof a);//4
printf("%d\n", sizeof(int));//4
//这里有一个问题;
int a = 5;
short s = 10;
printf("%d\n", sizeof(s = a + 2));//打印出来是 2
printf("%d\n", s);  //打印出来是 10  因为:sizeof 内部的表达式不参与运算

insert image description here

~Bitwise inverse of a number

  • Including the sign bit can also be bitwise reversed
#incluide <stdio.h>

int main()
{
    
    
	int a = 0;
	//00000000000000000000000000000000
	int b = ~a;
	printf("%d\n", b);

	//00000000000000000000000000000000
	//11111111111111111111111111111111 所有位按位取反
	// 
	//11111111111111111111111111111110 反码
	//10000000000000000000000000000001 原码
	//-1
	return 0;
}

--front, rear--

  • Front - -: first - -, then use
int a = 10;
int b = a--;
printf("%d\n", b);//这里打印出来还是 10
  • Back - -: use first, then - -
int a = 10;
int b = --a;
printf("%d\n", b);//这里打印出来才是9

++front, rear++

  • Pre ++: ++ first, then use
  • Postfix ++: use first, then ++

Be careful : don't write code like this (garbage code), you will be fired by the company!

int main()
{
    
    
	int a = 1;
	int b = (++a) + (++a) + (++a);//err
	printf("b=%d\n", b);

	return 0;
}

The two compilers are different here!
insert image description here

*Indirect access operator (dereference operator), can &be used in conjunction with fetching address

( 类型) type conversion

int a = (int)3.14;//默认写出的浮点数是double的,所以可以强制转换
printf("%d\n", a);
return 0;

6.2 sizeof and arrays

Let's look at a question and see how much they output respectively:

#include <stdio.h>

void test1(int arr[])//它的本质数是(int* arr[])
{
    
    
	printf("%d\n", sizeof(arr));//传的是首元素的地址
}

void test2(char ch[])
{
    
    
	printf("%d\n", sizeof(ch));//(4)
}

int main()
{
    
    
	int arr[10] = {
    
     0 };
	char ch[10] = {
    
     0 };
	
	printf("%d\n", sizeof(arr));//数组名单独放在sizeof内部,数组名表示整个数组
	printf("%d\n", sizeof(ch));//(3)

	test1(arr);
	test2(ch);

	return 0;
}

Output result:
insert image description here
For more knowledge about arrays , please see my last blog !


7. Relational operators (the following operators do not appear in the catalog alone)


Relational operators only make sense when compared between the same kind!

  • >
  • >=
  • <
  • <=
  • != for testing "not equal"
  • == for testing "equal"

These relational operators are relatively simple, there is nothing to talk about, but we should pay attention to the pitfalls when using some operators.
Note: When programming =and ==Wrong, it will lead to errors!


8. Logical operators


  • && Logical AND
    If false always false:
int a = 0;
int b = 3;
int c = a && b;//只判断真假,所以打印出来是 0
  • || Logical or
    one true must be true:
int a = 0;
int b = 3;
int c = a || b;
printf("%d\n", c);//打印出来是 1

Let’s take a look at a 360 written test question:

#include <stdio.h>

int main()
{
    
    
	int i = 0, a = 0, b = 2, c = 3, d = 4;
	i = a++ && ++b && d++;
	//i = a++||++b||d++;
	printf(" a = %d \n b = %d \n c = %d \nd = %d\n", a, b, c, d);//打印出来的是1 2 3 4
	
	return 0;
}

Diagram of thinking:
insert image description here
If it is logical or :

#include <stdio.h>

int main()
{
    
    
	int i = 0, a = 0, b = 2, c = 3, d = 4;
	i = a++ || ++b || d++;
	printf(" a = %d\n b = %d \n c = %d\n d = %d\n", a, b, c, d);//打印错来的是1 3 3 4
	
	return 0;
}

Idea diagram:
insert image description here


9. Conditional Operators


The conditional operator is also called the ternary operator

exp1 ? exp2 : exp3

int a = 0;
int b = 0;

if (a > 5)
	b = 3;
else
	b = -3;
	
//这里有更简单的写法:
(a > 5) ? (b = 3) : (b = -3);//直接搞定

10. Comma expressions


exp1, exp2, exp3, …expN

Comma expressions are multiple expressions separated by commas.
Comma expression rules: 从左向右依次执行,整个表达式的结果是最后一个表达式的结果.

Code demo:

//代码1
int a = 1;
int b = 2;
int c = (a>b, a=b+10, a, b=a+1);//c是多少?看的是最后一个表达式

//代码2
if (a =b + 1, c=a / 2, d > 0)//最后一个表达式判断的是 d > 0
//代码3
a = get_val();
count_val(a);
while (a > 0)//注意;这样写非常的冗余
{
    
    
	//业务处理
	a = get_val();
	count_val(a);
}

//如果使用逗号表达式,改写:
while (a = get_val(), count_val(a), a > 0)
{
    
    
    //业务处理
}

11. Subscript references, function calls, and structure members


[ ]Subscript reference
operator Operands: an array name + an index value

int arr[10];//创建数组
arr[9] = 10;//实用下标引用操作符。
//[ ]的两个操作数是arr和9。
//下面表达的意思都是相同的 
arr[4] -- > *(arr+4) --> *(4+arr) --> 4[arr]

( )function call operator

Accepts one or more operands : the first operand is the function name, and the remaining operands are the parameters passed to the function.

void test()
{
    
    
	printf("hehe\n");
}

int main()
{
    
    
	test();//这里就是函数调用操作符
	return 0;
}

结构成员访问操作符

  • .Struct variable.Member name
  • ->Structure pointer -> member name
#include <stdio.h>

struct Book
{
    
    
	char name[20];
	float price;
	char id[10];
};

void print1(struct Book b)
{
    
    
	printf("书名: %s\n", b.name);//在这里访问结构体成员
	printf("价格: %f\n", b.price);
	printf("书号: %s\n", b.id);

	//*(b.name);
}

void print2(struct Book* pb)
{
    
    
	/*printf("书名: %s\n", (*pb).name);
	printf("价格: %f\n", (*pb).price);
	printf("书号: %s\n", (*pb).id);*/

	printf("书名: %s\n", pb->name);//也可以这样访问
	printf("价格: %f\n", pb->price);
	printf("书号: %s\n", pb->id);
}

int main()
{
    
    
	struct Book b = {
    
    "C语言程序设计", 55.5f, "C20190201"};
	print2(&b);
	//print1(b);

	//结构成员访问操作符
	//结构变量.成员名
	//结构体指针->成员名
	//(*结构体指针).成员名

	return 0;
}

12. Expression evaluation


The order in which expressions are evaluated is determined in part by the precedence and associativity of operators . Likewise, operands of some expressions may need to be converted to other types during evaluation .

12.1 Implicit type conversions

Integer arithmetic in C is always performed with at least the precision of the default integral type .

To achieve this precision, character and short integer operands in expressions are converted to plain integer types before use , a conversion known as integer promotion .

Significance of integer promotion:

The integer operation of the expression must be executed in the corresponding operation device of the CPU. The byte length of the operand of the integer arithmetic unit (ALU) in the CPU is
generally the byte length of int, and it is also the length of the general-purpose register of the CPU.

Therefore, even if the addition of two char types is performed by the CPU, it must first be converted to the standard length of the integer operand in the CPU
.

It is difficult for a general-purpose CPU (general-purpose CPU) to directly add two 8-bit bytes (although there
may be such byte addition instructions in machine instructions). Therefore, the various integer values ​​in the expression whose length may be smaller than int must be converted
to int or unsigned int before being sent to the CPU for calculation.

How to carry out overall improvement?
整形提升是按照变量的数据类型的符号位来提升的

  • Integer promotion for negative numbers:
char c1 = -1;
//变量c1的二进制位(补码)中只有8个比特位:
//1111111
//因为 char 是有符号的 char
//所以整形提升的时候,高位补充符号位,即为1
//提升之后的结果是:
//11111111111111111111111111111111
  • Integer promotions for positive numbers:
char c2 = 1;
//变量c2的二进制位(补码)中只有8个比特位:
//00000001
//因为 char 是有符号的 char
//所以整形提升的时候,高位补充符号位,即为0
//提升之后的结果是:
//00000000000000000000000000000001

Notice:无符号整形提升,高位补0

//举例:
#include <stdio.h>

int main()
{
    
    
	char a = 3;//a是1byte - 8bit
	//00000000000000000000000000000011
	//00000011 - a
	char b = 127;//b是1byte - 8bit
	//00000000000000000000000001111111
	//01111111 - b
	
	//a和b都是char类型,自身大小的都是1byte,所以这里计算的时候要进行整型提升
	//00000000000000000000000000000011 a整形提升
	//00000000000000000000000001111111 b整形提升
	//00000000000000000000000010000010 相加后
	//
	char c = a + b;
	//10000010 - c
	//11111111111111111111111110000010 整形提升后的是补码
	//11111111111111111111111110000001 反码
	//10000000000000000000000001111110 原码
	//-126
	
	printf("%d\n", c);

	return 0;
}

The values ​​of a and b are promoted to ordinary integers before the addition operation is performed;
after the addition operation is complete, the result is truncated before being stored in c.

12.2 Arithmetic conversions

If the operands of an operator are of different types, the
operation cannot proceed unless one of the operands is converted to the type of the other. The hierarchy below is called ordinary arithmetic conversions .

1.long double
2.double
3.float
4.unsigned long int
5.long int
6.unsigned int
7.int

If the type of an operand ranks lower in the above list, it must first be converted to the type of the higher-level operand before performing the operation.

int a = 4;
float f = 4.5f;
float r = a + f;
//a首先转换成 float类型 然后和f相加

Warning: Arithmetic conversions need to be reasonable, otherwise there are some potential problems.

float f = 3.14;
int num = f;//这样隐式转换,会有精度丢失

12.3 Properties of operators

There are three factors that affect the evaluation of complex expressions:

  1. operator precedence
  2. operator associativity
  3. whether to control the order of evaluation

Which of two adjacent operators is executed first?
取决于他们的优先级;如果两者的优先级相同,取决于他们的结合性.

//两个相邻的操作符:
int a = 2;
int b = 4;
int c = a * b + 3;// * 的优先级比 + 高,所以先算乘法,再算加法 
//两者的优先级相同:
int a = 2;
int b = 4;
int c = a + b + 3;//两者优先级相同,看它们的结合性(看下面的操作符优先级表),所以是从左到右加

Operator precedence table ( 由高到低展示):
insert image description here

Then, think about it, are you able to perform calculations after you have mastered the operators 优先级, 结合性, and what 是否控制求值顺序was mentioned earlier in the expression? is the only result?整型提升算数转换

Unified answer:答案是否定的

Look at a few problematic expressions:

//表达式的求值部分由操作符的优先级决定
//问题表达式1:
a*b + c*d + e*f

insert image description here
Note: When calculating code 1, since * has a higher priority than +, it can only be guaranteed that the calculation of * is earlier than +, but the priority cannot determine that the third * is
executed earlier than the first +.

//问题表达式2
c + --c;

insert image description here
Note: As above, the priority of the operator can only determine the operation of the self-decrement – ​​in front of the operation of +, but we have no way
to know acquisition of the left operand of the + operator is evaluated before or after the right operand , so the result is unpredictable and ambiguous
.

//问题代码3-非法表达式
int main()
{
    
    
	int i = 10;
	i = i-- - --i * (i = -3) * i++ + ++i;
	printf("i = %d\n", i);
	return 0;
}

Some big guys tested the results under different compilers and found that they are different!
insert image description here
There are many more examples, so I won't list them one by one!

Finally, make a summary: 我们写出的表达式如果不能通过操作符的属性确定唯一的计算路径,那这个表达式就是存在问题的.

end of text

Guess you like

Origin blog.csdn.net/Cbiltps/article/details/120105372