[C Language Elementary] ❤️ Enseñarle a usar varios operadores en lenguaje C (uso competente + debe recopilarse) ❤️

Consejos amables

Hola a todos, soy Cbiltps. En mi blog, si hay oraciones que son difíciles de entender o puntos clave que son difíciles de expresar con palabras , tendré imágenes . ¡ Así que mi blog con fotos es muy importante ! ! !

¡ Si usted está interesado en mí por favor vea mi primer blog !

Puntos clave de este capítulo

  1. Introducción a varios operadores.
  2. evaluación de expresiones

inicio de texto


1. Clasificación de los operadores


  • operador aritmético
  • operador de turno
  • operador bit a bit
  • operador de asignación
  • operador unario
  • operador relacional
  • operador lógico
  • operador condicional
  • expresión de coma
  • Referencias a subíndices, llamadas a funciones y miembros de estructura

2. Operadores aritméticos


Los operadores aritméticos son: + - * / %
Además %del operador, varios otros operadores pueden actuar sobre números enteros y de coma flotante.

2.1 /Operadores

#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;
}

Los resultados de ejecución son los siguientes:
inserte la descripción de la imagen aquí
el segundo resultado sigue siendo 4.0, ¿por qué?
因为操作数中有浮点数,才执行浮点数除法。

2.2 %Operadores

%El operador es el operador módulo , también conocido como operador resto .

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

Nota: %el operador solo se puede usar para tipos enteros


3. Operadores de cambio de bits


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

3.1 <<Operador de desplazamiento a la izquierda

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

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

inserte la descripción de la imagen aquí
Si es un número negativo , mira el código:

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

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

inserte la descripción de la imagen aquí
Reglas de turno:左边抛弃、右边补0

Con respecto al código original, el código inverso y el código complementario , ¡lea otro blog avanzado que escribí !

3.2 >>Operador de desplazamiento a la izquierda

Reglas de cambio:
1. Cambio lógico: 左边用0填充,右边丢弃
2. Cambio aritmético:左边用原该值的符号位填充,右边丢弃

Ejemplo:

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

inserte la descripción de la imagen aquí
Aquí hay otro ejemplo con números negativos :

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

inserte la descripción de la imagen aquí
Aquí, se agrega el bit de signo original, por lo que VS2019 usa el desplazamiento aritmético a la derecha.

Advertencias ⚠:
1: Para el operador de turno, 不要移动负数位esto no está definido por la norma.
2: Cualquiera 被移动数o 移动的位数debe ser un número entero.

Por ejemplo ( demostración incorrecta ):

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

4. Operadores bit a bit


Los operadores bit a bit son:

  • &bit a bit Y
  • |bit a bit o
  • ^XOR bit a bit

Nota: Sus operandos deben ser números enteros.

4.1 &Operador AND bit a bit

Reglas de cálculo:
1: Siempre que haya 0 en el bit binario, es 0
2: Dos de los bits binarios son 1 al mismo tiempo, es decir, 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 |Operador OR bit a bit

Reglas de cálculo: siempre que haya 1 en el bit binario, es 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 ^Operador XOR bit a bit

Reglas de cálculo: el mismo bit binario es 0 y la diferencia es 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

Una pregunta de entrevista pervertida:

No se puede crear una variable temporal (la tercera variable) para intercambiar dos números.

#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;
}

Diagrama de ideas:
inserte la descripción de la imagen aquí

Nota: la legibilidad del código escrito de esta manera no es lo suficientemente buena y solo se aplica a tipos enteros.


5. Operador de asignación


El operador de asignación te permite obtener un valor con el que no estabas satisfecho antes, es decir, puedes reasignarte a ti mismo .

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

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

Los operadores de asignación se pueden utilizar consecutivamente, por ejemplo:

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

¿Cómo se siente este código?

Entonces escribe así:

x = y + 1;
a = x;

Mucho más limpio y fácil de depurar .

Operador de asignación compuesto:

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

Estos operadores se pueden escribir como efectos compuestos , tales como:

int x = 10;
x = x + 10;

x += 10;//复合赋值

6. Operadores unarios


Un operador unario es un operador con un solo operando

