2016-12-20 2 views
0

Ich habe Schwierigkeiten beim Lernen der dynamischen Speicherzuweisung in C. Ich habe dies in main.Einen Wert des Speichers außerhalb des zugewiesenen Speichers setzen

int *a = malloc(sizeof(int)); 
printf("%d %d %d\n", *a, *(a + 1), *(a + 2)); 
*a = 4; 
printf("%d %d %d\n", *a, *(a + 1), *(a + 2)); 
a = realloc(a, sizeof(int) * 2); 
printf("%d %d %d\n", *a, *(a + 1), *(a + 2)); 
*(a + 1) = 8; 
printf("%d %d %d\n", *a, *(a + 1), *(a + 2)); 
*(a + 2) = 16; 
printf("%d %d %d\n", *a, *(a + 1), *(a + 2)); 

Es ausgedruckt ..

7417176 7405760 706735178 
4 7405760 958328410 
4 7405760 958328410 
4 8 958328410 
4 8 16 

Wie Sie mich umverteilt a zu einer neuen Größe von ~ 8 Bytes sehen. Aber ich initialisierte *(a + 2) bis 16 während, wie Sie sehen können, ich nur ~ 8 Bytes nicht mehr zugewiesen (es benötigt mindestens 12 Bytes). Wie ist das möglich?

+3

Willkommen in C, komm her, wir müssen über Speicherverwaltung sprechen. Sie haben ein UB beim ersten Aufruf von 'printf()', '* (a + 1)' weil es außerhalb des Rahmens liegt. Und du hast UB beim zweiten Aufruf von 'printf()', weil du nicht init '* (a + 1)' initest hast. Sie sollten etwas über C lesen, bevor Sie versuchen, in C zu codieren. – Stargateur

+2

'* (a + 1)': 1st: Lesen des Wertes außerhalb der Grenzen. 2.: Lesen des nicht initialisierten Wertes. – BLUEPIXY

+0

@Stargateur Ja, ich habe nicht init * (a + 1) auf 'Zweck'. Wenn wir einen neuen Speicher zuweisen, hat er den Wert nicht initialisiert, richtig? Woher weiß ich also, dass diese Erinnerung mir gehört, damit ich den Wert festlegen kann? – Ortimh

Antwort

1

Ihr Programm hat ein undefiniertes Verhalten, wenn Sie auf Speicher zugreifen, der Ihrem Programm nicht zugewiesen wurde.

bei einigen Details der Suche:

int *a = malloc(sizeof(int)); 

// This part is fine. It will try to allocate the amount of memory 
// needed for storing exactly 1 int. It will assign the pointer a with 
// with a value that points to the allocated memory. 

Jedoch kann die malloc ausfallen (das heißt nicht in der Lage, die Menge an Speicher benötigt zuzuteilen) so müssen Sie prüfen, ob es fehlgeschlagen. Wenn malloc fehlschlägt, wird NULL zurückgegeben. So müssen Sie hinzufügen:

if (a == NULL) 
{ 
    // malloc failed... 
    // print error 
    exit(1); 
} 

nächste Zeile ist:

printf("%d %d %d\n", *a, *(a + 1), *(a + 2)); 

// This is undefined behavior: 
//  *a will read the value of the memory just malloc'ed as an int 
//  In principle that is OK but since you didn't initialize the 
//  memory, it is still undefined behavior 
// 
//  *(a+1) and *(a+2) will read memory after the memory malloc'ed 
//  So you access memory not allocated to you. That is undefined 
//  behavior 

Was sollten Sie tun, um 1) initialisieren Sie den Speicher erste und 2) nur Zugriffsspeicher Ihnen zugeordnet. Wie:

*a = 42; 
printf("%d\n", *a); 

Die nächste Zeile:

a = realloc(a, sizeof(int) * 2); 

// In principle this is valid. However, it is not good as realloc may 
// fail just like malloc. 

So sollten Sie tun:

int* temp = realloc(a, sizeof(int) * 2); 
if (temp == NULL) 
{ 
    // Error handling or just exit... 
    free(a); 
    exit(1); 
} 
a = temp; 

Für den Rest des Codes haben Probleme ähnlich wie die oben erwähnten.

Aber ich initialisiert * (a + 2) bis 16 während, wie Sie sehen können, ich nur ~ 8 Bytes nicht mehr zugewiesen (es benötigt mindestens 12 Bytes). Wie ist das möglich?

Die Sprache C überprüft nicht, ob alles, was Sie tun, gültig ist. Mit anderen Worten - C lässt Sie tun, wonach Sie fragen. Es liegt in Ihrer eigenen Verantwortung sicherzustellen, dass Sie nur gültige Dinge tun.

Zur Laufzeit erkennt das System möglicherweise, dass das Programm illegale Aktivitäten ausführt. Wenn so ein Absturz (Core Dump) passieren wird.

Es gibt jedoch viele Situationen, in denen das System nicht erkennen kann, dass Ihr Programm etwas Illegales tut. Also wird das Programm einfach weitergehen. Das kann zu allen möglichen seltsamen Fehlern führen, aber es sieht auch so aus, als ob das Programm die ersten 100 Mal korrekt ist, wenn Sie es ausführen und dann das nächste Mal fehlschlagen. Das ist, was undefiniertes Verhalten ist .... undefined - Sie werden nie wissen, was passieren kann.

Die Codierung in C bedeutet eine große Belastung für Sie. Es ist sehr einfach, illegale Dinge in C zu tun. Es liegt in Ihrer Verantwortung sicherzustellen, dass Sie nur legale Dinge tun.

Heute stehen eine Reihe von Werkzeugen zur Verfügung, um C zu analysieren und falschen Code zu finden, z.B. Valgrind und Coverity.

Verwandte Themen