Représentation en mémoire de données structurées (variables, pointeurs, tableaux, chaînes, structures et unions) en C

représentation structurée des données

1. Adresse mémoire :

Toutes les données sont stockées dans la mémoire.
La mémoire est une séquence numérotée d'octets commençant par 0x. Ce nombre calcule l'adresse mémoire.
Habituellement, après la compilation, le nom de la variable et le type de la variable ont disparu, remplacés par l'adresse mémoire.

insérez la description de l'image ici

Deuxièmement, la disposition de la mémoire des variables globales et des variables locales

A travers un exemple, observez leurs adresses mémoire

#include<stdio.h>
/*全局未初始化变量*/
int global_int1;
int global_int2;
/*全局初始化变量*/
int global_int3=1;
int global_int4=1;
int main(){
    
    
    /*局部未初始化变量*/
    int local_int1;
    int local_int2;
    /*局部初始化变量*/
    int local_int3=1;
    int local_int4=1;

    printf("全局变量的值:%d   %d   %d    %d\n",global_int1,global_int2,global_int3,global_int4);
    printf("局部变量的值:%d   %d   %d    %d\n",local_int1,local_int2,local_int3,local_int4);
    printf("初始化的全局变量地址:%#x   %#x\n",&global_int3,&global_int4);
    printf("未初始化的全局变量地址:%#x   %#x\n",&global_int1,&global_int2);
    printf("局部变量地址:%#x    %#x    %#x    %#x\n",&local_int1,&local_int2,&local_int3,&local_int4);
}

résultat de l'opération

全局变量的值:0   0   1    1
局部变量的值:35   8   1    1
初始化的全局变量地址:0x402000   0x402004
未初始化的全局变量地址:0x40506c   0x405068
局部变量地址:0x61fefc    0x61fef8    0x61fef4    0x61fef0

En regardant les valeurs dans les résultats d'exécution, nous trouvons:

Les variables globales non initialisées semblent être initialisées à 0 d'une manière ou d'une autre, mais les variables locales ne sont pas initialisées.

Ensuite, nous observons la valeur de l'adresse et constatons que :
pour les variables locales :

Toutes les variables locales sont allouées de manière contiguë et, lorsqu'elles sont agrégées, les
variables augmentent vers des adresses inférieures.

Pour les variables globales :

Les variables initialisées se trouvent dans un cluster et celles qui ne sont pas initialisées se trouvent dans un autre.
Les variables non initialisées se développent vers des adresses inférieures et les variables initialisées se développent vers des adresses supérieures.

Explication : Augmentez de 4 à la fois, car le type int occupe 4 octets.
insérez la description de l'image ici

3. Représentation des données en mémoire

Nous devons d'abord réaliser une chose, qu'est-ce qu'un pointeur ?

Le pointeur stocke l'adresse mémoire, ce qui est aussi la flexibilité du langage C. Pour une explication détaillée des pointeurs, vous pouvez afficher les pointeurs en langage C

Alors réfléchissons à une question, pouvons-nous utiliser un type char pour lire des données int ?

La réponse est oui car ils sont tous deux représentés en bits bruts dans le matériel.

Ceci est lié au stockage des données en mémoire, voyons un exemple :

#include<stdio.h>
int main(){
    
    
    int i=0x8041;
    char *p;
    p=(char*)&i;
    printf("%#x\n",*p);
}

Quel sera son résultat ?

//运行结果
0x41

Que se passe-t-il?
La variable i ressemble à ceci en mémoire :
insérez la description de l'image ici

Le type de caractère char n'occupe qu'un octet, donc seul 41 est lu ;

Testez-le si vous changez la valeur en 0x12345678 ;

#include<stdio.h>
int main(){
    
    
    int i=0x12345678;
    char *p;
    p=(char*)&i;
    printf("%#x\n",*p);
}

Le résultat de la course est

0x78

codage

Il spécifie le mappage des valeurs aux bits, c'est-à-dire quelle séquence de bits représente quel entier et quelle séquence de bits représente quel caractère
Il spécifie combien de bits sont nécessaires pour un type particulier, disons int, 4 octets, 32 bits sont nécessaires
en fonction de l'ordinateur et Le
compilateur d'encodage que nous utilisons fait le travail et gère ces détails pour nous.

Quatrièmement, la représentation du tableau en mémoire

définition de tableau

une séquence d'éléments d'un type uniforme

allocation de mémoire

Organiser les éléments du tableau en mémoire dans l'ordre croissant

#include<stdio.h>
int main(){
    
    
    int a=0;
    int intArray[5]={
    
    1,2,3,4,5};
    int b=6;
}

Représentation de la mémoire :
insérez la description de l'image ici

Pointeurs vs tableaux

intArray+N=&(intArray[N])
intArray[N]=*(intArray+N)

Tableaux de types multi-octets
Voir un exemple :

#include<stdio.h>
int main(){
    
    
    int intArray[10]={
    
    1,2,3,4,5,6,7,8,9,10};
    int *p=(int*)((char*)intArray+7);
    printf("%#x\n",*p);
}

résultat de l'opération :

0x300

Que se passe-t-il?
insérez la description de l'image ici
Écrivez un tableau à deux dimensions quand vous avez le temps

5. Représentation des chaînes en mémoire

En c, il n'y a pas de type chaîne
Une chaîne est un tableau de caractères terminé par le caractère '\0' (également appelé caractère nul)

Dans les bibliothèques de chaînes standard courantes, telles que char *strcat(char *dest,char *src), la première adresse du tableau de chaînes est transmise dans la fonction, alors pourquoi ne pas transmettre la longueur du tableau ? Personnellement, c'est l'une des raisons pour lesquelles les chaînes se terminent par le caractère '\0' (également appelé caractère nul), qui peut être utilisé pour traverser.

