Lenguaje C: primera introducción al lenguaje C

Prefacio

¿Los estudiantes que son nuevos en el lenguaje C no deben saber qué es el lenguaje C? , de qué sirve, entonces estás en el lugar correcto, esta serie te llevará a comenzar con el lenguaje C, desde comenzar hasta "enterrarlo", es broma, como dice el título, este tutorial primero tiene una comprensión preliminar En lenguaje C, puedes ver Comprender lo que otros escriben y tener un marco general, luego comenzaré a explicar. Este capítulo es principalmente un resumen del lenguaje C inicial.

1. ¿Qué es el lenguaje C?

¿ Qué es el lenguaje C ?

  • Idioma : chino, japonés, inglés, etc. El lenguaje es un lenguaje natural, un lenguaje utilizado por las personas para comunicarse entre sí.
    Lenguaje informático: por analogía, es la comunicación entre humanos y computadoras.

  • El lenguaje C es un lenguaje de programación de computadoras general que se usa ampliamente en el desarrollo de bajo nivel . El objetivo de diseño del lenguaje C es proporcionar un lenguaje de programación que pueda compilarse fácilmente, manejar memoria de bajo nivel, generar una pequeña cantidad de código de máquina y que pueda ejecutarse sin ningún soporte de entorno de ejecución. Aunque el lenguaje C proporciona muchas funciones de procesamiento de bajo nivel, aún mantiene buenas características multiplataforma.

2. El primer programa en lenguaje C.

  • Una vez que comprendamos qué es el lenguaje C, debemos comprender cómo utilizar un entorno de desarrollo integrado para completar el primer programa en lenguaje C.

  • ¿Qué es un entorno de desarrollo integrado?

  • El entorno de desarrollo integrado (IDE, Integrated Development Environment) es una aplicación que se utiliza para proporcionar un entorno de desarrollo de programas, que generalmente incluye herramientas como editores de código, compiladores, depuradores e interfaces gráficas de usuario.

  • Al igual que vscode es un editor, no es un entorno de desarrollo integrado, pero puede agregar muchos complementos para editar y generar varias formas de código.

  • Al igual que vs2022 es un entorno de desarrollo integrado, que es muy conveniente de usar en la vida diaria, pero el espacio de almacenamiento es relativamente grande, después de todo, tiene ventajas y desventajas, y las dos no son compatibles.

  • Pero personalmente no recomiendo usar esos compiladores antiguos como VC++, DEV++...

A continuación comenzaremos a escribir formalmente el primer programa en lenguaje C.

  1. Vaya al sitio web oficial para descargar VS2022, ¡no vaya a otros lugares para descargar versiones pirateadas! ! ! Haga clic para ingresar al sitio web oficial.

Insertar descripción de la imagen aquí

  • Haga clic en descarga gratuita personal, es suficiente para aprender y descargar.
  1. Abrir descarga

Insertar descripción de la imagen aquí

  1. Abra el software y cree un nuevo proyecto.

Insertar imagen aquí Descripción
Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí

Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí

  • En el aprendizaje del lenguaje C, el primer programa para la mayoría de las personas es hello word!¿Cómo lo imprimimos hello wordy comenzamos nuestro viaje de aprendizaje de programación? Síganme para aprender juntos.

Insertar descripción de la imagen aquí

  1. Sabemos que todos los caracteres y símbolos del lenguaje C están en inglés.
  2. El código en lenguaje C maincomienza desde la primera línea de la función.
  3. La función principal es el punto de entrada del programa, mainsolo hay una función en un proyecto.
  4. El código en el código printfse introduce mediante el archivo de encabezado del compilador y se puede usar directamente.
  5. <stido.h>es un archivo de encabezado, el sufijo es .cel archivo fuente y el sufijo .hes el archivo de encabezado.
#include<stdio.h>
int main()
{
    
    
	printf("hello world!\n");
	return 0;
}
  • Algunas personas pueden ver que lo que escribo aquí int main(){ ... return 0}generalmente se escribe así, y también es la forma de escritura más común.
    También hay otra forma de escribir: void main(){ }. Esta forma de escribir es relativamente antigua y no se puede utilizar ahora.

3. tipo de datos

Hemos escrito nuestro primer programa en lenguaje C. A continuación, hablemos de los tipos de datos en lenguaje C.

Antes de comprender los tipos de datos, primero exploremos por qué necesitamos escribir un programa .

  • Es utilizar programas para resolver algunos problemas de la vida. En la vida real, nuestros diversos datos tienen muchos tipos diferentes . Para expresar más abundantemente varios valores en la vida , se configuran muchos tipos de datos en programas de lenguaje C.
char        //字符数据类型
short       //短整型
int         //整形
long        //长整型
long long   //更长的整形
float       //单精度浮点数
double      //双精度浮点数
  • ¿Cuál es el tamaño de bytes de cada tipo?
    Lo que muestra la siguiente imagen es:

Insertar descripción de la imagen aquí

Unidades comunes en las computadoras: bit, byte, KB, MB, GB, TB, PB.

  • Su conversión de unidades es:

1 byte = 8 bits
1 KB = 1024 bytes
1 MB = 1024 KB
1 GB = 1024 MB
1 TB = 1024 GB
1 PB = 1024 TB

4. Variables, constantes

En la vida, algunos valores son constantes (como: pi, sexo, número de identificación, tipo de sangre, etc.), y algunos valores son variables (como: edad, peso, salario, etc.), y el constantesyvariablesSe introducen

Primero, hablemos de variables :

1. Variables

La sintaxis es : tipo + nombre. El código se muestra a continuación:

int age = 150;
float weight = 45.5f;  //浮点数默认为双精度浮点数,在后面加个f,说明是单精度浮点数类型
char ch = 'w';

1.1 Nombrar variables

  1. Solo puede constar de letras (incluidas mayúsculas y minúsculas), números y guiones bajos.
  2. No se puede empezar con un número.
  3. La longitud no puede exceder los 63 caracteres.
  4. El lenguaje C distingue entre mayúsculas y minúsculas.
  5. No se pueden nombrar nombres de variables 关键字.
  6. Los nombres de las variables deben ser lo más significativos posible.

1.2 Clasificación de variables

Las variables se dividen en variables locales y variables globales.

#include <stdio.h>
int global = 2019;//全局变量
int main()
{
    
    
    int local = 2018;//局部变量
    //下面定义的global会不会有问题?
    int global = 2020;//局部变量
    printf("global = %d\n", global);
    return 0;
}

Insertar descripción de la imagen aquí

Resumir:

globalEn realidad, ¡no hay nada de malo en la definición anterior de variables locales !
Cuando las variables locales y las variables globales tienen el mismo nombre, 局部变量se utilizan primero.

1.3 Uso de variables

Después de entender qué es una variable, ahora tenemos que usar esta variable específicamente, echemos un vistazo.

#include <stdio.h>
int main()
{
    
    
    int num1 = 0;
    int num2 = 0;
    int sum = 0;
    printf("输入两个操作数:>");
    scanf("%d %d", &num1, &num2);
    sum = num1 + num2;
    printf("sum = %d\n", sum);
    return 0;
}

Insertar descripción de la imagen aquí
Cuando vs se compile, encontrará que apareceremos aquí 4996警告.

  • ¿Por qué aparece esta advertencia?
    Esto se debe a que Microsoft tiene su propia definición de scanf_s al ingresar funciones en vs y no es seguro usar la función scanf.

¿Cómo eliminar esta advertencia?

  • El primer método es scanf()cambiarlo a scanf_s(), scanf()que también lo proporciona vs. Este método es muy simple, pero el código multiplataforma empeorará la portabilidad. Este método no se recomienda.
  • El segundo método es .cagregarlo al archivo #pragma warning(disable:4996)para que no aparezca esta advertencia.
  • Siga la operación paso a paso a continuación
    • Primero descargue todo el software, haga clic para abrir después de descargarlo
    • Buscar newc++file.cpp, abrir archivos

