2012-03-12 23 views
0

配列サイズに関するコードで大きな誤りがあったことに気がついたときに私が書いたコードで少しのテストを行ってきました。 ここには何が起こっているのかを知るための簡単なコードがあります。構造体の宣言されていない配列にデータが格納されています

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

typedef struct 
{ 
int score; 
}player; 

void printScore(player *p, int num); 

int main(void) 
{ 

    printf ("\nEnter number of players (1 - 4)\n"); 
    scanf ("%d", &numPlayers); 

    player *p = (player*)malloc(sizeof(player) * 3); 

    for (i=0;i<numPlayers;i++) 
    { 
     printScore(p, i); 
    } 

} 

void printScore(player *p, int num) 
{ 

     p[num].score = 1; 
     printf ("%d\n", p[num].score); 
} 

実際には、malloc関数の3はnumPlayersである必要があります。 私が3にしておき、メニューに高い数字を入力すると、プログラムは通常クラッシュしますが、時にはうまくいきます。そんなことがあるものか? p [0]、p [1]、p [2]のために十分なメモリしか予約されていない場合、p [15] .scoreにどのようにデータが格納されるのでしょうか?

+1

可能な複製:http://stackoverflow.com/questions/8641478/invalid-read-write-sometimes-creates-segmentation-fault-and-sometimes-does-not/ –

+0

何をコンパイルしていますか?いくつかのコンパイラは、このような動作がクラッシュ* all *の原因となることを保証します。 – detly

答えて

1

「未定義の動作」と呼ばれています。動作が定義されていない場合は、すべて可能です。無効なポインタへのアクセス(あなたの例のように)は、プログラムの動作が標準によって定義されていない多くの場合の1つであり、コンパイラは自由に何でもできます。

このような場合の動作は正しい動作です。あなたの場合、コンパイラは何もしません。プログラムはと同じようにを実行します。 OSがそれを(あなたがアクセス違反でプログラムがクラッシュする)あなたを殺さないなら、それはあなたの純粋な運です。

0

Cコードでは、実際のメモリを操作していることを覚えておく必要があります。コンパイラは無効なメモリアクセスをチェックするのに役立ちません。

pはヒープ上のポインタです.pの長さは3 * sizeof(player)ですが、それ以降はメモリはまだ存在する可能性がありますが、値は予測できません。

0

C予約メモリは、予約です。実際に割り当てられているものに制限はありませんが、要求したスペースがあなたの用途に予約されていることだけが保証されています。プログラムはあなたの正当なものを読み始め、アクセス権のないメモリの内容を読み続ける。メモリマネージャは、メモリを読み続けることができるようです。 Cはこれを行うことからあなたを守っていません。あなたが割り当てたものと読むことができるものを知ることは、あなた次第です。

他の人が言うように、割り当てられたスペースの最後の読み取りは、の未定義の動作です。これは何かが起こる可能性があることを意味します。ほとんどの場合、あなたがここで見ているものである非常に合理的なものが発生します。メモリ内

0

プログラムマップは、例えば、整理することができます。このマップは、コンパイル時に設立され、かつ実行中に一定に保たれる

(テキスト+データ+ BSS)、あなたのプログラムは、仮想メモリの空いている部分に展開することができます実行時に動的割り当てmalloc()を使用しています。

プログラム: 1-実行時に、メモリ(HEAP)に3つのメモリセグメントが割り当てられます。

2 pは、ヒープ内のアドレスNNNNを持つmallocによって初期化されます。それは割り当てられた3つのセグメントの最初のセットの位置です。 最初のアドレス(p + 0 *(sizeof(player))、2番目のセットは(p + 1 *(sizeof(player))、3番目のサイズは(p + 2 *(sizeof(player))になります。

Cを使用すると、いつでもどこでもアクセスできますが、コード、データ、または保護されていないゾーンを壊さないための安全機構を導入することができます。 この場合の安全機構の例:3 * sizeofの定数 "3"の代わりにnumPlayers * sizeofを使用するか、テストユーザーの入力。

したがって、p [15]へのすべての読み取り/書き込みアクセスは(p + 15 *(sizeof(player))に向けられます)。

3なぜそれが設定されますか? メモリには、プログラムの他のデータや雑音だけが含まれる場合があります。それがあなたの構造フィールドを埋めるものです。

4-なぜランダムなクラッシュですか? 書き込みアクセスによってデータが破損する可能性がありますが、クラッシュするほど悪くない場合があります。 TEXTセグメントに向かってメモリに落ちた場合。あなたはあなたのコードを破壊し、あなたは確かにクラッシュするでしょう。

関連する問題