Lenguaje C inicial: explique en detalle los operadores y los puntos propensos a errores de los operadores

Directorio de artículos de la serie

 El primer capítulo  "C" Huzhuan: conocer el lenguaje C por primera vez (¡más adecuado para principiantes!)

 El Capítulo 2  tiene una comprensión detallada de las sentencias de bifurcación y las sentencias de bucle y sus puntos propensos a errores. 

 Capítulo 3  Principiantes C—introducción de funciones en particular detalle

 Capítulo 4  Lenguaje C inicial——Explica en detalle el contenido de matrices y puntos propensos a errores

 Capítulo 5  Lenguaje C inicial: explicación detallada de los operadores y los puntos propensos a errores de los operadores


Tabla de contenido

Directorio de artículos de la serie

prefacio

1. Clasificación de los operadores

2. Operadores aritméticos (dos operandos)

3. Operador de desplazamiento (dos operandos)

3.1 Operador de desplazamiento a la izquierda <<

 3.2 Operador de desplazamiento a la derecha >>

3.3 Advertencias 

Cuatro, operador de bits (dos operandos)

4.1 Bit a bit AND &

Aplicaciones específicas de AND bit a bit:

 4.2 Bit a bit O |

4.3 Bit a bit XOR^ 

Aplicaciones específicas de XOR bit a bit:

4.4 Ejercicios sobre Bits Binarios 

5. Operador de asignación

 operador de asignación compuesto

Seis, operador unario (un operando)

6.1 Introducción a los operadores unarios

6.2 Operador lógico inverso ! 

 6.3 El operador de dirección & y el operador de desreferencia* 

6.4 Calcular la longitud de tipo sizeof del operando

6.5 Operadores ++ y --

7. Operadores relacionales (dos operadores)

Ocho, operadores lógicos (dos operadores)

8.1 Operador AND lógico &&

8.2 Operador OR lógico || 

8.3 Cortocircuito lógico 

Nueve, operador condicional (operador ternario)

10. Expresiones de coma 

11. Referencias a subíndices, llamadas a funciones y miembros de estructura 

11.1 [ ] operador de referencia de subíndice (dos operandos)

11.2 ( ) operador de llamada de función (al menos un operando)

11.3 Acceso a miembros de una estructura 

Resumir


prefacio

       En el capítulo anterior, el editor llevó a todos a aprender sobre arreglos en detalle, incluida la creación e inicialización de arreglos unidimensionales y bidimensionales , cómo almacenar arreglos unidimensionales y bidimensionales en la memoria , arreglos fuera de los límites , ¿ Qué pasa con las matrices como parámetros de función?

       En este capítulo, el editor lo llevará a aprender el contenido de los operadores . No es difícil para usted ver en la tabla de contenido que este capítulo tiene mucho contenido y que todos los operadores han sido incluidos. Espero que pueda pacientemente lee este capítulo léelo.


1. Clasificación de los operadores

       ¿Por qué aprender operadores? es para la evaluación de expresiones. ¡Antes de aprender operadores, siga al editor para aprender la clasificación de los operadores!

  • Operadores aritméticos: +, -, *, /, %
  • Operadores de desplazamiento: <<, >>
  • Operadores bit a bit: &, |, ^
  • Operadores de asignación: =, +=, -=, /=, *=, %=...
  • Operadores unarios: ! , -, +, tamaño de, ~, (tipo)
  • Operadores relacionales: >, <, >=, <=, !=, ==
  • Operadores lógicos: &&, ||
  • Operador condicional: exp1? exp2: exp3
  • Expresiones de coma: exp1, exp2, exp3, ... expN
  • Referencias a subíndices, llamadas a funciones y miembros de estructura: [ ], (), ., ->

2. Operadores aritméticos (dos operandos)

       En esta parte, el editor piensa que no hay nada de qué hablar, pero este blog es para explicar los operadores en detalle, ¡así que expliquemos los puntos propensos a errores! Los operadores aritméticos, como su nombre lo indica, son algunas operaciones matemáticas : +, -, *, /, %. No hay nada que hablar de los tres operadores +, -, *. A continuación, el editor se centrará en explicar : /, %. 

  1. Además del operador %, varios otros operadores trabajan con números enteros y de punto flotante .
  2. Para el operador /, si ambos operandos son enteros, se realiza la división de enteros . Y siempre que haya un número de punto flotante en los dos números, es la división de números de punto flotante.
  3. Los dos operandos del operador % deben ser números enteros y se devuelve el resto después de la división.

