C Programmation

malloc en langage c

malloc en langage c
Vous pouvez venir ici pour deux raisons : soit vous souhaitez allouer du contenu de manière dynamique, soit vous souhaitez en savoir plus sur le fonctionnement de malloc. Dans les deux cas, vous êtes au bon endroit! L'allocation dynamique est un processus qui arrive beaucoup mais généralement nous ne l'utilisons pas nous-mêmes : la grande majorité des langages de programmation gèrent la mémoire pour vous car c'est un travail difficile et si vous ne le faites pas correctement, il y a des implications de sécurité.

Cependant, si vous faites du C, du C++ ou du code assembleur, ou si vous implémentez un nouveau module externe dans votre langage de programmation préféré, vous devrez gérer vous-même votre allocation de mémoire dynamique.

Qu'est-ce que l'allocation dynamique? Pourquoi j'ai besoin de malloc?

Eh bien, dans toutes les applications, lorsque vous créez une nouvelle variable - cela s'appelle souvent déclarer une variable - vous avez besoin de mémoire pour le stocker. Comme votre ordinateur est dans les jours modernes, il peut exécuter plus d'une application à la fois et donc, chaque application doit dire à votre système d'exploitation (ici Linux) qu'il a besoin de cette quantité de mémoire. Quand vous écrivez ce genre de code :

#inclure
#inclure
#define DISK_SPACE_ARRAY_LENGTH 7
void getFreeDiskSpace(int statsList[], size_t listLength)
revenir;

int main()
/* Contient l'espace disque libre des 7 derniers jours. */
int freeDiskSpace[DISK_SPACE_ARRAY_LENGTH] = 0;
getFreeDiskSpace(freeDiskSpace, DISK_SPACE_ARRAY_LENGTH);
renvoie EXIT_SUCCESS ;

Le tableau freeDiskSpace a besoin de mémoire, vous devrez donc demander l'approbation de Linux pour obtenir de la mémoire. Cependant, comme il est évident à la lecture du code source que vous aurez besoin d'un tableau de 7 int, le compilateur le demande automatiquement à Linux, et il l'allouera sur la pile. Cela signifie essentiellement que ce stockage est détruit lorsque vous retournez la fonction où la variable est déclarée. C'est pourquoi tu ne peux pas faire ça :

#inclure
#inclure
#define DISK_SPACE_ARRAY_LENGTH 7
int* getFreeDiskSpace()
int statsList[DISK_SPACE_ARRAY_LENGTH] = 0 ;
/* POURQUOI FAISONS-NOUS ÇA?! statsList sera DÉTRUIT! */
retourner la liste des statistiques ;

int main()
/* Contient l'espace disque libre des 7 derniers jours. */
int *freeDiskSpace = NULL;
freeDiskSpace = getFreeDiskSpace();
renvoie EXIT_SUCCESS ;

Vous voyez plus facilement le problème maintenant? Ensuite, vous voulez concaténer deux chaînes. En Python et JavaScript, vous feriez :

newStr = str1 + str2

Mais comme vous le savez, en C ça ne marche pas comme ça. Ainsi, pour créer une URL par exemple, vous devez concaténer deux chaînes, telles que le chemin de l'URL et le nom de domaine. En C, nous avons strcat, d'accord, mais cela ne fonctionne que si vous avez un tableau avec suffisamment de place pour cela.

Vous serez tenté de connaître la longueur de la nouvelle chaîne en utilisant strlen, et vous auriez raison. Mais alors, comment demanderiez-vous à Linux de réserver cette quantité inconnue de mémoire? Le compilateur ne peut pas vous aider : l'espace exact que vous souhaitez allouer n'est connu qu'à l'exécution. C'est exactement là que vous avez besoin d'allocation dynamique, et malloc.

Écrire ma première fonction C avec malloc

Avant d'écrire du code, une petite explication : malloc vous permet d'allouer un nombre spécifique d'octets pour l'utilisation de votre application. C'est vraiment simple à utiliser : vous appelez malloc avec le nombre d'octets dont vous avez besoin, et il renvoie un pointeur vers votre nouvelle zone que Linux vous a réservée.

Vous n'avez que 3 responsabilités :

  1. Vérifiez si malloc renvoie NULL. Cela se produit lorsque Linux n'a pas assez de mémoire pour fournir.
  2. Libérez vos variables une fois inutilisées. Sinon, vous gaspillerez de la mémoire et cela ralentira votre application.
  3. Ne jamais utiliser la zone mémoire après avoir libéré la variable.

Si vous suivez toutes ces règles, tout se passera bien et l'allocation dynamique vous résoudra de nombreux problèmes. Parce que vous choisissez quand vous libérez la mémoire, vous pouvez également retourner en toute sécurité une variable allouée avec malloc. Juste, n'oublie pas de le libérer!

Si vous vous demandez comment libérer une variable, c'est avec la fonction free. Appelez-le avec le même pointeur que malloc vous a renvoyé, et la mémoire est libérée.

Laissez-moi vous montrer avec l'exemple concat :

#inclure
#inclure
#inclure
/*
* Lors de l'appel de cette fonction, n'oubliez pas de vérifier si la valeur de retour est NULL
* Si ce n'est pas NULL, vous devez appeler free sur le pointeur retourné une fois la valeur
* n'est plus utilisé.
*/
char* getUrl(const char* const baseUrl, const char* const toolPath)
size_t finalUrlLen = 0;
char* finalUrl = NULL;
/* Contrôle de sécurité. */
if (baseUrl == NULL || toolPath == NULL)
renvoie NULL ;