6.1 Varios operadores unarios

!inversión lógica

-valor negativo

+valor positivo

&tomar dirección

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

sizeofla longitud de tipo del operando en bytes

  • sizeof es un operador, no una función
  • sizeof es para calcular el tamaño de la memoria (unidad: byte) de una variable o tipo de variable creada, y la unidad no tiene nada que ver con los datos que se almacenan en la memoria
//以下几种写法都是一样的
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 内部的表达式不参与运算

inserte la descripción de la imagen aquí

~Inverso bit a bit de un número

  • Incluir el bit de signo también se puede invertir bit a bit
#incluide <stdio.h>

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

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

--delantero trasero--

  • Frente - -: primero - -, luego use
int a = 10;
int b = a--;
printf("%d\n", b);//这里打印出来还是 10
  • Atrás - -: usar primero, luego - -
int a = 10;
int b = --a;
printf("%d\n", b);//这里打印出来才是9

++delantero trasero++

  • Pre ++: ++ primero, luego use
  • Postfijo ++: use primero, luego ++

Tenga cuidado : no escriba código como este (código basura), ¡ la empresa lo despedirá!

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

	return 0;
}

¡Los dos compiladores son diferentes aquí!
inserte la descripción de la imagen aquí

*El operador de acceso indirecto (operador de desreferencia) &se puede utilizar junto con la obtención de direcciones

( 类型) conversión de tipos

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

6.2 tamaño de y arreglos

Veamos una pregunta y veamos cuánto producen respectivamente:

#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;
}

Resultado de salida:
inserte la descripción de la imagen aquí
para obtener más información sobre matrices , consulte mi último blog .


7. Operadores relacionales (los siguientes operadores no aparecen solos en el catálogo)


¡Los operadores relacionales solo tienen sentido cuando se comparan entre el mismo tipo!

  • >
  • >=
  • <
  • <=
  • != para probar "no igual"
  • == para probar "igual"

Estos operadores relacionales son relativamente simples, no hay nada de qué hablar, pero debemos prestar atención a las trampas al usar algunos operadores.
Nota: ¡Al programar =y ==Mal, dará lugar a errores!


8. Operadores lógicos


  • && Y lógico
    si es falso siempre falso:
int a = 0;
int b = 3;
int c = a && b;//只判断真假,所以打印出来是 0
  • || Lógico o
    uno verdadero debe ser verdadero:
int a = 0;
int b = 3;
int c = a || b;
printf("%d\n", c);//打印出来是 1

Echemos un vistazo a una pregunta de prueba escrita 360 :

#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;
}

Diagrama del pensamiento:
inserte la descripción de la imagen aquí
Si es lógico o :

#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;
}

Diagrama de ideas:
inserte la descripción de la imagen aquí


9. Operadores Condicionales


El operador condicional también se llama operador ternario.

exp1 ? exp2 : exp3

int a = 0;
int b = 0;

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

10. Expresiones de coma


exp1, exp2, exp3, …expN

Las expresiones de coma son expresiones múltiples separadas por comas.
Reglas de expresión de coma: 从左向右依次执行,整个表达式的结果是最后一个表达式的结果.

demostración de código:

//代码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. Referencias a subíndices, llamadas a funciones y miembros de estructura


[ ]Operador de referencia de subíndice
Operandos: un nombre de matriz + un valor de índice

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

( )operador de llamada de función

Acepta uno o más operandos : el primer operando es el nombre de la función y los operandos restantes son los parámetros pasados ​​a la función.

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

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

结构成员访问操作符

  • .Variable de estructura. Nombre de miembro
  • ->Puntero de estructura -> nombre de miembro
#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. Evaluación de expresiones


El orden en que se evalúan las expresiones está determinado en parte por la precedencia y la asociatividad de los operadores . Asimismo, es posible que sea necesario convertir los operandos de algunas expresiones a otros tipos durante la evaluación .

12.1 Conversiones de tipos implícitas

La aritmética de enteros en C siempre se realiza con al menos la precisión del tipo integral predeterminado .

Para lograr esta precisión, los operandos de caracteres y enteros cortos en las expresiones se convierten en tipos de enteros simples antes de su uso , una conversión conocida como promoción de enteros .

