[Lenguaje C] Explicación detallada de la estructura

¿Qué es una estructura?

Antes de aprender cada tipo necesitamos entender el significado de su existencia, es decir¿Qué es una estructura?¿Por qué introducir el tipo de estructura??
¿Podemos imaginar cómo procesamos la información de una persona en la realidad? Supongamos que queremos resumir la información personal de cada compañero de clase, en este momento, ¿crearemos una tabla separada para el nombre, la edad y otra información de cada persona? Obviamente no. Por lo general, a cada persona se le entrega un formulario de recopilación de información, en el que se puede completar el nombre, la edad, el peso y otra información de cada persona.
En el lenguaje C, las estructuras de datos en forma de tablas de recopilación de información se implementan a través de estructuras. Entre ellos, el nombre, la edad y otra información son variables miembro de la estructura.Obviamente las variables miembro de estas estructuras pueden ser de diferentes tipos de datos.
Después de introducir el tipo de estructura, cuando queremos representar un trabajo como información del estudiante,Esto reducirá en gran medida la creación de variables, reducirá nuestra carga de trabajo y mejorará la legibilidad del código.

Declaración de estructura

Lo anterior explica qué es una estructura y por qué se introduce el tipo de estructura. A continuación, presentaremos la estructura en detalle, comenzando con la declaración de la estructura :

struct tag
{
    
    
     member-list;//成员名
}variable-list;

Tomemos como ejemplo la información del estudiante:

struct Stu
{
    
    
     char[20] name;//姓名
     int age;//年龄
     double height;//身高
};//分号不能丢

Cada variable de estructura aquí tiene tres tipos diferentes de miembros: name(nombre del estudiante), age(edad del estudiante), height(altura del estudiante). Entre ellos, el nombre de la estructura Stuse denomina nombre de la estructura (etiqueta de estructura), {}y la declaración name, ageetc., se denominan miembros de la estructura (lista de miembros).

Creación e inicialización de variables de estructura.

Tipo de estructura anónima

Al declarar una estructura, no es necesario declararla completamente , por ejemplo:

struct
{
    
    
     int a;
     char b;
     float c;
}x;

La etiqueta de estructura anterior se omite cuando se declara. Pero hay una cosa a tener en cuenta:Básicamente, los tipos de estructura anónimos solo se pueden utilizar una vez si no se cambia el nombre del tipo de estructura.

Autorreferenciación de estructuras

Pensemos en esta pregunta: ¿Está bien incluir un miembro del tipo de la estructura misma en la estructura?
Por ejemplo, defina los nodos de una lista vinculada:

struct Node
{
    
    
     int data;//保存的数据
     struct Node next;//下一个结构体
};

¿Es correcto el código anterior? Si es correcto, sizeof(struct Node) ¿cuánto es eso?
Después de un análisis cuidadoso, en realidad no es posible, porque una estructura contiene una variable de estructura del mismo tipo. Se puede comparar con una función recursiva sin restricciones. De esta manera, el tamaño de la variable de estructura será infinito, lo cual no es razonable. .de.
Código correcto:

struct Node
{
    
    
     int data;
     struct Node* next;
};

Que struct Node* nextes un puntero a la siguiente estructura, de modo que las dos estructuras también se pueden encadenar.


En el proceso de uso de la autorreferencia de la estructura, typedefestá involucrado cambiar el nombre del tipo de estructura anónima, lo que fácilmente puede causar problemas. Eche un vistazo al siguiente código: ¿es factible?

typedef struct
{
    
    
     int data;
     Node* next;
}Node;

La respuesta es no, porque Nodese debe al cambio de nombre del tipo de estructura anónima anterior, pero Nodeno es factible usar el tipo para crear variables miembro por adelantado dentro de la estructura anónima.
La solución es la siguiente: no utilice estructuras anónimas al definir estructuras.

typedef struct Node
{
    
    
     int data;
     struct Node* next;
}Node;

Inicialización de la estructura.

Inicialización normal

De hecho, la forma de asignar un valor inicial a una estructura es la misma que la de un array. Los valores iniciales de cada miembro de la estructura están ordenados en {}secuencia y separados por comas. Si no se asigna ningún valor inicial al miembro, se inicializa en 0.

struct Stu //类型声明
{
    
    
     char name[15];//名字
     int age; //年龄
};
struct Stu s = {
    
    "zhangsan", 20};//初始化
struct Node
{
    
    
     int data;
     struct Stu s;
     struct Node* next; 
}n1 = {
    
    10, {
    
    "zhangsan", 20}, NULL}; //结构体嵌套初始化
struct Node n2 = {
    
    20, {
    
    "zhangsan", 20}, NULL};//结构体嵌套初始化

Los valores en el inicializador deben aparecer en el orden de los miembros de la estructura. En este ejemplo, Stulos miembros de la estructura nameson "zhangsan"y los miembros ageson 20.Al igual que las matrices, las expresiones utilizadas en los inicializadores de estructuras deben ser constantes.


