Technologieaustausch

C-Sprache von Grund auf lernen 33 – Speicherverwaltung (1)

2024-07-12

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

1. Grundsituation
Die Speicherverwaltung der C-Sprache ist in zwei Teile unterteilt: Systemverwaltung und Programmierer-Benutzerhandbuchverwaltung. Der vom System verwaltete Speicher besteht hauptsächlich aus Variablen (lokalen Variablen), die bei Ausführung der Funktion in den Speicher gelangen , das Betriebssystem entlädt es automatisch aus dem Speicher. Der vom Benutzer manuell verwaltete Speicher besteht hauptsächlich aus Variablen (globalen Variablen), die während des gesamten Programmlaufs vorhanden sind. Der Speicherbereich, in dem sich dieser Teil befindet, wird als „Heap-Bereich“ bezeichnet. Diese Variablen müssen manuell aus dem Speicher freigegeben werden durch den Benutzer. Wenn Sie vergessen, es nach der Verwendung freizugeben, belegt es weiterhin Speicher, bis es beim Beenden des Programms an das Betriebssystem übergeben wird.
2. Leerer Zeiger
Dem Speicherplatz im Computer wird ein eindeutiger Adresscode zugewiesen, und der angegebene Speicherbereich kann über den Speicherzeiger gefunden werden. Zeigervariablen müssen einen Typ haben, zum Beispiel: int* p=&x; deklariert einen Zeiger vom Typ int, der auf die Adresse der Ganzzahlvariablen x zeigt. Wenn der Compiler die Daten von dieser Adresse erhält, weiß er, dass der Typ int ist Daten werden gespeichert. Wenn Sie nicht sicher sind, welche Art von Daten gespeichert sind, und zunächst nur die Blockspeicheradresse ermitteln möchten, wird der Zeiger vom Typ „void“ verwendet. Ein Zeiger vom Typ „void“ wird auch als Zeiger vom unbestimmten Typ bezeichnet und kann auf jeden Datentyp verweisen.
Zeiger vom Typ „void“ können in Zeiger anderer Typen konvertiert werden, und ihre Verwendung hat keine Besonderheiten, außer dass der gespeicherte Inhalt nicht mit der Methode „*“ analysiert werden kann.
int x = 10; //Ganzzahlvariable x deklarieren
void* p = &x; //Deklarieren Sie den void-Zeiger und zeigen Sie auf die Adresse von x, um anzuzeigen, dass der int-Zeiger (&x) in einen void-Zeiger umgewandelt wird.
int* q = p; // Void-Zeiger wird zurück in Integer-Zeiger umgewandelt
printf( "%in", *q ); //Ergebnis ausführen: 10
Beachten Sie den Unterschied zwischen void* und void: void ist typlos und bedeutet bei der Deklaration einer Funktion, dass es keinen Rückgabewert gibt, während void* zwar typlos ist, aber einen Zeiger hat, aber etwas zurückgibt.
3. Funktionen im Zusammenhang mit der Speicherverwaltung
1. malloc ()
Diese Funktion kann separat gespeichert werden, und alloc ist die Abkürzung für Allocation.
Funktion: Beantragen Sie einen kontinuierlichen Speicherblock aus dem Heap-Bereich (Erinnerung: Der Heap-Bereichsspeicher muss vom Programmierer verwaltet und nach der Verwendung zerstört werden. Dies sollte immer beachtet werden. Verwendungsformat: malloc (siehe 1);
Parameter: Parameter 1 ist die Speicherblockgröße (eine nicht negative Ganzzahl vom Typ size_t, der Rückgabewert von sizeof ist von diesem Typ)
Rückgabewert: void* Zeiger (wir verwenden jeden Zeigertyp, den wir verwenden, um den zugewiesenen Speicher zu empfangen)
Verwendung: Die mit der malloc-Funktion deklarierten Variablen befinden sich im Heap-Bereich, daher wird häufig die anonyme Deklarationsmethode verwendet, dh anstelle der Adressmethode bestimmter Variablen gibt malloc den Zeiger direkt zurück, wie unten gezeigt:
int* ptr = (int*) malloc(sizeof(int)); //Eine int-Zeigervariable wird im Heap-Bereich deklariert
Die erzwungene Konvertierung in Klammern ist nicht erforderlich. Malloc gibt void* zurück, was mit int* empfangen werden kann. Die starke Konvertierung erleichtert hier das Verständnis.
Vorsichtsmaßnahmen:
a. Verwenden Sie zum Einbinden die malloc-Funktion<stdlib.h>Header-Datei, z. B. nur enthält<stdio.h> Es lässt sich gut kompilieren, läuft aber nicht richtig, das sollten Sie im Hinterkopf behalten.
b. Weisen Sie ptr einen Wert zu: *ptr=1000;.
c. Verwenden Sie malloc in Verbindung mit free (auf das Sie später noch stoßen werden).
d. Malloc ist möglicherweise nicht erfolgreich bei der Zuweisung von Adressen. Wenn dies nicht gelingt, wird NULL zurückgegeben. Aus diesem Grund kann eine if-Anweisung zur Verarbeitung hinzugefügt werden.
e. malloc reserviert nur Speicher, unabhängig von der Initialisierung. Wenn eine Initialisierung erforderlich ist, muss eine andere Funktion aufgerufen werden.
f. Der am häufigsten verwendete Anlass für Malloc ist die Zuweisung von Speicher für Arrays und benutzerdefinierte Datenstrukturen.
2. memset ()
Funktion: Weisen Sie jedem Byte im Speicherblock, auf den ein Zeiger zeigt, einen Anfangswert zu.
Parameter: Parameter 1 Zeiger, der auf den Zielspeicher zeigt Parameter 2 Zuweisungsinhalt (ASCII-Codewert vom Typ int oder Zeichen vom Typ char) Parameter 3 Anzahl der zuzuweisenden Bytes (Typ size_t)
Rückgabewert: Gibt den Zeiger zurück, der auf den Zielspeicher zeigt. Der Empfang ist sinnlos, genau wie Parameter 1.
Verwendung: memset(ptrDestMem,'A',sizeof(char)*1024) //Weisen Sie jedem Byte eines Speicherblocks mit einer Länge von 1024 Bytes das Zeichen A zu
Vorsichtsmaßnahmen:
a. Die Header-Datei, zu der diese Funktion gehört, ist<string.h> , einige Compiler können normal verwendet werden, ohne diese Header-Datei einzubinden. Wenn ein Lauffehler auftritt, fügen Sie ihn bitte ein.
b. Beachten Sie, dass es sich bei Memset um eine Operation für Bytes (nicht für Bits) handelt. Parameter 3 bezieht sich darauf, wie viele Bytes zugewiesen werden müssen. Diese Anzahl kann kleiner oder gleich der Anzahl der Bytes im Zielspeicher sein, darf jedoch den Grenzwert nicht überschreiten.
c. Der Wert von Parameter 2 darf den Platzbedarf von einem Byte nicht überschreiten (int-Typ 255). Wenn er den Wert überschreitet, kann er nicht geschrieben werden.
2, frei ()
Funktion: Mit malloc gepaarte Funktion, die verwendet wird, um den von der malloc-Funktion zugewiesenen Speicher freizugeben und Speicherlecks zu verhindern
Parameter: Von der Malloc-Funktion zurückgegebener Zeiger
Verwendung: kostenlos(ptr);
Vorsichtsmaßnahmen:
a. Die Header-Dateien, die bei der Verwendung von Free enthalten sein müssen, sind ebenfalls vorhanden<stdlib.h> , vergiss es nicht.
b. Die freie Funktion kann nur einmal ausgeführt werden, und dieselbe Speicheradresse kann nicht wiederholt freigegeben werden, und der freigegebene Zeiger kann nicht erneut verwendet werden.
c. Es ist am besten, zuerst malloc und free paarweise zu schreiben und dann andere Codes in die Mitte einzufügen, um ein Vergessen zu verhindern.
3. Realloc ()
re, was wiederum die Abkürzung „Alloc Allocation“ bedeutet, bedeutet zusammen Neuzuweisung des Speichers
Funktion: Ändern Sie die Größe des zugewiesenen Speicherblocks (erhöhen oder verringern).
Parameter: Parameter 1, ursprünglicher Speicherblockzeiger, Parameter 2, Speicherblockgröße nach Erhöhung oder Verringerung (immer noch Typ size_t)
Rückgabewert: void* Zeiger (kann von der ursprünglichen Zeigertypvariablen empfangen werden)
Verwendung: void* newPtr=realloc(ptr,sizeof(int)*10);
Vorsichtsmaßnahmen:
a. Bei Verwendung der Realloc-Funktion muss diese ebenfalls einbezogen werden<stdlib.h> .
b. Der Speicherblock, auf den der ursprüngliche Zeiger zeigt, wurde durch den neuen Zeiger ersetzt. Daher sollte dieser neue Zeiger freigegeben werden, wenn das Programm endet. Der ursprüngliche Zeiger muss nicht freigegeben werden, da sonst ein Betriebsfehler auftritt geschehen.
c. Realloc kann möglicherweise keinen Speicher zuweisen und NULL zurückgeben, daher ist es besser, eine if-Anweisung hinzuzufügen, um damit umzugehen.
4. Anwendungsbeispiele

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