Importancia de la promoción de enteros:

La operación entera de la expresión debe ejecutarse en el dispositivo de operación correspondiente de la CPU.La longitud en bytes del operando de la unidad aritmética entera (ALU) en la CPU es
generalmente la longitud en bytes de int, y también es la longitud de el registro de propósito general de la CPU.

Por lo tanto, incluso si la CPU realiza la adición de dos tipos de caracteres, primero debe convertirse a la longitud estándar del operando entero en la CPU
.

Es difícil para una CPU de propósito general (CPU de propósito general) agregar directamente dos bytes de 8 bits directamente (aunque
puede haber tales instrucciones de adición de bytes en las instrucciones de la máquina). Por lo tanto, los diversos valores enteros en la expresión cuya longitud puede ser menor que int deben convertirse
a int o int sin signo antes de enviarse a la CPU para su cálculo.

¿Cómo llevar a cabo la mejora global?
整形提升是按照变量的数据类型的符号位来提升的

  • Promoción de enteros para números negativos:
char c1 = -1;
//变量c1的二进制位(补码)中只有8个比特位:
//1111111
//因为 char 是有符号的 char
//所以整形提升的时候,高位补充符号位,即为1
//提升之后的结果是:
//11111111111111111111111111111111
  • Promociones enteras para números positivos:
char c2 = 1;
//变量c2的二进制位(补码)中只有8个比特位:
//00000001
//因为 char 是有符号的 char
//所以整形提升的时候,高位补充符号位,即为0
//提升之后的结果是:
//00000000000000000000000000000001

Aviso:无符号整形提升,高位补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;
}

Los valores de a y b se convierten en enteros ordinarios antes de realizar la operación de suma;
una vez que se completa la operación de suma, el resultado se trunca antes de almacenarse en c.

12.2 Conversiones aritméticas

Si los operandos de un operador son de diferentes tipos, la
operación no puede continuar a menos que uno de los operandos se convierta al tipo del otro. La siguiente jerarquía se llama conversiones aritméticas ordinarias .

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

Si el tipo de un operando ocupa un lugar más bajo en la lista anterior, primero debe convertirse al tipo del operando de nivel superior antes de realizar la operación.

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

Advertencia: las conversiones aritméticas deben ser razonables; de lo contrario, existen algunos problemas potenciales.

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

12.3 Propiedades de los operadores

Hay tres factores que afectan la evaluación de expresiones complejas:

  1. precedencia del operador
  2. asociatividad del operador
  3. si controlar el orden de evaluación

¿Cuál de los dos operadores adyacentes se ejecuta primero?
取决于他们的优先级;如果两者的优先级相同,取决于他们的结合性.

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

Tabla de precedencia de operadores ( 由高到低展示):
inserte la descripción de la imagen aquí

Entonces, piénsalo, ¿eres capaz de realizar cálculos después de haber dominado los operadores 优先级, y lo que se mencionó anteriormente en la expresión? es el unico resultado?结合性是否控制求值顺序整型提升算数转换

Respuesta unificada:答案是否定的

Mira algunas expresiones problemáticas:

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

inserte la descripción de la imagen aquí
Nota: Al calcular el código 1, debido a que * tiene mayor prioridad que +, solo se puede garantizar que el cálculo de * sea anterior a +, pero la prioridad no puede determinar que el tercer * se ejecute antes que el primer +
.

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

inserte la descripción de la imagen aquí
Nota: Al igual que arriba, la prioridad del operador solo puede determinar la operación de autodecremento – antes de la operación de +, pero no tenemos forma
de saber adquisición del operando izquierdo del operador + se evalúa antes o después del operando derecho , por lo que el resultado es impredecible y ambiguo
.

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

¡Algunos grandes probaron los resultados con diferentes compiladores y descubrieron que son diferentes!
inserte la descripción de la imagen aquí
Hay muchos más ejemplos, ¡así que no los enumeraré uno por uno!

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

fin del texto

Supongo que te gusta

Origin blog.csdn.net/Cbiltps/article/details/120105372
Recomendado
Clasificación