Partage de technologie

Apprendre le langage C à partir de zéro 33 - Gestion de la mémoire (1)

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

1. Situation de base
La gestion de la mémoire du langage C est divisée en deux parties : la gestion du système et la gestion du manuel d'utilisation du programmeur. La mémoire gérée par le système est principalement constituée des variables (variables locales) à l'intérieur de la fonction. Cette partie des variables entre dans la mémoire lorsque la fonction est en cours d'exécution. Cette partie de la zone mémoire devient la "zone de pile". , le système d'exploitation le décharge automatiquement de la mémoire. La mémoire gérée manuellement par l'utilisateur est principalement constituée de variables (variables globales) qui existent tout au long du processus d'exécution du programme. La zone mémoire où se trouve cette partie est appelée "zone de tas". Ces variables doivent être libérées manuellement de la mémoire. par l'utilisateur. Si vous oubliez de le libérer après utilisation, il continuera à occuper la mémoire jusqu'à ce qu'il soit remis au système d'exploitation à la fermeture du programme.
2. pointeur vide
L'espace mémoire de l'ordinateur se voit attribuer un code d'adresse unique et la zone mémoire spécifiée peut être trouvée via le pointeur de mémoire. Les variables pointeurs doivent avoir un type, par exemple : int* p=&x; déclare un pointeur de type int, qui pointe vers l'adresse de la variable entière x. Lorsque le compilateur récupère les données de cette adresse, il sait que le type int. les données sont stockées. Lorsque vous n'êtes pas sûr du type de données stockées et que vous souhaitez simplement trouver d'abord l'adresse de la mémoire du bloc, le pointeur de type void est utilisé. Un pointeur de type vide est également appelé pointeur de type indéfini et peut pointer vers n’importe quel type de données.
Les pointeurs de type void peuvent être convertis en pointeurs d'autres types, et leur utilisation n'a rien de spécial, sauf que le contenu stocké ne peut pas être analysé via la méthode "*".
int x = 10; //Déclare la variable entière x
void* p = &x; //Déclarez le pointeur void et pointez vers l'adresse de x, indiquant que le pointeur int (&x) est converti en pointeur void.
int* q = p; // le pointeur vide est reconverti en pointeur entier
printf( "%in", *q ); //Exécuter le résultat : 10
Faites attention à la différence entre void* et void : void est sans type, et lorsqu'il est utilisé pour déclarer une fonction, cela signifie qu'il n'y a pas de valeur de retour tandis que void*, bien qu'il soit sans type mais qu'il ait un pointeur, renvoie quelque chose ;
3. Fonctions liées à la gestion de la mémoire
1.malloc()
Cette fonction peut être mémorisée séparément. m est l'abréviation de mémoire, et alloc est l'abréviation d'allocation. Ensemble, ils allouent de la mémoire.
Fonction : demander un bloc de mémoire continu à partir de la zone du tas (rappel : la mémoire de la zone du tas doit être gérée par le programmeur et doit être détruite après utilisation. Il faut toujours s'en souvenir format d'utilisation : malloc (voir 1) ;
Paramètres : Le paramètre 1 est la taille du bloc mémoire (un entier non négatif de type size_t, la valeur de retour de sizeof est de ce type)
Valeur de retour : pointeur void* (nous utiliserons n'importe quel type de pointeur que nous utilisons pour recevoir la mémoire allouée)
Utilisation : Les variables déclarées à l'aide de la fonction malloc se trouvent dans la zone du tas, donc la méthode de déclaration anonyme est souvent utilisée, c'est-à-dire qu'au lieu d'utiliser la méthode d'adresse de variables spécifiques, malloc renvoie directement le pointeur, comme indiqué ci-dessous :
int* ptr = (int*) malloc(sizeof(int)); //Une variable de pointeur int est déclarée dans la zone du tas
La conversion forcée entre parenthèses n'est pas nécessaire. malloc renvoie void*, qui peut être reçu avec int*. La conversion forte ici rend le code plus facile à comprendre.
Précautions:
a. Utilisez la fonction malloc pour inclure<stdlib.h>fichier d'en-tête, tel que contenant uniquement<stdio.h> Il compile bien mais ne fonctionne pas correctement, gardez cela à l'esprit.
b. Attribuez une valeur à ptr : *ptr=1000 ;.
c. Utilisez malloc avec free (que vous rencontrerez plus tard). N'oubliez pas free (ptr);.
d. Malloc peut ne pas réussir à allouer des adresses. S'il échoue, il renverra NULL. Pour cette raison, une instruction if peut être ajoutée pour le traitement.
e. malloc alloue uniquement de la mémoire, quelle que soit l'initialisation. Si une initialisation est requise, une autre fonction doit être appelée.
f. L'occasion la plus couramment utilisée pour malloc est d'allouer de la mémoire aux tableaux et aux structures de données personnalisées.
2. memset()
Fonction : Attribue une valeur initiale à chaque octet du bloc mémoire pointé par un pointeur.
Paramètres : Paramètre 1 Pointeur pointant vers la mémoire cible Paramètre 2 Contenu de l'affectation (valeur de code ASCII de type int ou caractère de type char) Paramètre 3 Nombre d'octets à affecter (type size_t)
Valeur de retour : renvoie le pointeur pointé vers la mémoire cible. Cela n'a aucun sens de recevoir, comme le paramètre 1.
Utilisation : memset(ptrDestMem,'A',sizeof(char)*1024) //Attribuer le caractère A à chaque octet d'un bloc mémoire d'une longueur de 1024 octets
Précautions:
a. Le fichier d'en-tête auquel appartient cette fonction est<string.h> , certains compilateurs peuvent être utilisés normalement sans inclure ce fichier d'en-tête. Si une erreur d'exécution se produit, veuillez l'inclure.
b. Notez que memset est une opération sur les octets (et non sur les bits) ; le paramètre 3 fait référence au nombre d'octets qui doivent être attribués, qui peut être inférieur ou égal au nombre d'octets dans la mémoire cible, mais ne peut pas dépasser la limite.
c. La valeur du paramètre 2 ne peut pas dépasser ce qui peut être pris en charge par un octet (type int 255). Si elle dépasse la valeur, elle ne peut pas être écrite.
2、gratuit()
Fonction : Fonction associée à malloc, utilisée pour libérer la mémoire allouée par la fonction malloc et éviter les fuites de mémoire
Paramètres : pointeur renvoyé par la fonction malloc
Utilisation : gratuit (ptr);
Précautions:
a. Les fichiers d'en-tête qui doivent être inclus lors de l'utilisation de Free sont également<stdlib.h> , n'oublie pas.
b. La fonction libre ne peut être exécutée qu'une seule fois, et la même adresse mémoire ne peut pas être libérée à plusieurs reprises, et le pointeur libéré ne peut pas être réutilisé.
c. Il est préférable d'écrire d'abord malloc et free par paires, puis d'insérer d'autres codes au milieu pour éviter tout oubli.
3, realloc()
re, ce qui signifie encore une fois, allouer l'abréviation d'allocation, ensemble signifie réallocation de mémoire
Fonction : Modifier la taille du bloc mémoire alloué (augmenter ou diminuer).
Paramètres : paramètre 1, pointeur de bloc mémoire d'origine, paramètre 2, taille du bloc mémoire après augmentation ou diminution (toujours de type size_t)
Valeur de retour : pointeur void* (peut être reçu par la variable de type pointeur d'origine)
Utilisation : void* newPtr=realloc(ptr,sizeof(int)*10);
Précautions:
a. Lors de l'utilisation de la fonction de réallocation, elle doit également être incluse.<stdlib.h> .
b. Le bloc mémoire pointé par le pointeur d'origine a été remplacé par le nouveau pointeur, donc le nouveau pointeur doit être libéré à la fin du programme. Le pointeur d'origine n'a pas besoin d'être libéré, sinon une erreur de fonctionnement se produira.
c. realloc peut ne pas parvenir à allouer de la mémoire et renvoyer NULL en cas d'échec, il est donc préférable d'ajouter une instruction if pour y remédier.
4. Exemples d'applications

  1. #include<stdio.h>
  2. #include<stdlib.h> //malloc、free、realloc
  3. #include<string.h> //memset
  4. int main(void)
  5. {
  6. //A void指针的使用
  7. float PI = 3.14159;
  8. void* pPI = &PI;
  9. float r = 2.5;
  10. printf("半径2.5圆的面积:%fn", r * r * *(float*)pPI);//*(float*)pPI—pPI强转为float指针后再解出指向的值
  11. //B malloc、memset、free函数使用
  12. int n = 8;
  13. void* pMyMem = malloc(sizeof(char)*n); //char占1字节,malloc分派n字节的内存,返给void指针
  14. if (pMyMem == NULL)return 0; //若分派内存失败,程序结束
  15. void* myMem2=memset(pMyMem,'B',sizeof(char)*8); //对malloc分派的内存区块个字节都写入字符'B'。
  16. //并用myMem2接收返回的指针
  17. if (pMyMem == myMem2)printf("memset写入区块指针与其返回的指针相同n");
  18. char* transCh = pMyMem; //将void指针转成char型指针
  19. printf("显示写入内容:");
  20. for (int i = 0; i < n; i++)
  21. {
  22. printf("%c ", *transCh); //显示写入的字符
  23. transCh++;
  24. }
  25. printf("n");//换行
  26. free(pMyMem); //释放malloc函数分派的内存
  27. //free(ch); //只有malloc分派的内存才需要释放,且只释放一次(这里会报错)
  28. //C realloc、free函数的使用
  29. int* pMem = malloc(sizeof(int)*5);
  30. if (pMem == NULL)return 0;
  31. for (int i = 0; i < 5; i++) pMem[i] = (i+1)*10;
  32. for (int i = 0; i < 5; i++) printf("%i ", pMem[i]);
  33. printf("n重新增加分派内存后n");
  34. int* newpMem = realloc(pMem, sizeof(int) * 10);
  35. if (newpMem == NULL)return 0;
  36. for (int i = 0; i < 10; i++) newpMem[i] = (i + 1) * 10;
  37. for (int i = 0; i < 10; i++)printf("%i ", newpMem[i]);
  38. free(newpMem); //释放realloc的内存
  39. //free(pMem);//pMem已被重置,不能再释放,此语句会造成运行失败
  40. getchar(); //暂停屏幕
  41. return 0;
  42. }