Linguagem C avançada - reconheça a estrutura

insira a descrição da imagem aqui
1 Conhecimento básico de estrutura

Uma estrutura é uma coleção de valores chamados variáveis ​​de membro. Cada membro da estrutura pode ser uma variável de um tipo diferente.

2 Declaração de estrutura

struct tag
{
    
    
 member-list;
}variable-list;

Se descrevermos um aluno abaixo, vamos pensar no nome do aluno, série, sexo, etc., então podemos usar a estrutura para criar tal variável para conter esses conteúdos.

struct stu
{
    
    
	char name[20];
	int age;
	char sex[5];
	double score;
};

3 Avisos especiais

Ao declarar uma estrutura, ela pode estar incompleta.

por exemplo

//匿名结构体类型
struct
{
    
    
 int a;
 char b;
 float c;
}x;
struct
{
    
    
 int a;
 char b;
 float c;
}a[20], *p;

Essas estruturas só podem ser usadas uma vez, pois não há tag de estrutura para formar um tipo, então a estrutura anônima só pode ser usada uma vez.
Perceber! ! !

A estrutura anônima só pode ser usada uma vez, então não podemos realizar algumas operações, como

//在上面代码的基础上,下面的代码合法吗?
p = &x;

O compilador irá tratá-los como dois tipos completamente diferentes, então p não pode armazenar o endereço de x

4 Auto-referenciação de estruturas

É correto ter um membro em uma estrutura que seja do tipo da própria estrutura?

Cabe ressaltar aqui que não contém variáveis ​​de estrutura, mas contém ponteiros de estrutura desse tipo (é um ponteiro, abra os olhos grandes do seu Kazilan para ver), não pode ter esse tipo de estrutura em uma estrutura! ! !
Vejamos um exemplo

//代码2
struct Node
{
    
    
 int data;
 struct Node* next;
}

next é um ponteiro de estrutura e o tipo de ponteiro é struct Node.
Erro de código

struct Node
{
    
    
 int data;
 struct Node;
}

Esta é a estrutura da estrutura errada, somos ponteiros, não variáveis.

Olhando para um código abaixo

//代码3
typedef struct
{
    
    
 int data;
 Node* next;
}Node;
//这样写代码,可行否?

Isso equivale a redefinir uma estrutura anônima, que equivale a um poeta recluso da antiguidade que foi puxado por você para a luta. Você acha isso razoável? Embora pareça razoável, deve ser uma minoria, certo? !
Também é equivalente a se a galinha ou o ovo vem primeiro. Nossa estrutura ainda não foi criada, mas há ponteiros nela, e não há nenhum tipo de estrutura, então vamos renomeá-la, então deve ser o errado código correto

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

5 Definição e inicialização de variáveis ​​de estrutura
Declarar tipos e criar variáveis

struct stu
{
    
    
	char name[20];
	int age;
	char sex[5];
	double score;
}s1,s2;

Crie variáveis ​​s1 e s2 ao declarar a estrutura.
Atribua valores ao inicializar

struct stu
{
    
    
	char name[20];
	int age;
	char sex[5];
	double score;
}s1,s2;
int main()
{
    
    
	struct stu s3 = {
    
     "张三",18,"男",99.9 };
	return 0;
}

Estruturas contêm métodos de estruturas

//初始化:定义变量的同时赋初值。
struct Point p3 = {
    
     x, y };
struct Stu        //类型声明
{
    
    
	char name[15];//名字
	int age;      //年龄
};
struct Stu s = {
    
     "zhangsan", 20 };//初始化
struct Node
{
    
    
	int data;
	struct Point p;
	struct Node* next;
}n1 = {
    
     10, {
    
    4,5}, NULL }; //结构体嵌套初始化
struct Node n2 = {
    
     20, {
    
    5, 6}, NULL };//结构体嵌套初始化

6 Alinhamento de memória estrutural
Este é o conteúdo mais importante deste capítulo. Vou explicar o método em detalhes e dar um exemplo para ilustrar.
Primeiro, veja as regras
Como calcular?
Primeiro, você deve dominar as regras de alinhamento da estrutura:

  1. O primeiro membro está no deslocamento 0 da variável de estrutura.
  2. Outras variáveis ​​de membro devem ser alinhadas a um endereço que seja um múltiplo inteiro de um determinado número (número de alinhamento).
    Alinhamento = alinhamento padrão do compilador e o menor valor do tamanho do membro.
    O valor padrão no VS é 8
  3. O tamanho total da estrutura é um múltiplo inteiro do alinhamento máximo (cada variável de membro possui um alinhamento).
  4. Se uma estrutura for aninhada, a estrutura aninhada será alinhada a um múltiplo inteiro de seu próprio alinhamento máximo e o
    tamanho geral da estrutura será um múltiplo inteiro de todos os alinhamentos máximos (incluindo o alinhamento da estrutura aninhada).

por exemplo

#include<stdio.h>
struct S1
	
{
    
    
	char c1;
	int i;
	char c2;
};
int main()
{
    
    
	printf("%zd\n", sizeof(struct S1));
}

insira a descrição da imagem aqui