3. Operador de desplazamiento (dos operandos)

       Antes de hablar de ello, me gustaría mencionar que el operador de desplazamiento mueve bits binarios . Aquí, hablemos primero del binario del lenguaje C.

       Para un número entero, son cuatro bytes , que es ==32bit . Cuando un entero se escribe como una secuencia binaria, tiene 32 bits. Mira la imagen de abajo para entender:

       1) Para enteros con signo, el bit más alto es el bit de signo: el bit de signo es 1, lo que indica un número negativo; el bit de signo es 0, lo que indica un número positivo. 

       2) Para enteros sin signo, no hay bit de signo y todos los bits son bits válidos.

Hay tres representaciones binarias de números enteros : código original , código complementario y código complementario .

Código original: Según el signo del valor, la secuencia binaria escrita directamente es el código original.

Código inverso: el bit de signo del código original permanece sin cambios, y los otros bits se invierten poco a poco.

Código de complemento: El binario + 1 del código de complemento es el código de complemento. 

       En el ejemplo, podemos ver que para los enteros positivos, el código original, el código inverso y el complemento son los mismos , y no se requiere ningún cálculo; para los enteros negativos, es necesario calcular el código original, el código inverso y el código complementario.

               Los enteros se almacenan en complemento a dos en la memoria, y los enteros también se calculan en binario al calcular.


3.1 Operador de desplazamiento a la izquierda <<

Reglas de cambio: descartar a la izquierda y agregar 0 a la derecha.

       No hay casos especiales en los números regulares.Generalmente , en efecto, desplazar un bit a la izquierda equivale a multiplicar por 2 . Para números positivos , o para números negativos , en realidad es lo mismo, excepto que algunos números particularmente grandes son diferentes, y básicamente siguen: descartar el bit de signo, no importa cuál sea el bit alto a la izquierda, el número se agrega después de que se convierte en el bit de signo.

Aquí hay un ejemplo:

 


3.2 Operador de desplazamiento a la derecha >>

       Permítanme decir algo primero: el operador de turno derecho es más difícil. En primer lugar, la operación de desplazamiento a la derecha se divide en dos tipos: 1. Desplazamiento lógico a la derecha 2. Desplazamiento aritmético a la derecha . La principal diferencia entre los dos es: la clave depende de lo que se agregue a la izquierda .

Reglas de desplazamiento: 1. Desplazamiento lógico: la izquierda se rellena con 0 y la derecha se descarta 2. Desplazamiento aritmético: la izquierda se rellena con el bit de signo del valor original y la derecha se descarta.

       Del mismo modo, no hay casos especiales en números regulares y, en general, desplazar un bit a la derecha equivale a dividir por 2 en efecto . Para números positivos , siga: descarte un bit a la derecha y agregue 0 directamente a la izquierda . En cuanto a los números negativos , hay dos casos, por lo general, primero comprenda qué operación de desplazamiento a la derecha está usando su compilador, y el método es el siguiente. Seguir: Si es un desplazamiento aritmético a la derecha: la izquierda se rellena con el bit de signo original; si es un desplazamiento lógico a la derecha: la izquierda se rellena con 0.

 Aquí hay un ejemplo:

       Para números enteros positivos , estas dos operaciones de desplazamiento a la derecha son iguales ; para números enteros negativos , estas dos operaciones de desplazamiento a la derecha no son las mismas , así que céntrese en los números enteros negativos. Según esta diferencia, podemos escribir un código para ver qué operación de desplazamiento a la derecha admite el compilador que está utilizando. VS usa el desplazamiento aritmético a la derecha, y la mayoría de los compiladores usan el desplazamiento aritmético a la derecha . Mira el código a continuación:

#include <stdio.h>
int main()
{
	int a = -10 >> 1;
	if (a < 0)
		printf("该编译器用的是算术右移!\n");
	else
		printf("该编译器用的是逻辑右移!\n");
	return 0;
}

3.3 Advertencias 

Para los operadores de cambio, no cambie los bits negativos, esto no está definido por el estándar. Mira la foto de abajo:


Cuatro, operador de bits (dos operandos)

       Cuando aprendí lenguaje C por primera vez, el maestro probablemente no conocía esta parte, al menos nuestro maestro no habló sobre eso, pero esta parte es muy importante y juega un papel importante en algunos problemas binarios . ¡Pero no confunda los operadores bit a bit con los operadores lógicos! A continuación, el editor te llevará a estudiar por separado.

4.1 Bit a bit AND &

Reglas de funcionamiento: si es 1 al mismo tiempo, será 1; una vez que sea 0, será 0.

 Recordamos esta regla de operación y luego la calculamos , el código se explica a continuación:

