2012-01-06 8 views
4

この質問は、私は次のプログラムを試してみましたMalloc call crashing, but works elsewhere"malloc(sizeof(struct a *))"と "malloc(sizeof(struct a))"は同じですか?

の継続であり、私はそれが働いた( - これはあまりにも上記のリンクに記載された、すなわちがクラッシュしません)。私はそれが働くことが幸運かもしれないが、私はなぜこれが働いているのSOの専門家から合理的な説明を探していますか?ここ

malloc()

structures w.r.tと pointers
  • malloc(sizeof(struct a) * n)を用いmemoryの割り当てに関するいくつかの基本的な理解は、タイプstruct a要素のn数を割り当てています。そして、このメモリロケーションは、pointer-to-type-"struct a"を使用して格納およびアクセスすることができます。基本的にはstruct a *です。
  • malloc(sizeof(struct a *) * n)struct a *要素の番号nを割り当てます。各要素は、struct aの要素を指すことができます。基本的にmalloc(sizeof(struct a *) * n)array(n-elements)-of-pointers-to-type-"struct a"を割り当てます。また、割り当てられたメモリ位置は、pointer-to-(pointer-to-"struct a")を使用して格納およびアクセスすることができる。基本的にはstruct a **です。

我々はarray(n-elements)-of-pointers-to-type-"struct a"を作成するときに、それはstruct a *代わりのstruct a **にそれを割り当てるために有効な

  1. のですか?
  2. を割り当て/参照解除するにはpointer-to-"struct a"を使用しますか?

data * array = NULL; 

if ((array = (data *)malloc(sizeof(data *) * n)) == NULL) { 
    printf("unable to allocate memory \n"); 
    return -1; 
} 

次のようにコードスニペットは、次のとおりです。

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

int main(void) 
{ 
    typedef struct { 
     int value1; 
     int value2; 
    }data; 

    int n = 1000; 
    int i; 
    int val=0; 

    data * array = NULL; 

    if ((array = (data *)malloc(sizeof(data *) * n)) == NULL) { 
     printf("unable to allocate memory \n"); 
     return -1; 
    } 
    printf("allocation successful\n"); 

    for (i=0 ; i<n ; i++) { 
     array[i].value1 = val++; 
     array[i].value2 = val++; 
    } 

    for (i=0 ; i<n ; i++) { 
     printf("%3d %3d %3d\n", i, array[i].value1, array[i].value2); 
    } 

    free(array); 
    printf("freeing successful\n"); 

    return 0; 
} 

EDIT: 私は間違い

で、次の操作を行う場合はOKと言います
data * array = NULL; 
if ((array = (data *)malloc(sizeof(data *) * n)) == NULL) { 

コンパイル時に(GCCフラグを使用してコンパイル時に)このような意図しないプログラミングの誤植を捕捉する方法はありますか?私は-Wallを使ってこれを編集し、警告は見つからなかった!

+1

にあなたの質問のタイトルは、なぜあなたがしたいと思う、また –

+0

...上記のテキストの残りの部分で実際の質問と一致していないようです'malloc'の結果を間違ったものに代入して逆参照するのですか?私は質問の前提を理解していません。 –

+0

@OliCharlesworth私は間違って意図的に行っていません!そうすれば、プログラムがクラッシュするとは思わないのですか? –

答えて

4

基本的な誤解があるようです。

malloc(sizeof(struct a)* n)はn個の型struct a要素を割り当てます。

いいえ、これは通常、このような呼び出しの後に使用します。 malloc(size)は、sizeバイトのメモリ領域を割り当てます。あなたがその地域でしていることは、あなた次第です。重要なことは、割り当てられたメモリの限界を超えていないことだけです。 floatintの4バイトとdoubleの場合は、malloc(100*sizeof(float));が成功した後、400バイトの最初の120を15 doubleの配列として使用し、次の120を30 floatの配列として使用して、 20 charの直後に表示され、残りの140バイトは35 intで埋められます。それは完全に無害な定義された動作です。

mallocはそう

some_type **array = malloc(100 * sizeof(data *)); // intentionally unrelated types 

それはちょうどあなたが望んでいたメモリの量ではないかもしれない、まったく問題あり、暗黙的に任意の型のポインタにキャストすることができvoid*を返します。この場合、ポインターはポインターの内容にかかわらず同じサイズになる傾向があります。あなたはそれを持っていたとして

あなたのメモリの間違った量を与える可能性が高いが

data *array = malloc(n * sizeof(data*)); 

です。あなたがタイプdatan要素の配列としてメモリの割り当てられた部分を使用している場合は、三つの可能性

  1. sizeof(data) < sizeof(data*)があります。次に、あなたの唯一の問題は、あなたがいくらかのスペースを無駄にしているということです。
  2. sizeof(data) == sizeof(data*)。あなたはまったくタイプミスがないかのように、すべてがうまくいっていて、スペースが無駄になりません。
  3. sizeof(data) > sizeof(data*)。次に、後で配列要素に触れるときにアクセスすべきではないメモリにアクセスします。これは未定義の動作です。さまざまなことに応じて、コードが正しいかどうかのように一貫して動作し、直ちにsegfaultなどでクラッシュすることがあります(技術的には、これらの2つの間に意味のある動作はできませんが、

あなたが意図的に1または2が適用されるポイントを知って、それは悪い練習ではなく、誤りだ、それを行う場合。あなたがそれを意図せず行うと、それは無害ですが、無害ですが、1.または2.が適用されている間は見つからず、有害ですが、通常は3の場合に検出が簡単です。

例では、 dataは4 resp。 8バイト(たぶん)で、64ビットシステムではそれを1に設定します。 2.高い確率で、32ビットシステムで2 resp。このようなエラーを回避するために、3

推奨される方法は

type *pointer = malloc(num_elems * sizeof(*pointer)); 
+0

詳細な説明をありがとう。 +1と正解! :) –

7

sizeof(struct a*)ポインタのサイズです。
sizeof(struct a)は、構造体全体のサイズです。

+0

あなたの答えをありがとう。しかし、上記のコードスニペットがうまくいっている理由を詳しく教えてください! ..それはクラッシュすると思わない? –

+2

@SangeethSaravanaraj:定義されていない動作とは、プログラムが常にクラッシュすることを意味するものではなく、単にプログラムが異常であり、その動作を定義できないことを意味します。 –

+1

@SangeethSaravanaraj:**未定義の動作**は起こりそうなことです。 –

1

このarray = (data *)malloc(sizeof(data *) * n)は、あなたがいることをしたい場合、あなたはあなたのarraydata** arrayする必要があり、dataを構造体へsizeof(data*)ポインタ)を割り当てます。

あなたの場合は、ポインターをsizeof(data)(メモリ内の構造体)を指すようにします。別のポインターではありません。それにはdata**(ポインタへのポインタ)が必要です。

1

struct a **の代わりにstruct a *を割り当てることは有効ですか?

技術的に言えば、そのように割り当てることは有効ですが、そのようなポインタを逆参照することは間違っています(UB)。あなたはこれをしたくありません。

"struct a"へのポインタを使用して、割り当てられた配列(n要素)のポインタ型から "struct a"へのアクセス/参照解除に有効ですか?

未定義の動作。

+1

'malloc()'の呼び出し結果を「間違った」ポインタ型にキャスト(または直接割り当てる)しても間違いなく安全です。 'malloc()'は型の概念を持たず、単にバイト列を割り当てます。定義されていない振る舞いは、 'malloc()'があなたに与えるバイト列の最後を過ぎて書くことによってのみ発生します。 –

関連する問題