Como começamos do zero, o char na estrutura ocupa apenas um byte, e conforme nossa segunda regra, o alinhamento mínimo do inteiro é 4, então nosso inteiro deve começar com 4 múltiplos, então descemos quatro bytes da posição de 4 para a posição de 7, e outro tipo de char está exatamente na posição de 8, mas nosso tamanho total deve ser um múltiplo inteiro do número máximo de alinhamento, aqui O número de alinhamento é o número máximo de alinhamento da estrutura, então é um múltiplo de 4, ou seja, 12, exatamente na posição de 11, então o tamanho ocupado é 12.

Vamos dar uma olhada nos resultados
insira a descrição da imagem aqui
, então vamos dar outro exemplo para uma compreensão mais profunda

struct S3
{
    
    
	double d;
	char c;
	int i;
};
#include<stdio.h>
int main()
{
    
    
	printf("%d\n", sizeof(struct S3));
}

insira a descrição da imagem aqui
insira a descrição da imagem aqui

Na verdade, é o mesmo que a explicação acima. Começa de 0 no início e, em seguida, double é oito bytes de memória, porque é o mesmo valor que nosso número de alinhamento padrão, então o número de alinhamento é 8 e um char ocupa uma palavra. Seção, o alinhamento mínimo do próximo int é 4, então temos que começar na posição 12, que é exatamente 16 bytes no total, que também é um múltiplo inteiro do nosso alinhamento máximo double, então o a resposta é 16.

Vamos falar do tamanho de uma estrutura aninhada, acredito que todos também vão esquecer

struct S3
{
    
    
	double d;
	char c;
	int i;
};

struct S4
{
    
    
	char c1;
	struct S3 s3;
	double d;
};
#include<stdio.h>
int main()
{
    
    
	printf("%d\n", sizeof(struct S4));
}

insira a descrição da imagem aqui
insira a descrição da imagem aqui
Então, na posição de 31, por exemplo, 0 é apenas 32, que é um múltiplo de nosso número máximo de alinhamento de 8, então a resposta é por que há alinhamento de memória em 32? Podemos dividir em dois motivos, um
insira a descrição da imagem aqui
é
um problema de plataforma e o outro é um problema de desempenho.

  1. Razões da plataforma (motivos para portabilidade):
    Nem todas as plataformas de hardware podem acessar quaisquer dados em qualquer endereço; algumas plataformas de hardware podem buscar apenas determinados tipos
    de dados em determinados endereços, caso contrário, uma exceção de hardware será lançada.
  1. Razões de desempenho:
    estruturas de dados (especialmente pilhas) devem ser alinhadas em limites naturais tanto quanto possível.
    A razão é que para acessar a memória desalinhada, o processador precisa fazer dois acessos à memória; enquanto os acessos à memória alinhados requerem apenas
    um

O alinhamento de memória da estrutura é a prática de trocar espaço por tempo.
Então, como devemos projetar a estrutura para garantir que ela economize espaço e memória?
Podemos projetar dessa maneira, colocando pequenos bytes na frente, como char type Put o primeiro, seguido pelo curto, que pode economizar espaço.Por
exemplo, as listas de membros das duas estruturas a seguir são as mesmas, mas seus tamanhos de bytes são diferentes.

//例如:
struct S1
{
    
    
 char c1;
 int i;
 char c2;
};
struct S2
{
    
    
 char c1;
 char c2;
 int i;
};

Os membros dos tipos S1 e S2 são exatamente os mesmos, mas existem algumas diferenças no tamanho do espaço ocupado por S1 e S2.

7 Modifique o alinhamento padrão

#include <stdio.h>
#pragma pack(8)//设置默认对齐数为8
struct S1
{
    
    
	char c1;
	int i;
	char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认
#pragma pack(1)//设置默认对齐数为1
struct S2
{
    
    
	char c1;
	int i;
	char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认
int main()
{
    
    
	//输出的结果是什么?
	printf("%d\n", sizeof(struct S1));
	printf("%d\n", sizeof(struct S2));
	
		return 0;
}

Geralmente definimos para a potência de 2, em vez de completamente irregular como 1 3, por exemplo, em nossa plataforma de máquina de 32 bits, lemos quatro bytes por vez, se for 5, não há Em vez disso, os regulares tem que ser lido duas vezes, então a eficiência não é melhorada.

8 Estrutura Passando Parâmetros
Quando uma estrutura passa parâmetros, na verdade tem o mesmo efeito que nossa função passando parâmetros. Ao passar parâmetros, ela também abre espaço na pilha, e também segue o que costumamos dizer que um parâmetro formal é uma parte temporária de um parâmetro real. copiar


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

Vejamos o código acima, todos pensam se print1 ou print2 é melhor,
a resposta é 2 é melhor

Explique que
pelo fato de passarmos parâmetros na estrutura, se for print, continuará abrindo espaço para armazenamento, o que vai ocupar muito espaço, e o espaço para nosso print2 é no máximo 8 em uma plataforma de 64 bits , pois o que passamos é um Endereço, o endereço é do tamanho de uma variável de ponteiro, ou seja 4 bytes ou 8 bytes, então é melhor passar o endereço

Quando uma função passa parâmetros, os parâmetros precisam ser colocados na pilha, o que causará sobrecarga do sistema no tempo e no espaço.
Se um objeto de estrutura for passado, a estrutura é muito grande e a sobrecarga do sistema de enviar os parâmetros para a pilha é relativamente grande, o que levará a uma
diminuição no desempenho.

Por hoje é só compartilhar, até a próxima, obrigado a todos! ! !

Acho que você gosta

Origin blog.csdn.net/2301_76895050/article/details/132000763
Recomendado
Clasificación