int main()
{
	int a = 7;
	int b = -10;
	int c = a & b;//按二进制的位与
	//00000000 00000000 00000000 00000111 ----- 7的补码
	//10000000 00000000 00000000 00001010
	//11111111 11111111 11111111 11110101
    //*************************************
	//*11111111 11111111 11111111 11110110*----- -10的补码
	//*00000000 00000000 00000000 00000111*----- 7的补码
    //*************************************
	//同1为1,有0则0
	//00000000 00000000 00000000 00000110 ----- 6
	printf("%d", c);
	return 0;
}

Aplicaciones específicas de AND bit a bit:

       Si quiero saber si un cierto bit en el complemento a dos de un cierto número es 1 o 0, podemos usar la operación AND bit a bit para obtenerlo. ¿por qué?

       La idea básica es: porque la regla de operación de AND bit a bit es: el mismo 1 es 1 y 0 es 0 . Si desea solicitar el último dígito del complemento a dos de un número determinado , solo necesita Y 1 (2 ^ 0) , luego puede obtener que el último dígito del complemento a dos de un número determinado es ¿Qué, si el AND bit a bit es igual a 1, el último número es 1, y si es 0, el último número es 0. Del mismo modo, si desea solicitar el penúltimo dígito del complemento a dos de un número determinado , solo necesita realizar AND bit a bit en 2(2^1) .

Pregunta 1: ¿Cuál es el número de cierto dígito en el complemento a dos de cierto número?

**************************************************** **************************************************** ****

Método: a partir de las ideas básicas anteriores, se puede resumir una fórmula : si desea solicitar el número del último dígito N en el complemento a dos de un número determinado , solo necesita usar el AND bit a bit del 2 superior de un cierto número (N-1 ) a la potencia (2^(N-1)) .

**************************************************** **************************************************** ****

código:

int main()
{
	int num = 10;
	//如果想要求10的二进制补码中最后一位数
	int ans = num & 1;
	printf("ans = %d\n", ans);
	return 0;
}

Tema 2:  Encuentra el número en la última posición de 1 en el complemento a dos de un número determinado.

**************************************************** **************************************************** ****

método:

**************************************************** **************************************************** ****

código:

 int onlyone = eor & (~eor + 1);

 4.2 Bit a bit O |

Reglas de operación: es 0 solo cuando es 0 al mismo tiempo; una vez que es 1, es 1.

Este tipo de operación no necesita ser explicada, siempre y cuando recuerdes las reglas de operación, harás la operación , el código se explica a continuación:

int main()
{
	int a = 7;
	int b = -10;
	int c = a | b;//按二进制的位或
	//00000000 00000000 00000000 00000111 ----- 7的补码
	//10000000 00000000 00000000 00001010
	//11111111 11111111 11111111 11110101
	//*************************************
	//*11111111 11111111 11111111 11110110*----- -10的补码
	//*00000000 00000000 00000000 00000111*----- 7的补码
	//*************************************
	//同0为0,有1则1
	// 11111111 11111111 11111111 11110111 补码
	// 11111111 11111111 11111111 11110110 反码
	// 10000000 00000000 00000000 00001001 原码 --- -9
	printf("%d", c);
	return 0;
}

4.3 Bit a bit XOR^ 

Reglas de funcionamiento: 0 si son iguales, 1 si son diferentes. Aquí hay dos fórmulas para recordar: a ^ a = 0; a ^ 0 = a.

Propiedades: Las operaciones bit a bit siguen leyes conmutativas y asociativas.

       Aunque la regla de operación de XOR bit a bit es relativamente simple, todavía tenemos que aprender una regla de operación XOR bit a bit en el futuro: lo mismo es 1 y la diferencia es 0. Por lo tanto, es fácil confundir las dos operaciones.

Entonces, ¿cómo recordar el XOR bit a bit? Bitwise XOR, es decir, suma sin fundamento . ¿Cómo entender la suma sin fundamento? Mira la foto de abajo:

int main()
{
	int a = 7;
	int b = -10;
	int c = a ^ b;//按二进制的位异或
	//00000000 00000000 00000000 00000111 ----- 7的补码
	//10000000 00000000 00000000 00001010
	//11111111 11111111 11111111 11110101
	//*************************************
	//*11111111 11111111 11111111 11110110*----- -10的补码
	//*00000000 00000000 00000000 00000111*----- 7的补码
	//*************************************
	//相同为0,不同为1
	// 11111111 11111111 11111111 11110001 补码
	// 11111111 11111111 11111111 11110000 反码
	// 10000000 00000000 00000000 00001111 原码 --- -15
	printf("%d", c);
	return 0;
}

