2010-12-03 6 views
2

今日、このコードを読んで、Cプログラミング言語のコースでいくつかの学生を教えていました。 演習では、2つの機能を実装するよう求めました。最初のスキャンはユーザーからの入力をスキャンし、2番目のスキャンは前にスキャンしたものを表示します。 私が出会ったコードは以下の通りです:このコードは矛盾に満ちているがgccの下のCコードでの不思議な動作4.4.3


#include <stdio.h> 

void myInput(int i,int n) 
{ 
    int cpt; 
    int tab[n]; 

    for (cpt=0; cpt<n; cpt++) 
    { 
    printf("Enter a number :"); 
    scanf("%d",&i); 
    tab[cpt]=i; 
    } 
} 



void myDisp (int n) 
{ 
    int tab[n];  
    int cpt; 

    for (cpt=0; cpt <n; cpt++) 
    { 
    printf("%d ", tab[cpt]); 
    } 
} 

int main() 
{ 
    int n; int i; 
    printf(" Entrer the numbers of elements you want: \n"); 
    scanf("%d \n",&n); 
    int tab[n]; 
    myInput(i,n);   
    myDisp(n); 
} 

、それは実際にはgcc 4.4.3の下で動作しません:それは、入力された数値を表示します! !!!!! 誰でもこれらのコードがどのように機能するのか理解していますか?

ありがとうございました

+0

将来参照するには、コードを強調表示してCtrl + Kを押すか、コードをフォーマットするために「0 1」などのボタンをクリックしてください。ありがとう。 – birryree

+0

これは私が見ることのできる、完全に有効なC99です。 – Electro

+0

@Electro、@birryree:彼は、おそらく 'myDisp'で初期化されていない変数' tab'の使用を見ています。 – Thanatos

答えて

8

これが機能すれば、それはまったくダムの運を経ています。 myDispに印刷されているものは、初期化されていないスタックです。myInputに同様の名前の変数に入れられたデータが含まれている場合と含まれていない場合があります。 myInputmyDispへの呼び出しの間(printfに、例えば)

void myInput(int i,int n) 
{ 
    // Add some variables to mess up the stack positioning. 
    int breaker; 
    int cpt; 
    int stomper; 
    int tab[n]; 
    int smasher; 

    for (cpt=0; cpt<n; cpt++) 
    { 
    printf("Enter a number :"); 
    scanf("%d",&i); 
    tab[cpt]=i; 
    } 

    // Trick the compiler into thinking these variables do something. 
    breaker = 1; 
    smasher = 3 * breaker; 
    stomper = smasher + breaker; 
    breaker = stomper * smasher; 
} 

それは関数呼び出しを置くことであろう破るための別の方法:Related reading

はここで何もしないコードでそれを破るための簡単な方法です。

+3

展開する: 'myDisp'が' tab'を他の機能と同様にメモリを使用します。それは動作するように見えますが、コードが正しくなく、修正が必要です。 – Thanatos

+0

こんにちはNathon!私はgccの下で再コンパイルして実行しました。できます。私が入力した数字が表示されます! – strangeLoop

+0

@strangeLoop:確かに、-O3でコンパイルしてみてください。それはまだ動作しますか?入力したすべての数字が正しい順序で表示されますか? – nmichaels

0

2つの配列は完全に別々なので、実際には動作しません。それがそうであれば、彼らはメモリ内の同じ場所に終わったからです。

1

少なくとも一貫しては機能しません。物語の確かに私がしているGCC 4.4.4ではない4.4.3

$ ./a.out 
Entrer the numbers of elements you want: 
5 
2 
Enter a number :Enter a number :4 
Enter a number :1 
Enter a number :2 
Enter a number :3 
2 4 1 134514562 3 

道徳あなたが初期化されていないメモリにアクセスする際、何が作業の外観含め、発生する可能性があります。

+0

ええ、ありがとうSiegeX、gcc 4.4.4で試してみましょう。 – strangeLoop

0

tabmyInput e myDispローカルのメモリ位置が同じ(ほぼ同じ)になっている可能性があります。

myInputmyDispはほとんど同じシグネチャを持っています(パラメータはintの1つだけ異なります)。最悪のシナリオでも、2つの機能においてtabによって参照されるスタック上の位置は、依然として正しく整列され、最大で2つだけ siおよびcptmyInput)シフトします。

0

あなたが宣言したすべての配列int tab[n]の同じメモリ位置にプログラムがアクセスしているようですが、前述のように動作しません。

しかし、ここで起こっていることは、main()内にタブ[]を割り当てているとします。アドレス0x00000001(例としてのみ)の下に割り当てようとしています。配列はn個の整数を持ちますが、値はまったくありません。

次に、myInput()に入り、0x001F0000のような別のアドレスに配列を再度宣言して(同じサイズ)、値を1つずつ設定します。

したがって、関数が終了すると、変数の割り当てられたメモリが解放されるため、配列はもう存在しません。

しかし、これはCです。したがって、メモリを解放すると、ヒープ(またはメモリアロケータ)にアドレスの再使用を伝えるだけです。メモリから値を正確に削除するわけではありません。

次に、myDisp()を呼び出して、配列を再度宣言します。あなたが要求したメモリの優先順位が高くなっているように見えますが、それはあなたのプログラムにもう少し与えられます。あなたの配列は再びインスタンス化され、同じアドレスにあります。

したがって、値を入力しなくても、メモリは読み込まれます(Cでは常に有効です)。値はそのまま残ります。

ああ、配列はmain()内で宣言されていますか?それには何も起こりません。その値を印刷しようとすると、あなたは正しいものを持っていないだろうと確信しています。

これは私の推測です。

EDIT:タブの後に別の配列を宣言してください(タブの名前を変更しないでください)。tab2と同じ長さを使用してタブの代わりに値を入力し、 )

+0

はい、main()スコープの配列はまったく役に立たないです。私はちょうど私が与えられたコードを書き換えた。この配列宣言にコメントを付けると、コードは実行され、良い値が得られます! – strangeLoop

+0

私はこの状況のた​​めにメモリヒープを非難しています。私の意見では、私が述べたように、あなたはヒープの上にあったので、配列とヒープは1つのアドレスXを与えることを宣言します。その後、Xをフリーにすると、ヒープの先頭に戻ってきます(奇妙に聞こえる)。そして、ヒープは、再びタブを宣言すると同じアドレスを与えます。 – Giuliano

関連する問題