Teknologian jakaminen

Opi C-kieli tyhjästä 33 - Muistinhallinta (1)

2024-07-12

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

1. Perustilanne
C-kielen muistinhallinta on jaettu kahteen osaan: järjestelmänhallintaan ja ohjelmoijan käyttöoppaan hallintaan. Järjestelmän hallitsema muisti on pääosin funktion sisällä olevat muuttujat (paikalliset muuttujat) Tämä osa muuttujista tulee muistiin, kun toiminto on käynnissä , käyttöjärjestelmä poistaa sen automaattisesti muistista. Käyttäjän manuaalisesti hallitsema muisti koostuu pääasiassa muuttujista (globaalit muuttujat), jotka ovat olemassa koko ohjelman ajon aikana. Muistialuetta, jossa tämä osa sijaitsee, kutsutaan "kasa-alueeksi". Nämä muuttujat on vapautettava manuaalisesti käyttäjän toimesta. Jos unohdat vapauttaa sen käytön jälkeen, se jatkaa muistia, kunnes se luovutetaan käyttöjärjestelmälle ohjelman sulkeuduttua.
2. tyhjä osoitin
Tietokoneen muistitilalle on määritetty yksilöllinen osoitekoodi, ja määritetty muistialue löytyy muistiosoittimen kautta. Osoitinmuuttujilla on oltava tyyppi, esimerkiksi: int* p=&x; ilmoittaa int-tyypin osoittimen, joka osoittaa kokonaislukumuuttujan x osoitteeseen tiedot tallennetaan. Kun et ole varma, minkä tyyppistä dataa on tallennettu ja haluat vain löytää ensin lohkomuistin osoitteen, käytetään void type -osoitinta. Tyhjätyyppistä osoitinta kutsutaan myös määrittelemättömän tyypin osoittimeksi ja se voi osoittaa minkä tahansa tyyppiseen tietoon.
Void-tyyppiset osoittimet voidaan muuntaa muun tyyppisiksi osoittimiksi, eikä niiden käytössä ole mitään erityistä, paitsi että tallennettua sisältöä ei voida jäsentää "*"-menetelmällä.
int x = 10 //Ilmoita kokonaislukumuuttuja x
void* p = &x; //Ilmoita void-osoitin ja osoita x:n osoitteeseen, mikä osoittaa, että int-osoitin (&x) muunnetaan void-osoittimeksi.
int* q = p; // void-osoitin muunnetaan takaisin kokonaislukuosoittimeksi
printf("%in", *q ); //Aja tulos: 10
Kiinnitä huomiota eroon void*:n ja void:n välillä: void on tyypitön, ja kun sitä käytetään funktion ilmoittamiseen, se tarkoittaa, että paluuarvoa ei ole, kun taas void*, vaikka se on tyypitön, mutta siinä on osoitin, palauttaa jotain.
3. Muistinhallintaan liittyvät toiminnot
1、malloc()
Tämä funktio voidaan muistaa erikseen m on muistin lyhenne ja alloc on lyhenne allokoinnista.
Toiminto: hae jatkuvaa muistilohkoa kasa-alueelta (muistutus: ohjelmoijan pitää hallita kasaalueen muistia ja se on tuhottava käytön jälkeen. Tämä tulee aina muistaa käyttömuoto: malloc (katso 1);
Parametrit: Parametri 1 on muistilohkon koko (ei-negatiivinen kokonaisluku tyyppiä koko_t, paluuarvo sizeof on tätä tyyppiä)
Palautusarvo: void*-osoitin (käytämme mitä tahansa osoitintyyppiä, jota käytämme varatun muistin vastaanottamiseen)
Käyttö: Malloc-funktiolla ilmoitetut muuttujat ovat kasa-alueella, joten usein käytetään anonyymiä ilmoitusmenetelmää, eli tiettyjen muuttujien osoitemenetelmän sijaan malloc palauttaa osoittimen suoraan alla olevan kuvan mukaisesti:
int* ptr = (int*) malloc(sizeof(int) //Int-osoitinmuuttuja ilmoitetaan kasa-alueella
Suluissa oleva pakotettu muunnos ei ole välttämätön.
Varotoimenpiteet:
a. Käytä malloc-toimintoa sisällyttääksesi<stdlib.h>otsikkotiedosto, kuten vain sisältää<stdio.h> Se käännetään hyvin, mutta ei toimi kunnolla, pidä se mielessä.
b. Määritä arvo ptr:lle: *ptr=1000;.
c. Käytä mallocia yhdessä ilmaisen kanssa (jotka kohtaat myöhemmin).
d. Malloc ei ehkä onnistu varaamaan osoitteita, se palauttaa arvon NULL. Tästä syystä voidaan lisätä if-lause.
e. malloc varaa vain muistia alustuksesta riippumatta, jos alustus vaaditaan.
f. Yleisimmin käytetty tapa mallocille on varata muistia taulukoille ja mukautetuille tietorakenteille.
2、 memset()
Toiminto: Anna alkuarvo jokaiselle tavulle muistilohkossa, johon osoitin osoittaa.
Parametrit: Parametri 1 Kohdemuistiin osoittava osoitin Parametri 2 Kohteen sisältö (int-tyypin ASCII-koodin arvo tai char-tyypin merkki) Parametri 3 Määritettävien tavujen määrä (size_t-tyyppi)
Palautusarvo: Palauttaa osoittimen kohdemuistiin. Vastaanottaminen on merkityksetöntä, sama kuin parametri 1.
Käyttö: memset(ptrDestMem,'A',sizeof(char)*1024) //Määritä merkki A muistilohkon jokaiseen tavuun, jonka pituus on 1024 tavua
Varotoimenpiteet:
a. Otsikkotiedosto, johon tämä funktio kuuluu, on<string.h> , joitain kääntäjiä voidaan käyttää normaalisti ilman tätä otsikkotiedostoa.
b. Huomaa, että memset on tavujen (ei bittien) toiminto. Parametri 3 viittaa siihen, kuinka monta tavua on osoitettava, mikä voi olla pienempi tai yhtä suuri kuin tavujen määrä kohdemuistissa, mutta se ei voi ylittää rajaa.
c. Parametrin 2 arvo ei voi ylittää yhden tavun verran (int-tyyppi 255), jos se ylittää arvon.
2, ilmainen ()
Toiminto: Malloc-pariksi yhdistetty toiminto, jota käytetään vapauttamaan malloc-funktion varaama muisti ja estämään muistivuotoja
Parametrit: malloc-funktion palauttama osoitin
Käyttö: free(ptr);
Varotoimenpiteet:
a. Otsikkotiedostot, jotka on sisällytettävä, kun käytät ilmaista, ovat myös<stdlib.h> , älä unohda.
b. Vapaa-toiminto voidaan suorittaa vain kerran, ja samaa muistiosoitetta ei voi vapauttaa toistuvasti, eikä vapautettua osoitinta voi käyttää uudelleen.
c. On parasta kirjoittaa malloc ja free ensin pareittain ja sitten syöttää muut koodit keskelle unohtamisen estämiseksi.
3、realloc()
re, joka tarkoittaa jälleen allokointilyhennettä, yhdessä tarkoittaa muistin uudelleenallokointia
Toiminto: Muokkaa varatun muistilohkon kokoa (lisää tai vähennä).
Parametrit: Parametri 1, alkuperäisen muistilohkon osoitin, parametri 2, muistilohkon koko lisäyksen tai pienennyksen jälkeen (vielä koko_t-tyyppi)
Palautusarvo: void*-osoitin (voi vastaanottaa alkuperäisen osoitintyypin muuttujan)
Käyttö: void* newPtr=realloc(ptr,sizeof(int)*10);
Varotoimenpiteet:
a. Realloc-funktiota käytettäessä se on myös sisällytettävä<stdlib.h> .
b. Alkuperäisen osoittimen osoittama muistilohko on korvattu uudella osoittimella, joten uusi osoitin on vapautettava, kun ohjelma päättyy, eikä alkuperäistä osoitinta tarvitse vapauttaa, muuten tapahtuu toimintavirhe. esiintyä.
c. realloc ei välttämättä varaa muistia ja palauttaa NULL-arvon, jos se epäonnistuu, joten on parempi lisätä if-käsky sen käsittelemiseksi.
4. Sovellusesimerkkejä

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