2016-06-18 9 views
1

次のコードが機能するようです。 gcc 5.2.1 on linuxは警告を出さなかった。メモリを1つの関数に割り当て、別の関数で使用する

私はCの初心者です。&と*演算子が英語の文章と試行錯誤を使って各行で何を行うのかを書き留めることで、これを実現しました。

わからないことが2つあります。

ラインAのp0の初期値は予測できません。しかし、E行はmainの変数p0の値で指定されたアドレスに値を割り当てます。これで問題はありますか?もしそうなら、それを修正する方法は?

コードは非常に*使用していますが、***のように行Cで使用できますか?

ありがとうございます。

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

void* f(int*** ptr_p)  //C 
{ 
    int** p = *(ptr_p); //D 
    *p  = malloc(8); //E 
    *(*p) = 200;  //F 
    (*p)[1] = 4;   //G 
} 

int main(void) 
{ 
    int** p0;    //A 
    f(&p0);    //B 
    printf("%d, %d\n",*(*p0), (*p0)[1]); 
    free(*p0);   //H 
} 

英語の文章を見たい場合は、ここにあります。

警告:私はCの初心者ですが、すべて正しいかどうかわかりません。

ライン[A] int** p0;

p0

の値は予測不能です。

ライン[B]はf(&p0);

&p0可変p0のアドレスです。 f(&p0)は、関数fを呼び出して、関数の第1引数に&p0を代入することを意味します。

ライン[C] void* f(int*** ptr_p)

ラインBはptr_p&p0割り当てます。これは、ptr_pの値が、メイン関数の変数p0のアドレスに等しいことを意味します。

ライン[D] int** p = *(ptr_p);

*(ptr_p)アドレスとして解釈ptr_pの値によって指定されたアドレスの値を意味します。 ptr_pの値は、メイン関数の変数p0のアドレスです(行Cで説明しています)。したがって、*(ptr_p)は、main関数の変数p0の値です。

p = *(ptr_p);手段は、ライン[E] *(p) = malloc(8);

*(p)pの値によって指定されたアドレスの値を意味p

の値に主な機能にp0の値を割り当てます。 pの値は、ライン[D]で説明されているように、メイン変数p0の値です。次に、*(p)は、p0変数の値で指定されたアドレスの値を意味します。main()です。

malloc(8)は、メモリに8バイトを予約し、8バイトの最初のアドレスを返します。

行全体は、p0変数で指定されたアドレスの値として、これらの8バイトのうちの最初のアドレスをmain()に割り当てることを意味します。

ライン[F] *(*p) = 200;

ライン[G]は(*p)[1] = 4;

(p)[1]*(p + 1)

(*p)[1]が意味を意味*(*p + 1)

+0

3:10 am、私は今眠る。明日の回答をチェックします。これは楽しく便利です。前もって感謝します。 – rxu

答えて

2

はい、行Eが問題です。実際には、あなたはp0の(未定義の)値を読んでいるので、すでにD行目で問題になっています。これはCでは禁止されています。それは恐ろしいの定義されていない動作の一部です。つまり、すべてのベットがオフで、コンパイラが要求しているもの、つまりバイナリがクラッシュしたり、 "Hello world!"という名前を出力することが合法的に許可されています。

p0は、そのバッファに書き込む前にint *バッファを指しているはずです。しかし、この余分なレベルの間接化の必要はありません。 p0ができint *

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

void f(int** ptr_p)  //C 
{ 
    *ptr_p  = malloc(sizeof(int) * 2); //E 
    (*ptr_p)[0] = 200;  //F 
    (*ptr_p)[1] = 4;   //G 
} 

int main(void) 
{ 
    int* p0;    //A 
    f(&p0);    //B 
    printf("%d, %d\n", p0[0], p0[1]); 
    free(p0);   //H 
    return 0; 
} 

最後の一つです:mallocが失敗し、NULLを返すことができます。堅牢なプログラムがそれをチェックします。

+0

最後に、関数から複数の配列を(ポインタに)返そうとしたので、私はあなたのメソッドを選択しました。コードはこの質問で使用されています(http://stackoverflow.com/questions/37933956/get-sizes-of-pairwise-intersection-between-sorted-sets-very-efficiently)ありがとうございます。 – rxu

+0

@rxu私は元のコードとの一貫性のためにこのスタイルだけを選択しました。私は通常、戻り値が1つしかない場合は戻り値を使用します。それらのうちの2つまたは3つがあっても、時々それらを一緒に、私が戻ってくる構造にまとめる。最適化コンパイラは非常に効率的なコードを生成することができます。特に、関数が 'static'(コンパイル単位のローカルなので、ABIに束縛されていない場合)です。一般に、ローカル変数のアドレスを取らないことは、コンパイラが「メモリから取り出す」、すなわちCPUレジスタに保持するのに役立つ。 – odelande

+0

ああ私は次回の構造を使用します。 – rxu

2

あなたが必要とするより多くの星を持っている:少数のより良いので、私はあなたのプログラムを簡素化しました。

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

int *f(int size)     // returns a pointer 
{ 
    int *p;       // define a pointer 
    p = malloc(size);    // allocate memory to it 
    if(p == NULL) {     // check the result 
     exit(1);     // emergency exit 
    } 
    *p = 200;      // put a value at p[0]; 
    p[1] = 4;      // put a value at p[1]; 
    return p;      // return the pointer 
} 

int main(void) 
{ 
    int *p0;      // pointer as yet has no value assigned 
    p0 = f(2 * sizeof *p0);   // get memory for 2 ints and initialise it 
    printf("%d, %d\n", *p0, p0[1]); // show the two ints assigned 
    free(p0);      // release the memory 
    return 0;      // end of program 
} 

プログラムの出力:少数の星から離れて

200, 4 

、あなたのプログラム

  1. 関数はポインタを直接返すには、2つの主な変更点があります。それを引数で設定するにはもう一つ星が必要です。

  2. 要求されたメモリ量は、データタイプの2つの要素であり、「ハードコードされていません」です。

また、ポインタに基づいて配列にアクセスできる方法は複数あります。

+2

Amen、a * three-star *関数は一般的に関数の補数ではありません(時には必要です)。 –

+0

非常に明確でクリーンな実装をありがとう。コメントはとても役に立ちます。私はこの関数を使用して、関数から1つの配列を返す必要があるときにだけ使用します。 – rxu

関連する問題