2016-09-29 19 views
0

ここにはGCCコンパイラ用に書いたコードがあります。次のように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)); 
} 

出力は次のようになります。

1, 2147483647, 2147483647, 1025 

私の質問は、私はポインタにのみ9バイトを割り当てられていますが、すべての12バイトを使用しているようだ、です。 (int *)の代わりに(char *)をキャストした場合、結果は同じです(コンパイラの警告はありません)。 malloc()の割り当てはフルサークルですか?すなわち、割り当てられたものに関係なく、ポインタのデータ型の倍数で常に割り振られますか?それとも具体的な実装ですか?

+2

バイト単位で指定する必要がありますか? PS - キャストは必要ありません。 –

+0

あなたは何か違法な行為をしており、気付いたことはありません。それはそれを合法にしますか? –

+0

ありがとうございます。私は –

答えて

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

整数のサイズが4バイトの場合は、undefined behaviorとします。 9バイトを割り当てて12を使用したため、

キャストは効果がありませんが、実際にはmallocの結果をCにキャストすべきではありません。あなたは未定義の動作を引き起こした

別の場所はsizeofの間違った書式指定子を使用している、あなたは(sizeof用)printf%zu代わりの%dを使用する必要があります。

+0

ありがとうございます。私はそれを修正する必要がありますか? –

+1

@UmeshCGもちろん、あなたはすべきです。 (提供されたリンクも参照してください) –

+0

'sizeof'の正しい書式指定子は符号なしであるため、' '%zu" 'です。 – mch

1

「余分な」バイトに書き込めるということは、割り当てられたという意味ではありません。それらが存在することを意味します。これらのバイトは、割り当てられていないため、将来的には変更されないことを期待する必要はありません。また、他のコードが変更した場合は、変更することができます(コードとは違法です)。

+0

あなたは合法ではないと言っていますが、プログラムがクラッシュしなかったのは幸運です。 –

+2

@UmeshCG私は不運だと思います。 –

3

他の人が触れたように、あなたはmallocされたバッファの最後を超えて書いています。これによりundefined behaviorが呼び出されます。

未定義の動作とは、何かが起こる可能性があることを意味します。プログラムがクラッシュしたり、予期しない結果が発生したり、(この場合は)正常に動作しているようです。

一見無関係なコードを変更すると、突然プログラムが突然クラッシュする可能性があります。ここでは、何が起こっているかを説明するために

は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) 

あなたが読んで、あなたの割り当てられたバッファの末尾を越えて書いているのはこの出力から見ることができます。

+0

デモをありがとう! –

1

Cでは、ポインタは必要なメモリに移動できます。あなたのコードでは、9バイトしか割り当てていません。 C言語はバウンドチェックを提供しないため、ポインタを任意の場所に移動するだけで済みます。しかし、それはあなたがそれらのメモリ位置を制御できるという意味ではありません。 sigsegv、アプリケーションクラッシュまたはAccessViolationException(このコードがC#やJavaなどの他の言語でネイティブに使用されている場合)が発生する可能性があります。また、これらのバイトは、データを破損する可能性のある他のプログラムによって変更することができます。