finalUrlLen = strlen(baseUrl) + strlen(toolPath);
/* N'oubliez pas le '\0', d'où le + 1. */
finalUrl = malloc(sizeof(char) * (finalUrlLen + 1));
/* En suivant les règles malloc… */
if (finalUrl == NULL)
renvoie NULL ;

strcpy(finalUrl, baseUrl);
strcat(finalUrl, toolPath);
retourner finalUrl;

int main()
char* googleImages = NULL;
googleImages = getUrl("https://www.Google.com", "/imghp");
if (googleImages == NULL)
renvoie EXIT_FAILURE ;

puts("URL de l'outil :");
met(googleImages);
/* Ce n'est plus nécessaire, libérez-le. */
gratuit(googleImages);
googleImages = NULL ;
renvoie EXIT_SUCCESS ;

Vous voyez donc un exemple pratique d'utilisation des allocations dynamiques. Tout d'abord, j'évite les pièges tels que donner la valeur de retour getUrl directement à la fonction puts. Ensuite, je prends également le temps de commenter et de documenter le fait que la valeur de retour doit être libérée correctement. Je vérifie également les valeurs NULL partout afin que tout ce qui soit inattendu puisse être détecté en toute sécurité au lieu de faire planter l'application.

Enfin, je prends le soin supplémentaire de libérer la variable puis de définir le pointeur sur NULL. Cela évite d'être tenté d'utiliser - même par erreur - la zone mémoire désormais libérée. Mais comme vous pouvez le voir, il est facile de libérer une variable.

Vous remarquerez peut-être que j'ai utilisé sizeof dans malloc. Il permet de savoir combien d'octets un char utilise et clarifie l'intention dans le code afin qu'il soit plus lisible. Pour char, sizeof(char) est toujours égal à 1, mais si vous utilisez un tableau d'entiers à la place, cela fonctionne exactement de la même manière. Par exemple, si vous devez réserver 45 int, faites simplement :

fileSizeList = malloc(sizeof(int) * 45);

De cette façon, vous voyez rapidement combien vous voulez allouer, c'est pourquoi je recommande toujours son utilisation.

Comment fonctionne malloc sous le capot?

malloc et free sont, en fait, des fonctions incluses dans tous les programmes C qui parleront à Linux en votre nom. Cela facilitera également l'allocation dynamique car, au départ, Linux ne vous permet pas d'allouer des variables de toutes tailles.

Linux fournit en fait deux façons d'obtenir plus de mémoire : sbrk et mmap. Les deux ont des limitations, et l'une d'elles est la suivante : vous ne pouvez allouer que des quantités relativement importantes, telles que 4 096 octets ou 8 192 octets. Vous ne pouvez pas demander 50 octets comme je l'ai fait dans l'exemple, mais vous ne pouvez pas non plus demander 5 894 octets.

Cela a une explication : Linux doit conserver une table où il indique quelle application a réservé quelle zone mémoire. Et cette table utilise également de l'espace, donc si chaque octet avait besoin d'une nouvelle ligne dans cette table, une grande part de mémoire serait nécessaire. C'est pourquoi la mémoire est divisée en gros blocs de, par exemple, 4 096 octets, et tout comme vous ne pouvez pas acheter 2 oranges et demie dans une épicerie, vous ne pouvez pas demander des demi-blocs.

Donc malloc prendra ces gros blocs et vous donnera une petite tranche de ces blocs de mémoire chaque fois que vous l'appelez. De plus, si vous avez libéré peu de variables, mais pas assez pour justifier la libération d'un bloc entier, le système malloc peut conserver les blocs et recycler les zones mémoire lorsque vous appelez à nouveau malloc. Cela a l'avantage de rendre malloc plus rapide, cependant la mémoire réservée par malloc ne peut être utilisée dans aucune autre application, alors que le programme ne l'utilise pas actuellement en réalité.

Mais malloc est intelligent : si vous appelez malloc pour allouer 16 Mio ou une grande quantité, malloc demandera probablement à Linux des blocs complets dédiés uniquement à cette grande variable en utilisant mmap. De cette façon, lorsque vous appelez gratuitement, cela évitera plus probablement ce gaspillage d'espace. Ne vous inquiétez pas, malloc fait un bien meilleur travail de recyclage que les humains ne le font avec nos ordures!

Conclusion

Je pense que maintenant tu comprends mieux comment tout ça fonctionne. Bien sûr, l'allocation dynamique est un grand sujet et je pense que nous pouvons écrire un livre complet sur le sujet, mais cet article devrait vous mettre à l'aise avec le concept à la fois en général et avec des conseils de programmation pratiques.

Outils utiles pour les joueurs Linux
Si vous aimez jouer à des jeux sur Linux, il est probable que vous ayez utilisé des applications et des utilitaires comme Wine, Lutris et OBS Studio p...
Jeux HD remasterisés pour Linux qui n'ont jamais eu de version Linux plus tôt
De nombreux développeurs et éditeurs de jeux proposent une remasterisation HD d'anciens jeux pour prolonger la durée de vie de la franchise, veuillez ...
Comment utiliser AutoKey pour automatiser les jeux Linux
AutoKey est un utilitaire d'automatisation de bureau pour Linux et X11, programmé en Python 3, GTK et Qt. En utilisant ses fonctionnalités de script e...