Insertar descripción de la imagen aquí

  • Pegue esta línea #define _CRT_SECURE_NO_WARNINGS 1y no olvide agregar [1] después

Insertar descripción de la imagen aquí

  • Este método puede resolver nuestro problema de una vez por todas ~~

Crea un .carchivo nuevamente y verás que esa línea aparece automáticamente.

Insertar descripción de la imagen aquí

1.4 Alcance y ciclo de vida de las variables

Ahora que sabemos cómo usar variables para escribir programas, echemos un vistazo al alcance y ciclo de vida de las variables.

Alcance:

El alcance es un concepto de programación. En términos generales, los nombres utilizados en un fragmento de código de programa no siempre son válidos/utilizables. En términos generales, los nombres de variables utilizados en un fragmento de código no siempre son válidos. El alcance del código que limita la disponibilidad de este nombre es el alcance del nombre de la variable.

Ahora que entendemos los conceptos básicos, demostrémoslo en el código.

  • Se puede ver que el programa reporta un error, diciendo [identificador indefinido], se puede ver que este alcance tiene un alcance limitado.
int main()
{
    
    
	{
    
    
		int a = 10;
		printf("a = %d", a);
	}
	printf("a = %d", a);

	return 0;
}

Insertar descripción de la imagen aquí

  • Lo anterior es el alcance de las variables locales.
  • Como se puede ver en el código siguiente, no se informa ningún error, porque el alcance de la variable global es desde el momento en que se define la variable hasta el final de todo el programa, y ​​toda la variable se destruirá y esta variable a está en este bloque de código. Se destruirá una vez que finalice, por lo que no podremos acceder a esta variable más adelante.

Insertar descripción de la imagen aquí

  • Para el alcance de las variables globales, también puede usarlo así, definir la variable b en el archivo add.c, luego definimos test.cla variable b en este archivo y externla declaramos con esto

Insertar descripción de la imagen aquí
ciclo vital:

El ciclo de vida de una variable se refiere al período de tiempo entre la creación de la variable y su destrucción.

El ciclo de vida de las variables locales es : el ciclo de vida comienza al ingresar al alcance y finaliza al salir del alcance.

El ciclo de vida de las variables globales es : el ciclo de vida de todo el programa.


Ahora que hemos hablado de variables, hablemos de constantes.

2. Variables

Hay varios tipos de constantes en lenguaje C:

  • constante literal
  • constvariable constante modificada
  • #definir constante de identificador definido
  • constantes de enumeración
#include <stdio.h>
//举例
enum Sex
{
    
    
    MALE,
    FEMALE,
    SECRET
};
//括号中的MALE,FEMALE,SECRET是枚举常量

//#define的标识符常量 演示
#define MAX 100

int main()
{
    
    
    //字面常量演示
    3.14;//字面常量
    1000;//字面常量

    //const 修饰的常变量
    const float pai = 3.14f;   //这里的pai是const修饰的常变量
    pai = 5.14;//是不能直接修改的!

    printf("max = %d\n", MAX);

    //枚举常量演示
    printf("%d\n", MALE);//0
    printf("%d\n", FEMALE);//1
    printf("%d\n", SECRET);//2
    //注:枚举常量的默认是从0开始,依次向下递增1的
    return 0;
}

Una constante es una cantidad que no cambia, por eso se llama constante.

5. cuerda

1. Concepto

  • Antes de hablar de cadenas, primero echemos un vistazo a lo siguiente: debido a que lo que se almacena y representa en la computadora es binario, lo que imprimimos también será binario.
  • Primero defina una variable de carácter ch de tipo char y luego imprímala como %c, %d y %s respectivamente. Puede ver que los resultados mostrados son diferentes.
  • %c imprime un carácter, %d imprime el valor de este carácter en la tabla de códigos ASCLL y el último %s imprime la cadena ch.

Insertar descripción de la imagen aquí

  • Entonces hablemos de cuerdas.

Concepto: una cadena de caracteres entre comillas dobles se llama cadena

2. Encuentra la longitud de la cuerda [strlen]

Después de hablar sobre los conceptos básicos de las cadenas y comprender qué es una cadena, veamos cómo encontrar la longitud de una cadena.

  • Para las cadenas, todos deben saber que la marca de fin es un carácter de escape \0. Hablaremos de los caracteres de escape en el siguiente módulo. Esto \0significa que la cadena ha terminado. Pero al calcular la longitud de la cuerda, esto \0no se incluye en el cálculo.
  • En otras palabras, encontrar la longitud de una cadena cuenta \0cuántos caracteres aparecen antes en la cadena.

Entonces, ¿cómo encontramos la longitud de una cuerda?

  • Aquí necesitamos usar una función llamada en el archivo de encabezado [string.h], que strlen()puede calcular la longitud de una cadena, es decir, la longitud antes de \ 0. Hablaremos de esta función en detalle más adelante.
printf("len = %d\n", strlen("abc"));

Insertar descripción de la imagen aquí

Mencionamos anteriormente que el tipo char puede definir una variable de carácter. No solo eso, aquí también podemos definir una matriz de caracteres. ¿Qué es una matriz de caracteres? Significa que todos los caracteres están almacenados en esta matriz. Veamos una definición específica.

char arr[] = "abcdef";
  • Lo anterior es la definición básica de matriz de caracteres.
  • A continuación, veamos otra forma: la siguiente también es una forma de definir una matriz de caracteres.
char arr2[] = {
    
     'a','b','c','d','e','f' };
  • Como puede ver, el contenido de estas dos matrices de caracteres es el mismo, así que si sus longitudes impresas y calculadas son las mismas, echemos un vistazo.

Insertar descripción de la imagen aquí

  • Obviamente, a juzgar por los resultados anteriores, son diferentes, ¿por qué? Aprendamos sobre esto a través de un diagrama.

Insertar descripción de la imagen aquí

  • En la imagen de arriba, deberíamos poder ver claramente por qué la segunda matriz arr2 aparece [caliente, caliente, caliente] al imprimir. Debería ser lo mismo si lo prueba usted mismo en el compilador.
  • Debido a que el valor del contenido de la segunda matriz se asigna a 'f', no es una cadena completa, pero a la primera matriz se le asigna una cadena completa, por lo que automáticamente tiene un '\0', y la segunda matriz La matriz desapareció , por lo que lo que se imprima más tarde solo será un valor aleatorio y el recorrido no finalizará hasta que encuentre un \0.
  • Entonces podemos ver que la longitud también se ve afectada: la longitud de la matriz arr1 es 6, pero la longitud de la matriz arr2 es la longitud después de agregar algunos caracteres aleatorios, lo que parece inexacto.

3. Caracteres de escape [incluidas las preguntas de prueba escritas]

  • Entonces, ¿qué son los personajes de escape? Echemos un vistazo al código.
int main()
{
    
    
	printf("abcndef");
	printf("abc\ndef");
}

Insertar descripción de la imagen aquí

  • Podemos ver en los resultados de ejecución que nsi se agrega esto delante \, su significado cambiará. En el carácter de escape, se llama [\nline feed], por lo que puede ver que se imprime en [abc] una línea. Se produjo una interrupción y se imprimió def en la siguiente línea.

  • Luego veremos una ruta que imprime un test.c
  • A juzgar por los resultados de la ejecución, en realidad no se imprime una ruta, pero aparecen muchos espacios.
  • Los amigos cuidadosos deberían poder encontrar que el primer carácter t de esta prueba y el \ de la ruta son del mismo color y ambos están descoloridos. Entre los caracteres de escape, esto se llama [\ carácter de tabulación horizontal], que también es mostrado en nuestro teclado. [Tecla Tab], un toque puede abrir 4 espacios.