Aplicaciones específicas de XOR bit a bit:

 Una pregunta de entrevista muy pervertida: 

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

**************************************************** **************************************************** ****

Método 1: primero sume los dos números a y b y asígnelos a a, luego reste b de a y asígnelo a b, de modo que lo que está almacenado en b sea a, y luego reste b de a (el valor de b en este tiempo es a) se asigna a a, entonces el valor de a es el valor de b.

**************************************************** **************************************************** ****

código:

int main()
{
	int a = 10;
	int b = 90;
	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;
}

Defecto: si el valor de la variable es muy grande, se producirá un truncamiento de datos .

**************************************************** **************************************************** ****

Método 2: use XOR bit a bit, de acuerdo con a ^ a = 0, a ^ 0 = a , se puede obtener. En este proceso, no se generará ningún acarreo y los datos no se desbordarán.

**************************************************** **************************************************** ****

código:

int main()
{
	int a = 10;
	int b = 90;
	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;
}

Contras: este código no es muy legible y no es muy eficiente .

Tema 2:  dado un número arr, en el que solo dos números aparecen veces impares y otros números aparecen veces pares, genere los dos números en orden ascendente.

**************************************************** **************************************************** ****

Método: primero XOR todos estos números, puede obtener el resultado XOR de dos números que aparecen veces impares y asignarlos a eor, lo que indica que los dos números no deben ser iguales, y debe haber una posición en el binario de eor que sea 1, encuentre el número cuya posición es 1 (consulte 4.1 aplicación específica de AND bit a bit) , y luego divida el número en la matriz en dos partes, una parte es el número cuya posición es 1 y la otra parte es el número cuya posición es es 0 Luego, los dos números se separan y se puede obtener un número seleccionando al azar un conjunto de datos para XOR, y luego se puede obtener otro número usando e o XOR.

**************************************************** **************************************************** ****

código:

#include <stdio.h>
int main() 
{
    int n = 0;
    int eor = 0, eor1 = 0;
    int temp = 0, ans = 0;
    scanf("%d", &n);
    int arr[100000];
    for(int i = 0; i < n; i++)
    {
        scanf("%d", &arr[i]);
    }
    for(int i = 0; i < n; i++)
    {
        eor ^= arr[i];
    }
    int onlyone = eor & (~eor + 1);
    for(int i = 0; i < n; i++)
    {
        if((onlyone & arr[i]) != 0)
            eor1 ^= arr[i];
    }
    ans = eor ^ eor1;
    if(eor1 > ans)
    {
        temp = eor1;
        eor1 = ans;
        ans = temp;
    }
    printf("%d %d\n", eor1, ans);
    return 0;
}

4.4 Ejercicios sobre Bits Binarios 

Tema: Escribir código para lograr: Encontrar el número de 1 en binario almacenado en la memoria por un número entero.


5. Operador de asignación

       El operador de asignación es un gran operador, si no está satisfecho con el valor anterior, puede usar este operador para reasignarse.

Por ejemplo:

int weight = 120;//体重
weight = 80;//不满意就赋值
double salary = 100000.0;
salary = 200000.0; //使用赋值操作符赋值

Los operadores de asignación se pueden utilizar consecutivamente , pero se ejecutan secuencialmente de derecha a izquierda

	int a = 10;
	int x = 0;
	int y = 20;
	a = x = y + 1; //连续赋值,可读性不高
	//改进
	x = y + 1;
	a = x;//这样写更加清晰爽朗而且便于调试

 operador de asignación compuesto

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

Estos operadores se pueden escribir como efectos compuestos, lo que hace que el código sea más ordenado .

Por ejemplo:

	int x = 10;
	x = x + 10;
	x += 10; //这样写比较整洁

Seis, operador unario (un operando)

6.1 Introducción a los operadores unarios

6.2 Operador lógico inverso ! 

Reglas de operación: convertir verdadero en falso y falso en verdadero .

 Veamos el escenario de uso:

int main()
{
    int a = 0;
    if(!a)
        printf("hehe\n");
    return 0;
}

 6.3 El operador de dirección & y el operador de desreferencia* 

       El operador de dirección es sacar la dirección de una variable y almacenarla en p , y el operador de desreferencia es encontrar el objeto al que apunta p a través de la dirección almacenada en p.

6.4 Calcular la longitud de tipo sizeof del operando

