2016-09-29 1 views
0

Hier ist ein Code, den ich für GCC Compiler schrieb.Interessantes Verhalten von malloc()

#include <stdio.h> 
#include <stdlib.h> 

int main() 
{ 
    int *p; 
    p = (int *)malloc(9 * sizeof(char)); 
    p[0] = 2147483647; 
    p[1] = 2147483647; 
    p[2] = 1025; 
    printf("%d, %d, %d, %d\n", sizeof(char), *(p), *(p+1), *(p+2)); 
} 

Die Ausgabe ist wie folgt:

1, 2147483647, 2147483647, 1025 

Meine Frage ist, obwohl ich nur 9 Bytes auf den Zeiger zugeordnet, Es scheint, die 12 alle Bytes zu verwenden. Das Ergebnis ist dasselbe (abgesehen von einer Compiler-Warnung), wenn ich (char *) anstelle von (int *) umsetze. Ist die Zuordnung malloc() ein Vollkreis? d. h. es teilt immer in Vielfachen des Datentyps des Zeigers zu, unabhängig davon, was wir zugeordnet haben? oder ist es implementierungsspezifisch?

+2

Sollten Bits by Bytes? PS - Du brauchst die Besetzung nicht. –

+0

Sie haben etwas nicht legales getan und niemand bemerkt. macht es legal? –

+0

Danke. Ich korrigierte –

Antwort

7
p = (int *)malloc(9 * sizeof(char)); 

Was Sie tun, ist undefined behavior, wenn die Größe der Ganzzahl 4 Bytes ist. Weil du 9 Bytes zugewiesen und 12 benutzt hast.

Casting hat keine Wirkung, eigentlich solltest du kein Ergebnis von malloc in C überhaupt werfen.

Ein weiterer Ort, an dem Sie nicht definiertes Verhalten ausgelöst wird, die falsche Formatangabe für sizeof verwenden, sollten Sie %zu statt %d in printf (für sizeof) verwenden.

+0

Danke. Sollte ich es korrigieren? –

+1

@UmeshCG Natürlich sollten Sie. (Lesen Sie auch den angegebenen Link) –

+0

Der korrekte Formatbezeichner für 'sizeof' ist' "% zu" ', da er nicht vorzeichenbehaftet ist. – mch

1

Die Tatsache, dass Sie in die "extra" Bytes schreiben konnten, bedeutet nicht, dass sie Ihnen zugewiesen wurden; es bedeutet nur, dass sie existieren. Sie haben keinen Grund zu erwarten, dass sich diese Bytes in Zukunft nicht "magisch" ändern werden, da Sie sie nicht zugewiesen haben, und wenn ein anderer Code dies getan hat, könnten Sie sie ändern (und, anders als Ihr Code, legitim).

+0

Sie wollen sagen, es ist nicht legitim und ich bin glücklich, dass das Programm nicht abgestürzt ist? –

+2

@UmeshCG Ich würde sagen, unglücklich. –

3

Wie andere erwähnt haben, schreiben Sie nach dem Ende eines Pufferspeichers. Dies ruft undefined behavior auf.

Was undefined Verhalten bedeutet, dass alles passieren kann. Das Programm kann abstürzen, es kann zu unerwarteten Ergebnissen kommen oder (in diesem Fall) scheint es richtig zu funktionieren.

Eine scheinbar nicht zusammenhängende Codeänderung könnte Ihr Programm plötzlich zum Absturz bringen.

Um zu zeigen, was hier geschieht, ist die Ausgabe von läuft Ihr Programm unter valgrind:

[dbush] valgrind /tmp/x1 
==19430== Memcheck, a memory error detector 
==19430== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al. 
==19430== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info 
==19430== Command: /tmp/x1 
==19430== 
==19430== Invalid write of size 4 
==19430== at 0x40050E: main (x1.c:11) 
==19430== Address 0x4c18048 is 8 bytes inside a block of size 9 alloc'd 
==19430== at 0x4A0610C: malloc (vg_replace_malloc.c:195) 
==19430== by 0x4004E9: main (x1.c:8) 
==19430== 
==19430== Invalid read of size 4 
==19430== at 0x40051C: main (x1.c:12) 
==19430== Address 0x4c18048 is 8 bytes inside a block of size 9 alloc'd 
==19430== at 0x4A0610C: malloc (vg_replace_malloc.c:195) 
==19430== by 0x4004E9: main (x1.c:8) 
==19430== 
1, 2147483647, 2147483647, 1025 
==19430== 
==19430== HEAP SUMMARY: 
==19430==  in use at exit: 9 bytes in 1 blocks 
==19430== total heap usage: 1 allocs, 0 frees, 9 bytes allocated 
==19430== 
==19430== LEAK SUMMARY: 
==19430== definitely lost: 9 bytes in 1 blocks 
==19430== indirectly lost: 0 bytes in 0 blocks 
==19430==  possibly lost: 0 bytes in 0 blocks 
==19430== still reachable: 0 bytes in 0 blocks 
==19430==   suppressed: 0 bytes in 0 blocks 
==19430== Rerun with --leak-check=full to see details of leaked memory 
==19430== 
==19430== For counts of detected and suppressed errors, rerun with: -v 
==19430== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 4 from 4) 

Sie sind von diesem Ausgang sehen können, dass Sie nach dem Ende Ihrer zugewiesenen Puffer lesen und zu schreiben.

+0

Danke für die Demonstration! –

1

In C können Zeiger zu jedem Speicher gehen, den sie wollen. In Ihrem Code haben Sie nur 9 Bytes zugewiesen. Da die C-Sprache keine Überprüfung bietet, können Sie den Zeiger einfach an einen beliebigen Ort bewegen. Aber es bedeutet nicht, dass Sie die Kontrolle über diese Speicherorte haben. Es kann dazu führen, sigsegv, Anwendung Absturz oder AccessViolationException (wenn dieser Code nativ von einer anderen Sprache wie C# oder Java verwendet wird). Diese Bytes können auch von einem anderen Programm geändert werden, das Ihre Daten beschädigen kann.