Insertar descripción de la imagen aquí

  • Entonces, cuando printf genere algo, no escriba algunos caracteres de escape. ¿Cuáles son los caracteres de escape en lenguaje C? Echemos un vistazo.

Utilice una tabla para presentarlo a todos:

Personaje de escape Definición
? Se utiliza al escribir varios signos de interrogación seguidos para evitar que se analicen en palabras de tres letras.
\' Se utiliza para representar constantes de caracteres.
\“ Se utiliza para representar comillas dobles dentro de una cadena.
\ \ Se utiliza para representar una barra invertida, evitando que se interprete como un carácter de secuencia de escape.
\a Carácter de advertencia, timbre
\b carácter de retroceso
\F carácter de alimentación de papel
\norte nueva línea
\r Ingresar
\ t pestaña horizontal
\v pestaña vertical
\ddd ddd representa de 1 a 3 dígitos octales. Por ejemplo: \130X
\xdd dd representa 2 dígitos hexadecimales. Por ejemplo: \x30 0

Hablemos de los puntos clave

  • El primero es dos o tres. Mire la primera línea de código. Si lo que imprime es ['''], entonces el compilador informará un error. Originalmente quería imprimir un [']. ¿Qué debe hacer en este momento? ¿Tiempo? Simplemente agregue un \ al frente, que se convierte en un carácter de escape, y luego podrá generarlo como el resultado de la ejecución.
  • Luego el tercero es el mismo, así que no lo explicaré con demasiado detalle aquí.

Insertar descripción de la imagen aquí

  • Luego está la ruta de impresión que acabamos de mencionar ¿Cómo podemos imprimir esta ruta? Así es, solo necesitas agregar otro [\], lo que significa una barra invertida, echemos un vistazo al código.
  • Como puede ver, esta ruta se ha impreso por completo.

Insertar descripción de la imagen aquí

  • Finalmente, hablemos de los dos últimos puntos sobre octal y hexadecimal.
  • Lo mismo, primero da los resultados de ejecución.

Insertar descripción de la imagen aquí

  • Respecto a [\ddd], representa octal, es decir, calculado a través de octal. Si usa %d para imprimir el resultado del cálculo, si usa %c para imprimir el símbolo de código ASCLL correspondiente al número.

  • Lo mismo ocurre con el hexadecimal, el valor /xdd es decimal y lo mismo ocurre cuando se mira la impresión de arriba.

  • Para [\x3a], utilice un*160

  • Entonces hablemos de una pregunta de prueba escrita sobre personajes de escape.

printf("%d\n", strlen("c:\test\628\test.c"));
  • Cual es el resultado? Las respuestas varían
  • La verdadera respuesta es [14], ¿por qué? vamos a ver

analizar

  • En primer lugar, en el primer paso, acabamos de aprender sobre los caracteres de escape: [\t] debe representar un carácter, por lo que se excluye 18.
  • Luego, en el segundo paso, creo que lo que más confunde a todos es este \ 628. Este es en realidad el \ ddd que mencionamos anteriormente, pero ¿se puede contar? En este momento, debes pensar si octal puede contener 8. Octal es un número del 0 al 7, por lo que no habrá 8, por lo que este [\62] cuenta como un carácter de escape.
  • Finalmente podemos obtener la respuesta como [14]

6. Notas

Primero debemos entender qué son las anotaciones y para qué se pueden utilizar.

  1. Los comentarios pueden bloquear temporalmente el código que no necesita o no desea eliminar todavía. Cuando se ejecuta el programa, el código comentado se omitirá directamente y no se ejecutará.
  2. Si hay algún código oscuro en algunos programas , el código que escriba puede necesitar algunos comentarios para que las personas que lean su código más tarde puedan saber lo que significa. En este caso, puede colocarlo encima de este código o escribir algunos comentarios a continuación para que que las generaciones futuras puedan entender el código que escribiste.
int main()
{
    
    
	//下面是创建一个整型变量并赋值10
	int a = 10;
	int b = 100;
	//C++ 注释风格 - C99

	/*	C语言的注释风格
	int c = 10;
	int d = 20;
	printf("ff");
	*/	// - 嵌套的话此处结束注释
	//不支持嵌套注释

	return 0;
}
  • Analicémoslo. Para doble barra //, este es el estilo de comentario para C++ en C99. Entonces, ¿cuál es el estilo de comentario del lenguaje C? Es decir/**/
  • Pero también agregué una oración más tarde, es decir, este método de anotación en lenguaje C no se puede anidar. Por ejemplo, si agrega un /**/ a la capa externa, devuelve 0; no se anotará. ¿Por qué? Debido a que el de arriba coincide primero con el de arriba, no irá al de abajo /*.return 0;

7. Seleccione declaraciones

  • En lenguaje C u otros lenguajes de programación, existen tres métodos estructurales: [Secuencia], [Selección] y [Bucle].
  • Entonces, ¿qué es esta declaración de selección? Es decir, a veces te enfrentas a dos o más opciones, y diferentes opciones corresponden a diferentes resultados.

Echemos un vistazo al código específicamente.

int main()
{
    
    
	int input = 0;
	printf("你要好好学习吗(1/0)\n");
	scanf("%d", &input);
	if (input == 1) 
	{
    
    
		printf("拿一个好offer\n");
	}
	else 
	{
    
    
		printf("回家种田\n");
	}
	return 0;
}
  • El código anterior es una declaración de selección: puede ingresar su elección en la terminal y preguntar si desea estudiar mucho. Si eliges 1 para estudiar mucho, entonces puedes obtener una buena oferta ; pero si eliges 0 para ser miserable, entonces sólo podrás ir a casa y cultivar.

8. Declaraciones de bucle

Entonces hablemos de otra forma, que es la declaración de bucle.

  • ¿Qué es un ciclo? Un bucle es cuando haces algo una y otra vez hasta que se cumple una determinada condición antes de salir.

Entonces echemos un vistazo a través de un fragmento de código.

int main()
{
    
    
	int line = 0;
	printf("好好学习\n");
	while (line < 20000)
	{
    
    
		printf("写代码:%d\n", line);
		line++;
	}
	if (line == 20000)
		printf("好offer\n");
	return 0;
}

Insertar descripción de la imagen aquí

  • Y los bucles for, no solo existen while, sino también do…while(), forestos, de los que hablaremos en el seguimiento.

9. Función

En realidad, una función encapsula una función en un módulo, y luego este módulo se puede llamar varias veces para simplificar el código.

  • Veamos primero este fragmento de código.
  • Este es un código para sumar dos números. Ingresa dos datos y luego genera su suma.
  • Pero imaginemos que si queremos encontrar la suma de otros dos números, tenemos que ingresarla nuevamente y luego escribir el código de suma nuevamente, lo que sólo aumenta la cantidad de código y hace que todo el programa sea muy redundante. ¿Qué pasa con la simplificación? Sí, solo usa funciones.
int main()
{
    
    
	int num1 = 0;
	int num2 = 0;
	int sum = 0;
	printf("请输入两个操作数字:>");
	scanf("%d %d", &num1, &num2);

	sum = num1 + num2;
	printf("sum = %d\n", sum);
	return 0;
}
  • Echemos un vistazo a cómo se ve después de la simplificación usando funciones.
  • Este código utiliza tres sumas y obtiene tres resultados de suma.
int Add(int m, int n)
{
    
    
	return (m + n);
}
int main()
{
    
    
	int sum1 = 0;
	int sum2 = 0;
	int sum3 = 0;

	sum1 = Add(1, 2);
	sum2 = Add(3, 4);
	sum3 = Add(5, 6);

	printf("sum1 = %d\n", sum1);
	printf("sum2 = %d\n", sum2);
	printf("sum3 = %d\n", sum3);
	return 0;
}

Insertar descripción de la imagen aquí

10. matriz

1. Definición de matriz

  • En primer lugar, conocemos el concepto de números, pero cuando necesitamos un montón de números, ¿dónde los almacenamos? Así es, se almacena en algo llamado [matriz].
  • Entonces, ¿cómo almacenarlo?, echemos un vistazo.
int a[10] = {
    
     1,2,3,4,5,6,7,8,9,10 };
  • En primer lugar, debe declarar de qué tipo es la matriz, ya sea un número entero, un carácter, un punto flotante, etc. En el caso de una matriz, estos datos se pueden almacenar y luego agregar una variable después, y []puede escribe entre paréntesis lo que vas a hacer con él. ¿Cuánto espacio abre este arreglo? Por ejemplo, si arriba dice 10, entonces el número máximo de datos que se pueden almacenar en este arreglo es solo 10. Pero si No lo escribas, puedes almacenar más. Te enseñaré un método más adelante. ¿Cómo calcular el tamaño de esta matriz sin dar el tamaño específico de los datos?
  • Aquí se proporciona primero. Puede echar un vistazo primero. sizeof() es un operador unario, que se utiliza para calcular el tamaño de bytes de espacio ocupado por el operando que utiliza.
int sz = sizeof(a)/sizeof(a[0]);
  • Como se mencionó anteriormente, además de almacenar datos enteros, las matrices también pueden almacenar datos de caracteres y de punto flotante.
char b[] = {
    
     'a','b','c'};
double c[] = {
    
    2.5,6.9,7.7,1.5 }

2. Subíndice de matriz

Ahora que sabemos cómo declarar matrices, ¿cómo obtenemos las matrices que declaramos?

  • El lenguaje C estipula que cada elemento de la matriz tiene un subíndice y se accede al subíndice a partir de 0. El siguiente es 下标el elemento con el subíndice 8 en la matriz a la que accedemos y se imprimirá como 9.
//下标访问数组元素
printf("%d\n", a[8]);
  • Puedes ver los detalles claramente mirando el diagrama.
    Insertar descripción de la imagen aquí

  • Como puede ver, el tamaño de la matriz arr aquí es 10. ¿Qué pasará si accedemos al subíndice 18? Comprobémoslo en el compilador.

  • Como se puede ver en la figura, el subíndice total es solo 9. Si accede a él, se producirá un acceso fuera de límites y lo que acceda será un valor aleatorio.

Insertar descripción de la imagen aquí

3. Uso de matrices

  • Echa un vistazo al código. Primero definimos una matriz de enteros con un tamaño de 10 y luego inicializamos su contenido a 0. Luego ingresamos algunos datos a través de scanf en un bucle while y los colocamos en la matriz uno por uno mediante subíndices. Luego, sigue siendo lo mismo, recorre la matriz y llama a printf para imprimir los datos que contiene.
  • Esta es una forma de utilizar matrices. Explicaremos el resto en detalle en el capítulo sobre matrices más adelante.
int main()
{
    
    
	int arr[10] = {
    
     0 };
	//0 ~ 9 - 输入10个值给数组
	int i = 0;
	while (i < 10) 
	{
    
    
		scanf("%d", &arr[i]);
		i++;
	}

	i = 0;
	while (i < 10) 
	{
    
    
		printf("%d ", arr[i]);
		i++;
	}
	return 0;
}

Insertar descripción de la imagen aquí

11. Operador

Hay muchos operadores en lenguaje C. Aquí daremos una breve introducción y los explicaremos en detalle más adelante.

1. Operadores aritméticos

Insertar descripción de la imagen aquí

  • Aquí nos centramos en [división] y [resto]
  • Primero mire este código, ¿cuál será el resultado?
int a = 7 / 2;
printf("%d\n", a);
  • El resultado de ejecución es 3, debido a que los lados izquierdo y derecho del operador son números enteros , por lo que se realiza la división de enteros, incluido el siguiente párrafo. El resultado de ejecución es 3, solo debido al número de punto flotante flotante, hay 6 ceros más después el punto decimal.
float f = 7 / 2;
printf("%f\n", f);
  • Luego, cómo convertirlo en división de coma flotante, es decir, para obtener la respuesta de 3.5, solo necesita cambiar cualquier número 7 o 2 a un número de coma flotante, por ejemplo, 7.0/2.0, al menos un operando se ejecuta como un número de coma flotante es una división de coma flotante

echemos un vistazo a los resultados

Insertar descripción de la imagen aquí

  • Entonces echemos un vistazo al operador [resto]
int main()
{
    
    
	// % 取余操作符,关注的是除法后的余数
	int a = 7 % 2;	//商3余1
	printf("%d\n", a);
	return 0;
}
  • Lo que obtienes es el resto después de dividir un número entero por otro número entero.

Insertar descripción de la imagen aquí


2. Operador de turno

Insertar descripción de la imagen aquí

  • Entendamos esto primero, no entraré en detalles por ahora, lo explicaré en detalle en el capítulo del operador.

Mover hacia la izquierda para expandir,
mover hacia la derecha para reducir


3. Operadores de bits

  • Se llama desplazamiento arriba y posición aquí. ¿Hay una gran diferencia? La diferencia es enorme, son dos conceptos completamente distintos.
    Insertar descripción de la imagen aquí

  • Esto también se explicará en detalle en capítulos posteriores.


4. Operador de asignación

Insertar descripción de la imagen aquí

  • En cuanto a los operadores de asignación, el primero debería ser familiar para todos, es nuestra operación de asignación común, y las siguientes se componen de algunos [suma, resta, multiplicación, división, resto y desplazamiento], puedes probarlo tú mismo en el compilador.

5. Operador unario

Centrémonos en el algoritmo monocular.

Insertar descripción de la imagen aquí

  • La primera es esta operación de negación. En lenguaje C, solo hay dos tipos de expresiones: verdadero y falso, 0 representa falso y 非0representa verdadero.
  • Mire el código siguiente. Esta a es [verdadera], por lo que se ejecutará la declaración "jaja". Pero si reemplaza a con 0, entonces !aes [verdadera] y se imprimirá la declaración "jeje".
//C语言是如何表示真假的呢?
//0表示假,非0表示真
//-1 表示的就是真
int main()
{
    
    
	//把假变成真,把真变成假
	int a = 10;
	if (a)
		printf("haha\n");
	if(!a)	//这个不执行
		printf("hehe\n");
	return 0;
}
  • Entonces [obtener positivo] [obtener negativo] es muy simple: cuando vea el siguiente código, se imprimirá el número opuesto de a.
int a = -10;
printf("%d\n", +a);
printf("%d\n", -a);
  • Luego, para la toma de direcciones y el operador de asterisco, lo introduciremos en la parte del puntero a continuación.
  • Entonces echemos un vistazo al operador sizeof() ¿Es sizeof() una función? No, sizeofes un operador.
int a = 10;
char c = 'w';
int arr[10] = {
    
     0 };	
printf("%d\n", sizeof(a));		//4
printf("%d\n", sizeof(c));		//1
printf("%d\n", sizeof(arr));	//40
  • En cuanto al operador sizeof(), se utiliza para calcular el tamaño del espacio de memoria ocupado . La unidad son bytes, por lo que la salida del código anterior es el tamaño del espacio de memoria ocupado por números enteros, caracteres y una matriz.
  • Debido a que estas variables se definen usando tipos de variables como int y char, puede usar directamente sizeof() para pasar los tipos de estas variables y los resultados serán los mismos.
printf("%d\n", sizeof(a));			//4
printf("%d\n", sizeof(int));		//4
printf("%d\n", sizeof(c));			//1
printf("%d\n", sizeof(char));		//1
  • Dado que se trata de un operador, ¿por qué necesitamos los paréntesis? ¿No sería mejor simplemente eliminarlo? De lo contrario, causará ambigüedad, como la siguiente
printf("%d\n", sizeof int);
  • Cuando lo ejecutamos en el compilador, podemos ver que no se puede ejecutar ~~
  • En realidad, esto ilustra mejor que sizeof es un operador, no una función, y los paréntesis se pueden omitir.
  • Entonces podemos sacar la conclusión: las variables se pueden poner entre corchetes, pero los tipos no.

Como mencionamos anteriormente, cuando no configuramos el número de elementos iniciales para una matriz, podemos usar sizeof() para calcular cuántos elementos hay en la matriz.

  • Es el siguiente, sizeof(arr) es el tamaño de toda la matriz, sizeof(arr[0]) es el tamaño de un elemento, por supuesto, también puedes escribirlo como [sizeof(int)], porque el tamaño de un elemento en una matriz de enteros es seguro Tiene 4 bytes, que es el tamaño de los bytes ocupados por int.
printf("%d\n", sizeof(arr));;
int sz = sizeof(arr) / sizeof(arr[0]);
printf("%d\n", sz);

Entonces hablemos de [pre-, post-] y [pre-, post-++]

  • Estos dos son en realidad iguales, echemos un vistazo a [pre-, post-++]
  • Para anteponer ++, ++ se asigna primero, por lo que la siguiente a dará el valor después de ++ a b, y luego también puede ++, por lo que el resultado final es 11 11
int a = 10;
int b = ++a;	//先++后赋值
// a = a + 1
// b = a

printf("%d %d\n", a, b);	//11 11
  • Es diferente para el sufijo ++, por el contrario, c primero le dará su valor a d, y luego a ++ por sí solo, entonces lo que obtiene d es 10, y después de que c termine con ++, será 11.
int c = 10;
int d = c++;	//先赋值后++
// d = c;
// c = c + 1

printf("%d %d\n", c, d);	//11 10

Insertar descripción de la imagen aquí

  • Entonces hablemos de [preposición, posposición –], la misma razón
int a = 10;
int b = --a;	///先--在赋值

printf("%d %d\n", a, b);	//9 9

int c = 10;
int d = c--;	///先赋值后--

printf("%d %d\n", c, d);	//9 10

Insertar descripción de la imagen aquí

  • Luego lo mismo ocurre con esta sección. Lo primero que se imprime a– debe ser el valor anterior, y luego lo siguiente que se imprime es el valor después de –, que es 9.
int a = 10;
printf("%d\n", a--);	//先使用,后--
printf("%d\n", a);

Respecto a la posición previa y posterior ±, siempre me gusta hacer algunas preguntas en la entrevista para confundirte. De hecho, no tiene ningún sentido, echemos un vistazo.

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

Insertar descripción de la imagen aquí

  • Desde la perspectiva de VS, el resultado de ejecución de este código es 12, pero en el compilador gcc de Linux, el resultado de ejecución es en realidad 10

  • Si un fragmento de código se ejecuta con resultados diferentes en diferentes compiladores, significa que hay algún problema con ese fragmento de código y, para ser precisos, hay ambigüedad.

  • Hablemos del último de los operadores unarios, la conversión de tipo forzada.

  • Primero, veamos estas dos líneas de código: ¿qué crees que generará esto?

int a = 3.14;
printf("%d\n", a);
  • Debido a que 3.14 proporcionó una variable entera a, solo se conservarán los números enteros. En este momento, mire la Advertencia que dibujé con un bolígrafo rojo a continuación, que dice que [convirtiendo de "doble" a "int"], es posible que se pierdan datos.
  • ¿Qué debemos hacer en este momento? Puede agregar un (int) delante de 3.14 para forzar el número a un número entero, que es la línea de código que comenté anteriormente. Si intenta ejecutarlo nuevamente en este momento, no se informará la Advertencia.
    Insertar descripción de la imagen aquí

6. Operadores relacionales

Insertar descripción de la imagen aquí

  • Para los primeros cuatro, utilícelos directamente y compárelos intuitivamente. Hablemos de los dos siguientes.
  • Es decir, compara si dos números son iguales o no. Esto debe distinguirse de [=] en [Operador de asignación]. Uno compara dos números o variables y el otro realiza operaciones de asignación. No hay confusión. Entendido
int a = 10;
int b = 20;

if (a == b)
	printf("haha\n");
if(a != b)
	printf("hehe\n");
  • En ese momento, algunos estudiantes preguntaron, además de comparar números, ¿se pueden comparar cadenas?
char arr1[] = "abcdef";
char arr2[] = "abcdef";
if (arr1 == arr2)
	printf("==\n");
else
	printf("!=\n");

Insertar descripción de la imagen aquí

  • Se puede ver que las dos matrices de caracteres son obviamente iguales, pero tomaron la segunda rama e imprimieron [!=], en realidad hay un problema aquí. ¿por qué? Hablaremos de esto más adelante. El nombre de la matriz es la dirección del primer elemento de toda la matriz. De hecho, [==] compara sus direcciones.
  • Para comparar cadenas, existe una función especial en lenguaje C llamada strcmp(). Pertenece al archivo de encabezado [string.h] como strlen(). Si los dos comparados son iguales, devolverá 0, el primero es mayor que el último, devuelve un número > 0, el último es mayor que el anterior, devuelve un número < 0, por lo que sólo necesitas juzgar el tamaño de la suma 0
//两个字符串不可以用“==”来判断是否相等,使用strcmp(库函数)
char arr1[] = "abcdef";
char arr2[] = "abcdef";
if (strcmp(arr1,arr2) == 0)
	printf("==\n");
else
	printf("!=\n");

En este caso, el resultado será correcto.

Insertar descripción de la imagen aquí


7. Operadores lógicos

Insertar descripción de la imagen aquí

  • Lógico y [&&] significa y, lógico o [| |] significa o. 1 si es verdadero, 0 si es falso
  • Para AND lógico, el resultado es 1 solo si ambos números son 1. Mientras uno de ellos sea 0, el resultado es 0.
int a = 5;
int b = 4;
int c = a && b;
printf("c = %d\n", c);
if (a && b)
	printf("hehe\n");

Insertar descripción de la imagen aquí

  • Se puede ver en el código anterior y en los resultados de ejecución que debido a que a y b no son 0, sus resultados son 1, y luego se puede ingresar el siguiente juicio: si cualquiera de a y b se cambia a 0, el resultado será ser 0. , y luego no ingresará el siguiente juicio
  • Para OR lógico, siempre que uno de los números sea 1, es 1, y solo si ambos números son 0, es 0.
  • Por lo tanto, el siguiente resultado mostrado es 0 y no se juzga esta condición if.
int a = 0;
int b = 0;
int c = a && b;
printf("c = %d\n", c);
if (a || b)
	printf("hehe\n");

Insertar descripción de la imagen aquí


8. Operador condicional

  • El siguiente es un juicio de rama simple y luego asigna un valor a b
int a = 10;
int b = 0;
if (a > 5)
	b = 3;
else
	b = -3;
printf("b = %d\n", b);
  • Pero para el operador ternario, no hay necesidad de ser tan problemático, solo esta oración es suficiente.
  • El significado específico es determinar si a es mayor que 5. Si es así, asigne b a 3. Si no, asigne b a -3.
a > 5 ? b = 3 : b = -3;
  • Pero hay una forma más sencilla de escribirlo, también se juzga de la misma forma y finalmente el valor obtenido se le da a b a la izquierda.
b = (a > 5 ? 3 : -3);

9. Expresión de coma

Primero hablemos de sus reglas de operación: se calcula de izquierda a derecha y el resultado de toda la expresión es el resultado de la última expresión.

  • Aparece una expresión de coma. Puede intentar calcularla usted mismo. Las variables involucradas en la operación cambiarán cada vez que se pase una expresión. Finalmente, los valores impresos de a, byc también han cambiado.
int a = 3;
int b = 5;
int c = 0;
int d = (a += 2, b = b - c + a, c = a + b);
		//a = 5	 b = 10			c = 5 + 10 = 15
printf("d = %d\n", d);
printf("%d %d %d\n", a, b, c);

Insertar descripción de la imagen aquí


10. Otros

[Operador de referencia de subíndice]

  • ¿Qué es el operador de referencia de subíndice? Es decir [ ], el tamaño de la matriz que especificamos al definir la matriz.
int arr[10] = {
    
     0 };
arr[4] = 5;
printf("%d\n", arr[4]);
  • Para el código anterior, llamamos arr4 a los dos operadores de []
  • Recordemos el operador [+]. Este es un operador binario. Por ejemplo, 2 + 3, entonces se puede decir que 2 3 son los dos operadores de + . Para nosotros, 2 + 3 se puede escribir como 3 + 2, ya que Los operadores binarios se pueden intercambiar de esta manera, ¿se puede usar [operador de referencia de subíndice]? ¡La respuesta es sí! ! !
  • También podemos escribir el código anterior así.
int arr[10] = {
    
     0 };
4[arr] = 5;
printf("%d\n", 4[arr]);

Lo siguiente es este operador llamado [Llamada de Función]

int Add(int x, int y)
{
    
    
	return (x + y);
}
int main()
{
    
    
	int c = Add(2, 3);	//()是函数调用操作符,操作数是:Add 2 3
	printf("c = %d\n", c);
	return 0;
}
  • Está muy claro que son los dos paréntesis fuera de la función. También mencionamos esto cuando hablamos del operador sizeof() arriba. Para sizeof(), aunque tiene (), no puede considerarse como una función. También ser un operador
  • Luego, para el operador de llamada de función, consulte la función Agregar arriba, () es el operador, luego el operando es Agregar 2 3

12. Palabras clave comunes

1. Introducción

Ahora que entendemos los operadores comunes en lenguaje C, echemos un vistazo a las palabras clave en lenguaje C.

  • En primer lugar, para las palabras clave, los dos puntos a los que debemos prestar atención son

    1. Las palabras clave se utilizan directamente, debemos comprender
    2. Los nombres de las variables no pueden ser palabras clave

  • Como se puede ver a continuación, todavía hay muchas palabras clave en lenguaje C.

Insertar descripción de la imagen aquí

  • Primero hablemos de [auto] por separado, es bastante especial porque en el compilador, cuando defines una variable, existe de forma predeterminada.
  • Auto, traducido como automático, se refiere a variables automáticas en lenguaje C. Todas las variables locales que usted define se crean y destruyen automáticamente, por lo que todas las variables locales se modifican automáticamente.
  • Al igual que la variable entera a a continuación, no se informará ningún error si agrega auto delante de int o no. La razón es que todas las variables locales son automáticas.
//auto int a = 10;
int a = 10;	//auto可以省略

2. Los principios subyacentes del almacenamiento de datos.

  • En cuanto a los registros, implica el almacenamiento de datos, hablemos de ello en detalle para que todos puedan comprender primero el principio subyacente.

En primer lugar, necesita saber dónde se almacenan los datos en la computadora.

①Memoria ②Disco duro ③Caché ④Registrar

Entonces echemos un vistazo a esta imagen.
Insertar descripción de la imagen aquí

  • Para los registros en la computadora, el espacio es en realidad muy pequeño y la unidad es solo bytes, pero su velocidad de lectura y escritura es muy rápida y puede interactuar directamente con la CPU [unidad central de procesamiento].

  • Luego el espacio se va haciendo más grande conforme vas bajando, la memoria ahora es generalmente de 8G, 16G, y más grande, 32G, no como 2MB hace mucho tiempo, para los discos duros, cuando vamos al mercado a comprarlos, también son 500G, 1 T. tamaño

  • Nuestro registro, debido a que su velocidad de lectura es muy rápida, la CPU obtiene directamente los datos del registro, pero ¿qué debemos hacer si la memoria del registro no es lo suficientemente grande en este momento? Si no puede instalar tanto, el caché tal como lo conocemos, es decir, el caché, proporcionará memoria para el registro. Si no hay suficiente en el caché, la memoria continuará proporcionándola . De esta manera, se mejora la eficiencia operativa general de la computadora.

  • El siguiente es el uso de la palabra clave [registro]. Agregar esta palabra clave al definir la variable b significa [recomendar] al compilador poner esta variable en un registro. Cabe señalar aquí que es solo una sugerencia, no ponerla directamente entrar

  • Puedes consultar información sobre cómo usarlo específicamente, no entraré en demasiados detalles aquí.

//建议把b放到寄存器中
register int b = 10;

3. palabra clave typedef

La primera es esta [typedef]. Esta palabra clave se usa para cambiar el nombre y se usa más comúnmente en estructuras.

typedef struct Linknode{
    
    
	int data[MaxSize];
	struct Linknode* next;
}LNode;
  • Por supuesto, no solo se aplica a estructuras, sino que también se puede cambiar el nombre para algunos tipos de datos, como el siguiente [unsigned int], más adelante, cuando uses [uint] para definir variables, será lo mismo que [unsigned En t].
typedef unsigned int uint;

int main()
{
    
    
	unsigned int num1 = 0;
	uint num2 = 0;	//与num1一样
	return 0;
}

4. palabra clave estática

Finalmente, hablemos de la palabra clave estática.

  • Aquí hay una charla sobre la palabra clave estática en lenguaje C. En primer lugar, debe comprender qué se puede usar para modificar la palabra clave estática. Se puede usar principalmente para modificar los siguientes tres
    • Modificar variables locales
    • Modificar variables globales
    • función modificada
4.1 La palabra clave estática modifica las variables locales

Primero, echemos un vistazo a la modificación estática de variables locales.

void test()
{
    
    
	int a = 3;
	a++;
	printf("%d ", a);
}
int main()
{
    
    
	int i = 0;
	while (i < 10)
	{
    
    
		test();
		i++;
	}
	return 0;
}
  • ¿Qué crees que generará el programa anterior? Viendo el programa principal, se usa un bucle while para controlar la variable i. Cuando i = 10, el borde no entrará en el bucle, por lo que se repetirá 10 veces. Luego mire la función interna test(). Cada vez que esta función se llama en el bucle, define una variable a, luego cámbiala a 4 después de ++ y luego genera
  • Entonces, el resultado de ejecutar este programa es que generará 10 4s.

Insertar descripción de la imagen aquí

  • Luego modificamos la variable definida a y la configuramos como una variable estática, es decir, agregamos una modificación estática delante de int
  • Entonces, ¿qué crees que imprimirá el programa anterior en este momento?
static int a = 3;
  • Primero, es necesario comprender las características de las variables estáticas y las diferencias entre otras variables ordinarias.

① Las variables locales ordinarias se colocan en el área de pila de la memoria. Al ingresar al alcance local, la variable se crea y la variable
se destruye al salir del alcance local. ② Cuando static modifica la variable local, la variable local La variable abre espacio en el área estática. En este momento, la variable local Las variables no se destruyen cuando salen del alcance. La próxima vez que ingresen al alcance, se utilizarán los datos sobrantes de la última vez (la ubicación de almacenamiento). se cambia, del área de pila al área estática, lo que cambia el ciclo de vida de la variable)

  • Sabiendo esto, debes saber cuál es el resultado impreso, 4~13cada vez que ingresas a esta función test(), esta variable a ya no se ejecutará, es decir, solo se definirá cuando ingreses a esta función por primera vez, y entonces Siempre existirá y no se destruirá hasta el final de este programa, por lo que esta variable a retiene cada vez es el resultado después del último ++

Insertar descripción de la imagen aquí

  • Después de ver los resultados anteriores, creo que también tiene una comprensión preliminar de los miembros modificados por variables estáticas: las variables locales ordinarias se almacenan en el área de la pila. Pero para las variables estáticas, ¿sabe dónde se almacenan?
  • Así es, en cuanto al área estática, usemos la siguiente imagen para comprender cómo se almacenan las variables en la memoria de la computadora.
4.2 La palabra clave estática modifica las variables globales

agregar.c:

int g_val = 2022;

prueba.c:

extern int g_val;	//声明外部符号
int main()
{
    
    
	printf("%d\n", g_val);
	return 0;
}
  • La declaración de variable global anterior y la llamada a la palabra clave [externa] declaran una variable, pero ¿qué sucede si la variable g_val se define como una variable estática? vamos a ver

Insertar descripción de la imagen aquí

  • Como puede ver, este comando externo no se puede analizar.

    Las variables globales tienen atributos de enlace externo. Si la variable global se modifica mediante estática, el atributo de enlace externo se convierte en un atributo de enlace interno y otros archivos fuente ya no podrán encontrar este símbolo a través del enlace.

  • Por lo tanto, se puede concluir que las variables locales modificadas por estática solo se pueden usar dentro del archivo .c donde se encuentran ~

4.3 La palabra clave estática modifica funciones
  • De hecho, el concepto es el mismo: si no usa modificación estática, entonces puede usar la palabra clave extern para hacer una introducción, entonces es un enlace externo, pero si usa modificación estática, entonces esta función solo puede ser Se usa en el archivo fuente original, no Se puede usar para archivos externos. Este es un enlace interno.

Insertar descripción de la imagen aquí

  • Como puedes ver, por el mismo motivo, este es un enlace interno y no se puede acceder desde el exterior, ni siquiera con la palabra clave extern.

13. #define define constantes y macros

  • Primero hablemos de este #define para definir constantes.
#define MAX 100
int main()
{
    
    
	printf("%d\n", MAX);
	int a = MAX;
	int arr[MAX] = {
    
     0 };

	printf("%d\n", a);
	return 0;
}
  • Al ver el código anterior, utilicé #define para definir una constante MAX con un valor de 100. En la función principal, puedes usar esta constante directamente para imprimirla y asignarle valores.

  • Por supuesto, además de definir constantes de datos enteros, también son posibles otros tipos, como cadenas.

#define STR "abcdef"
printf("%s\n", STR);

Después de hablar sobre el uso de #define para definir constantes, hablemos de la definición de macro, que también se declara usando #define.

  • A continuación se muestra una función de suma y cómo escribir una suma de definición de macro.
//函数
int Add(int x, int y)
{
    
    
	return x + y;
}
//宏
#define ADD(x,y) ((x) + (y))	//为了保持整体性

Además de la función de suma, puedes definir otras funciones. Por ejemplo, para comparar el valor mayor de dos números, puedes escribirlo de la siguiente manera, usando un operador ternario.

#define MAX(x,y) ((x) > (y) ? (x) : (y))

14. puntero

1. Introducción

  • Con respecto a los punteros, muchos estudiantes han escuchado de otros cuando comenzaron a aprender el lenguaje C que los punteros son difíciles y difíciles, y operaciones como acceder a la memoria y tomar direcciones son peligrosas y difíciles.

2. Concepto e introducción de la memoria

  • En cuanto a los punteros, están directamente relacionados con la memoria de la computadora, así que hablemos primero del conocimiento relacionado con la memoria y dejemos que todos comprendan primero el conocimiento subyacente.

  • En cuanto a la memoria, deberías haber oído hablar de ella en la vida diaria, como las tarjetas de memoria que compramos para computadoras y notebooks, y la memoria de nuestros teléfonos móviles, para esta memoria suele ser 8G o 16G, que es similar a la memoria. El correspondiente es el disco duro , que suele ser de 500G o 1T.

  • En una computadora, la memoria es un espacio de almacenamiento continuo, pero esto no se puede asignar a cada parte para su uso. En este momento, la memoria se divide en pequeñas unidades de memoria. Para acceder efectivamente a cada parte de la unidad de memoria, la unidad de memoria está numerado y estos números se denominan dirección de la unidad de memoria.

Insertar descripción de la imagen aquí

  • En el diagrama anterior, puede ver intuitivamente cómo se almacena la memoria en la computadora. El tamaño de cada unidad de memoria es de un byte y luego están numerados, de modo que cuando el mundo exterior necesite acceder a ella, puede especificar un acceso basado en este número de memoria. Cada uno de estos números en realidad se llama dirección.

Después de conocer el concepto básico de dirección, vayamos al compilador para ver cómo se divide esta dirección.

  • Primero, veamos la oración de código más simple, que es definir una variable a. Todos sabemos que las variables enteras int ocupan 4 bytes en la memoria. Pongamos un punto de interrupción en este código e ingresemos a la ventana de memoria para echar un vistazo. todo
int main()
{
    
    
	int a = 4;
}

Insertar descripción de la imagen aquí

  • Ingrese esto [&a], y podrá ver las 4 unidades de memoria abiertas para la variable a en la memoria. La primera dirección comienza desde [0x00CFF814]. La variable entera ocupa 4 bytes. Mire los 4 I enmarcados, por cada byte que tiene. su propio número, &a es la dirección del primer byte.

Insertar descripción de la imagen aquí

  • Entonces, ¿cómo usamos el código para obtener esta dirección?
&a		//	拿到的值第一个字节的地址
  • Echemos un vistazo nuevamente a través de la ventana de depuración. Obviamente obtuvimos los resultados que queríamos.

Insertar descripción de la imagen aquí

  • O si no desea ir a la ventana de depuración para verlo, también está bien.
  • Podemos imprimirlo directamente con printf. Puedes ver que aquí se usa %p, que es específicamente para el acceso a la dirección. Si eres %d, lo que sale es el número formateado.

Insertar descripción de la imagen aquí

  • Después de hablar sobre memoria y dirección, el siguiente paso es el puntero real, pero de hecho, para la dirección, es un puntero. El puntero es un alias de la dirección. Veamos cómo se define el puntero.
int a = 4;
int* pa = &a;
  • Como puede ver, agregué un asterisco [*] después del tipo int, lo que significa que esta es una variable de tipo puntero. Este pa es una [variable de puntero], porque como se mencionó anteriormente, un puntero es un alias para una dirección, entonces esto La ecuación está establecida. La variable de puntero pa puede recibir la dirección de a y también almacena la dirección de a.

Insertar descripción de la imagen aquí


  • Dado que esta variable de puntero almacena la dirección de la variable, ¿es posible acceder a esta dirección a través de esta variable de puntero e imprimirla? La respuesta es sí, esto involucra nuestro siguiente punto de conocimiento, que es la desreferencia del puntero.

  • Utilice el operador [*]

*pa
  • Como se definió anteriormente, pa es una variable de puntero. *pa en realidad encuentra el espacio donde se almacena esta dirección a través de la dirección almacenada en pa. Lo que se obtiene en este momento es en realidad la variable a. Debido a que se obtiene esta dirección, todas las variables en este espacio es El punto de partida del almacenamiento es el contenido de la variable a. Veámoslo ejecutando

Insertar descripción de la imagen aquí

resumen

①El puntero es en realidad la dirección, y la dirección es el número de la unidad de memoria
②Cuando se almacena la dirección, se puede colocar en una variable, que es la [variable de puntero]
③El puntero del que estamos hablando en realidad se llama [puntero] en términos profesionales Variable]
④[*] La desreferenciación de Asterisk puede acceder rápidamente a la ubicación donde está almacenada la variable en la memoria a través de la dirección donde está almacenada la variable, y luego obtener el contenido.

3. El tamaño de la variable de puntero.

  • Para encontrar el tamaño de una variable, use sizeof()esta palabra clave
int a = 10;
printf("%d\n",sizeof(a));
printf("%d\n",sizeof(int));
  • El código anterior imprime 4 4. ¿Qué pasa con el siguiente código?
int a = 10;
int* pa = &a;
printf("%d\n",sizeof(pa));
printf("%d\n",sizeof(int*));
  • Obviamente también es 4 4

Insertar descripción de la imagen aquí

  • En la esquina superior izquierda del compilador, hay x64 y x86. Esto se llama [Entorno de ejecución]. Ahora lo cambié a 64 bits.

Insertar descripción de la imagen aquí

  • Obviamente, el mismo código produce valores diferentes en diferentes entornos operativos.

Insertar descripción de la imagen aquí

  • Las variables de puntero almacenan direcciones, por lo que el tamaño de la variable de puntero depende de cuánto espacio se necesita para almacenar una dirección.

Debe ver que no es una dirección, sino una línea de dirección almacenada. Sí, es la línea de dirección en el hardware.

  • La computadora que usamos es en realidad hardware. Si es hardware, debe estar encendido. De hecho, existe una [línea de dirección] en nuestra computadora. Los 32 bits y 64 bits que mencionamos anteriormente también pueden corresponder a esto Entre las líneas de dirección, porque en un entorno de 32 bits, hay 32 líneas de dirección, en un entorno de 64 bits, hay 64 líneas de dirección.
  • Cuando tenemos 32 líneas de dirección, habrá una señal eléctrica después del encendido. Esta señal eléctrica es 0/1. Entonces, ¿cómo son exactamente estas señales eléctricas? Echemos un vistazo.

Insertar descripción de la imagen aquí

  • Es un método de almacenamiento como 0101, y luego, según el sistema binario, se enumeran cuántas direcciones se pueden almacenar en estas 32 líneas de direcciones. Aquí para decirles, hay un total de 232 direcciones que se pueden almacenar.
  • Entonces podemos sacar la conclusión de que una secuencia de direcciones compuesta por 32 0 o 1 requiere 32 bits, que son 4 bytes, para almacenarse , y estos 4 bytes corresponden al tamaño de nuestra variable de puntero. Entonces podemos descubrir por qué el tamaño de la variable puntero es de 4 bytes
  • Entonces expliquemos por qué esta variable de puntero se convierte en 8 bytes en un entorno de 64 bits. De hecho, también puedes deducirlo tú mismo. Una secuencia de direcciones compuesta por 32 0 o 1 requiere 32 bits, por lo que aquí necesitamos 64 bits, según 1B. = 8 bits, por lo que se necesitan 8 bytes para almacenar . También se puede concluir que el tamaño de la variable de puntero en un entorno de 64 bits es de 8 bytes.

Después de comprender lo anterior, sabemos que el tamaño de las variables de puntero depende del tamaño de la dirección. Echemos un vistazo al tamaño de estas variables de puntero. Estoy ejecutando en un entorno de 32 bits.

printf("%d\n", sizeof(short*));
printf("%d\n", sizeof(long*));
printf("%d\n", sizeof(long long*));
printf("%d\n", sizeof(float*));
printf("%d\n", sizeof(double*));
  • ¿Es 1 4 8 4 8? Si esta es la respuesta, regrese y observe atentamente el proceso de derivación anterior.
  • Echemos un vistazo a los resultados.

Insertar descripción de la imagen aquí

  • Como puede ver, son 4. Todas son variables de puntero. ¿Cuál es el tamaño de una variable de puntero? Es el tamaño de la dirección. Como se mencionó anteriormente, estoy ejecutando en un entorno de 32 bits, por lo que es 32. La línea de dirección requiere 32 bits, que son 4 bytes para almacenar

  • Como puede ver, se informan muchas advertencias. ¿A qué se debe esto? Obviamente, este código se puede ejecutar y también puede producir resultados. Aquí, se informa un problema [no coinciden los símbolos]. ¿Por qué? Permítanme aclarar aquí que cuando sizeof() calcula el tamaño de los bytes de datos, el tipo de retorno predeterminado es unsigned int, que es un entero sin signo. Sin embargo, %d se usa para imprimir variables enteras, por lo que [entero sin signo] aparece aquí .problema de coincidencia]

Insertar descripción de la imagen aquí

  • Deberías modificarlo y pedirle a %zu que lo imprima. Solo recuerda que se usa especialmente para imprimir el valor de retorno de sizeof(). No importa si no lo entiendes en profundidad.
  • Modifique de la siguiente manera: puede ver que no hay más Advertencia.

Insertar descripción de la imagen aquí

15. Estructura

La estructura también es una parte importante del lenguaje C, porque el lenguaje C es un lenguaje orientado a procesos. No está orientado a objetos como C++ y Java. Tiene clases, y las variables miembro y los métodos miembro se pueden definir dentro de la clase. , entonces Hay una estructura en C que se puede utilizar para describir objetos complejos.

  • Todos hemos ido a las librerías a comprar libros, sabemos que un libro tiene título, editorial y autor, todos estos se pueden definir como tipos de personajes, pero también está el precio del libro, ¿cómo definirlo? ¿También se puede definir como un tipo de carácter? Por supuesto que no, todavía se define como un tipo de punto flotante. Además de estos, en realidad hay muchos tipos que deben definirse.
  • Pero para tantos tipos, ¿tienen que estar separados? Esto definitivamente no es posible, por lo que este libro no será un todo. Si tiene pensamiento orientado a objetos, sabrá que todos sus atributos y comportamientos están definidos en esta clase. Todos están encapsulados, esta es la encapsulación de clases.
  • En lenguaje C, también podemos implementar la encapsulación, es decir, usar estructuras.

Usamos el tipo de estudiante para hacer un paquete.

  • Como puede ver, hemos utilizado la palabra clave struct, que es la palabra clave que pertenece al módulo de palabras clave y que se explicará aquí. stu es la abreviatura de estudiante. Como puede ver, hay tres tipos, a saber, nombre, edad y calificaciones . Debido a que un estudiante tiene estos tres atributos, que son sus atributos comunes, se pueden empaquetar juntos.
struct stu {
    
    
	char name[20];		//姓名
	int age;			//年龄
	float score;		//成绩
};
  • Entonces, ¿cómo definir variables para la inicialización de tipos compuestos como estructuras?
  • De hecho, es lo mismo que las variables ordinarias. Debe considerar [struct stu] como un tipo. Las variables definidas con este tipo se denominan [variables de estructura]. Para la inicialización de cada variable de estructura, un par de llaves {} , ingrese para inicializar las variables que definió en la estructura una por una en orden.
  • Recordatorio: el tipo de puntuación flotante aquí va seguido de los tipos f y doble como distinción.
struct stu s1 = {
    
     "zhangsan",20,80.5f };
struct stu s2 = {
    
     "lisi",25,90.5f };

Entonces, ¿cómo imprimir estas variables después de inicializarlas y luego acceder a la información de cada alumno?

  • Aquí necesitamos usar el operador de punto [.] que dejamos anteriormente, este operador puede acceder a la información de la variable actual a través de las variables declaradas en la estructura, el código es el siguiente:
//格式:结构体变量.结构体成员
printf("%s %d %f\n", s1.name, s1.age, s1.score);
printf("%s %d %f\n", s2.name, s2.age, s2.score);

Bien, mi primera introducción al lenguaje C termina aquí. Más adelante clasificaré todo el contenido del lenguaje C. ¡Espero que sea útil para todos! ! ! ¡Vamos a trabajar juntos!

Supongo que te gusta

Origin blog.csdn.net/2201_76004325/article/details/134981046
Recomendado
Clasificación