Exemple:

#include<stdio.h>
int main(){
    
    
    int i;
    char a[4]="hi?";
    char b[3]="hi?";//错误写法,很危险
    for(i=0;i<4;i++){
    
    
        printf("%#x:%c(%d)\n",&a[i],a[i],a[i]);
    }
    printf("\n");
    for(i=0;i<3;i++){
    
    
        printf("%#x:%c\n",&b[i],b[i]);
    }
    puts(b);
}

résultat de l'opération

0x61fef8:h(104)
0x61fef9:i(105)
0x61fefa:?(63)
0x61fefb: (0)

0x61fef5:h
0x61fef6:i
0x61fef7:?
hi?hi?

Que se passe-t-il?
insérez la description de l'image ici

6. Représentation des structures et syndicats en mémoire

Les types de données agrégées sont capables de stocker plusieurs données distinctes à la fois. C fournit deux types de types de données agrégées, des tableaux et des structures.
Un tableau est une collection d'éléments du même type, chacun étant sélectionné par référence d'indice ou par indirection de pointeur.
Une structure est également une collection de valeurs appelées ses membres, mais les membres d'une structure peuvent avoir des types différents.
Les indices d'éléments de tableau sont accessibles par indice car les éléments de tableau ont la même longueur.
Cependant, ce n'est pas le cas dans les structures. Étant donné que les membres d'une structure sont de longueurs différentes, ils ne sont pas accessibles à l'aide d'indices, à la place chaque membre de la structure a son propre nom et ils sont accessibles par leur nom.

Avant d'aborder la mémoire d'une structure, regardons la déclaration de la structure :

Exemple 1 : Cette déclaration crée une variable nommée x avec trois membres : un entier, un caractère et un nombre à virgule flottante.

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

Exemple 2 : cette instruction crée y et z. y est un tableau qui contient 20 structures. z est un pointeur vers une structure de ce type.

struct{
    
    
    int a;
    char b;
    float c;
}y[20],*z;

Les variables membres de ces deux structures sont les mêmes, sont-elles du même type ?

La réponse est non, ces deux déclarations sont traitées comme deux types distincts par le compilateur. C'est -à-dire z=&xque c'est illégal.

Donc la question est, si je veux continuer à utiliser le type déclaré auparavant, dois-je le créer dans une déclaration séparée ?

La réponse est non, vous pouvez utiliser des balises. Les balises permettent à plusieurs déclarations d'utiliser la même liste de membres. Comme suit:

struct SIMPLE{
    
    
    int a;
    char b;
    float c;
};
struct SIMPLE x;
struct SIMPLE y[20],*z;
z=&x;//这时候是合法的;

Une meilleure pratique pour déclarer des structures consiste cependant à typedefcréer un nouveau type en utilisant ce qui suit :

typedef struct{
    
    
    int a;
    char b;
    float c;
}SIMPLE;//此时SIMPLE是个类型名而不是结构标签

SIMPLE x;
SIMPLE y[20],*z;

Entrez dans le sujet : Regardons le stockage réel de la structure en mémoire
Voyons d'abord un exemple

#include<stdio.h>
int main(){
    
    
    typedef struct {
    
    
        char a;
        char b;
        int c;
        double d;
    }test;
    test x;
    printf("%#x\n%#x\n%#x\n%#x\n",&x.a,&x.b,&x.c,&x.d);
    printf("%d",sizeof(x));
}

résultat de l'opération :

0x61fef0
0x61fef1
0x61fef4
0x61fef8
16

insérez la description de l'image ici
Pourquoi cela est-il ainsi? Ensuite, vous devez comprendre les règles d'alignement du stockage de la mémoire dans la structure :

1. Le compilateur alloue de l'espace pour chaque membre un par un dans l'ordre de la liste des membres
2. L'alignement d'une structure est le même que l'alignement maximum de ses éléments
3. La taille d'une structure est un multiple de son alignement
4 .K octets de taille Les données doivent être stockées à une adresse qui est un multiple entier de K

Modifiez un peu cet exemple :

#include<stdio.h>
int main(){
    
    
    typedef struct {
    
    
        char a;
        char b[4];
        int c;
        double d;
    }test;
    test x;
    printf("%#x\n%#x\n%#x\n%#x\n",&x.a,&x.b,&x.c,&x.d);
    printf("%d",sizeof(x));
}
0x62fe00
0x62fe01
0x62fe08
0x62fe10
24

insérez la description de l'image ici

Alors pourquoi l'aligner de cette façon ? Ne serait-ce pas une perte de place ?

Il est lié à la façon dont le processeur gère la mémoire, ce qui peut améliorer les performances du système et accélérer la vitesse d'accès aux données.

Alors, qu'est-ce que l'union ?

Contrairement à une structure, chaque membre d'une union partage un morceau de mémoire, et un seul d'entre eux est sélectionné lorsqu'il est utilisé.

Stockage en mémoire des structures

L'espace occupé dépend du plus grand élément de l'union

voir un exemple

#include<stdio.h>
int main(){
    
    
    typedef union{
    
    
        char a;
        char b[4];
        int c;
        double d;
    }test;
    test x;
    printf("%#x\n%#x\n%#x\n%#x\n",&x.a,&x.b,&x.c,&x.d);
    printf("%d",sizeof(x));
}

Structure de fonctionnement :

0x61fef8
0x61fef8
0x61fef8
0x61fef8
8

Je suppose que tu aimes

Origine blog.csdn.net/weixin_47138646/article/details/122017208
conseillé
Classement