Especificar inicialización

Indica el método de inicialización (C99), que permite la inicialización no en el orden de los miembros.
como sigue:

struct Stu
{
    
    
     int age;
     char name[15];
     float weight;
};
struct Stu s = {
    
    .weight=75.5f, .age=20, .name="zhangsan"};//初始化

Ventajas de especificar inicializadores:

  1. Fácil de leer y fácil de verificar, porque el lector puede ver claramente la correspondencia entre los miembros en la estructura y los valores en el inicializador;
  2. No es necesario que el orden de los valores en el inicializador sea coherente con el orden de los miembros en la estructura y no afecta el inicializador especificado.

Los valores enumerados en el inicializador especificado no necesariamente tienen que ir precedidos de un mensaje, como en el siguiente ejemplo:

struct Stu s = {
    
    .weight=75.5f, .age=20, "zhangsan"}

No hay ningún indicador delante del valor "zhangsan", por lo que el compilador asumirá que se utiliza para inicializar agelos miembros posteriores de la estructura. Los miembros que no participan en la fórmula de inicialización se establecen en 0.

Alineación de la memoria de la estructura

Reglas de alineación

Hemos dominado el uso básico de las estructuras. Ahora analizamos en profundidad un problema: calcular el tamaño de una estructura .
Las reglas de alineación específicas son las siguientes:

  1. El primer miembro de la estructura está alineado con el desplazamiento de dirección 0 en relación con la posición inicial de la variable de estructura.
  2. Otras variables miembro deben alinearse con direcciones que sean múltiplos enteros de un determinado número (logaritmo).
    Número de alineación = El valor más pequeño del número de alineación predeterminado del compilador y el tamaño de la variable miembro.
  • El valor predeterminado en VS es 8
  • No hay un número de alineación predeterminado en Linux, el número de alineación es el tamaño del miembro mismo.
  1. El tamaño total de la estructura es un múltiplo entero del número de alineación máximo (cada variable miembro en la estructura tiene un número de alineación, que es el mayor de todos los números de alineación).
  2. Si una estructura está anidada y los miembros de la estructura anidada están alineados con un múltiplo entero del número máximo de alineación de sus propios miembros , el tamaño total de la estructura es el número máximo de alineación de todos los miembros (incluido el número de alineación del miembros en la estructura anidada). ) es un múltiplo entero.

Eche un vistazo a los siguientes ejemplos:

//练习1
struct S1
{
    
    
     char c1;
     int i;
     char c2;
};
printf("%d\n", sizeof(struct S1));//---12

Análisis del ejercicio 1:

variable tamaño variable Número de alineación predeterminado Número de alineaciones
c1 1 8 1
i 4 8 4
c2 1 8 1

De la tabla anterior, podemos imaginar su almacenamiento aproximado en memoria:
Insertar descripción de la imagen aquí


//练习2
struct S2
{
    
    
     char c1;
     char c2;
     int i;
};
printf("%d\n", sizeof(struct S2));//---8

Almacenamiento en memoria:
Insertar descripción de la imagen aquí


Modificación del número de alineación predeterminado

#pragma Esta directiva de preprocesamiento puede cambiar el número de alineación predeterminado del compilador.

#pragma pack(4);//设置默认对齐数为4

Cuando la alineación de la estructura es inapropiada, podemos cambiar nosotros mismos el número de alineación predeterminado.

Paso de parámetros de estructura

Hay dos operadores de acceso a miembros de la estructura: uno es y .el otro es ->,
el formulario es el siguiente:

结构体变量.成员变量名
结构体指针—>成员变量名

Compara las siguientes funciones Print1de suma Print2, ¿cuál es mejor?

struct S
{
    
    
     int data[1000];
     int num;
};
struct S s = {
    
    {
    
    1,2,3,4}, 1000};
//结构体传参
void Print1(struct S s)
{
    
    
    printf("%d\n", s.num);
}
//结构体地址传参
void Print2(struct S* ps)
{
    
    
     printf("%d\n", ps->num);
}
int main()
{
    
    
     Print1(s); //传结构体
     Print2(&s); //传地址
     return 0;
}

De hecho, Print2es mejor y he aquí por qué:

  1. Cuando una función pasa parámetros, los parámetros deben insertarse en la pila, lo que provocará una sobrecarga del sistema en el tiempo y el espacio.
  2. Si se pasa un objeto de estructura y la estructura es demasiado grande, la sobrecarga del sistema al insertar parámetros en la pila será relativamente grande, lo que provocará una degradación del rendimiento.

En resumen, conclusión: al pasar parámetros a una estructura, se debe pasar la dirección de la estructura.


Supongo que te gusta

Origin blog.csdn.net/2301_77404033/article/details/133085796
Recomendado
Clasificación