int main()
{
	int a = 10;
	printf("%d\n", sizeof(a));
    printf("%d\n", sizeof a); //这种写法是正确的,证明了sizeof不是函数,函数后的括号省略不了
	printf("%d\n", sizeof(int));
	return 0;
}

       Como se puede ver en el código anterior, sizeof puede calcular tanto la longitud de la variable como la longitud del tipo. Después de ejecutar este código, ¿por qué aparece la siguiente imagen?

       Dado que el resultado del cálculo de sizeof es del tipo size_t y size_t es un entero sin signo , puede utilizar %zd para imprimir datos del tipo size_t . En algunos compiladores antiguos que no admiten %zd, también se puede usar %u .

6.5 Operadores ++ y --

Reglas de operación: Posición previa ++ (--): primero + (-) 1, luego usar; posición posterior ++ (--): usar primero, luego + (-) 1. 


7. Operadores relacionales (dos operadores)

        Estos operadores son relativamente simples, no hay nada de qué hablar, pero debemos prestar atención a las trampas al usar algunos operadores.

Advertencia: en el proceso de programación, == y = se escriben mal accidentalmente, lo que genera errores.


Ocho, operadores lógicos (dos operadores)

8.1 Operador AND lógico &&

Reglas operativas: AND lógico es AND, todo lo verdadero es verdadero y lo falso es falso.

Distinguir entre lógico y bit a bit y

1 & 2  -------->0
1 && 2 -------->1

8.2 Operador OR lógico || 

Reglas de operación: lógico o es o, todo falso es falso, verdadero es verdadero.

 Distinguir entre lógico o y bit a bit o

1 | 2 -------->3
1 || 2 ------->1

8.3 Cortocircuito lógico 

Reglas de operación: && Si el operando de la izquierda es falso, la expresión de la derecha no se cuenta; || Si el operando de la derecha es verdadero, la expresión de la derecha no se cuenta.

Después de aprender este operador, de repente pensé en una pregunta que me hizo mi compañero de clase:

       Estaba confundido cuando vi esta pregunta hace un momento, porque ambas opciones b y c se sienten mal, pero no lo son. Porque la opción c involucra algunos puntos de conocimiento que no conozco, porque hay un cortocircuito lógico, en el lenguaje C, cuando hacemos cálculos, necesitamos optimizar el código para evitar que el programa haga cálculos sobrecargados. En el programa, debido a que a||(b = c) es esta operación lógica, ¿ por qué hay un cortocircuito lógico? Para reducir la cantidad de cálculo del programa, al realizar esta operación lógica, el lenguaje C adopta el método de simplificar la operación al no calcular la operación subsiguiente cuando se ha determinado el valor exacto de la expresión manteniendo correcta la operación lógica original.

       En la operación OR, si a es verdadero, no importa cuál sea el siguiente valor, no necesitamos calcular, porque el resultado del programa ya se conoce, debemos realizar un cortocircuito lógico y luego no calcular b. = c, por lo que c no se calcula Asignado a b, b sigue siendo igual al valor original. Si a es falso, significa que el resultado posterior puede afectar a todo el resultado, por lo que no se puede realizar un cortocircuito lógico.

Aquí hay una pregunta de prueba escrita:

tema:

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);
	return 0;
}

Respuesta:


Nueve, operador condicional (operador ternario)

 Siento que este operador se usa para simplificar el código, vea el siguiente código para más detalles:

if (a > 5)
	b = 3;
else
	b = -3;
//等价于
b = a > 5 ? 3 : -3;

solicitud: 

Tema: Usar expresiones condicionales para encontrar el valor mayor de dos números

Método: uso de expresiones condicionales

código:

int main()
{
	int a = 90, b = 78;
	int ans = a > b ? a : b;
	printf("%d\n", ans);
	return 0;
}

10. Expresiones de coma 

Reglas de cálculo: los cálculos se realizan secuencialmente de izquierda a derecha, el resultado de la expresión completa es el resultado de la última expresión y los cálculos anteriores pueden afectar los resultados posteriores. 

 Veamos el escenario de uso:

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

11. Referencias a subíndices, llamadas a funciones y miembros de estructura 

11.1 [ ] operador de referencia de subíndice (dos operandos)

Operando: un nombre de matriz + un valor de índice

int arr[10]; //创建数组
arr[9] = 10; //使用下标引用操作符
[ ]的两个操作数是arr和9。

11.2 ( ) operador de llamada de función (al menos un operando)

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.

11.3 Acceso a miembros de una estructura 

.struct.membername

-> puntero de estructura -> nombre de miembro


Resumir

       En esta parte, el editor escribió un blog sobre la explicación detallada de los operadores en detalle. Espero que todos dejen un comentario después de leerlo, ¡gracias!

Supongo que te gusta

Origin blog.csdn.net/2301_77868664/article/details/132173595
Recomendado
Clasificación