C言語関係掲示板

過去ログ

No.1105 動的に確保された複数の領域は配列なのか?

[戻る] [ホームページ]
No.1618

動的に確保された複数の領域は配列なのか?
投稿者---Misae(2004/04/28 20:10:00)


動的に確保された領域は配列のように連続しているのでしょうか?


以下のコードのような配列の添字によるアクセスは正しいでしょうか?

#define MAX 5

/* 中略 */

  int *n=NULL;
  int i;

  /* MAX個のint型の領域を確保して
   * その先頭の要素へのポインタを返す */
  n=(int*)calloc(MAX,sizeof(int));

  /* 適当な値を代入 */
  for(i=0;i<MAX;i++)
    n[i]=i+10;  // 添字による各領域へのアクセス


また、次のコードとどう違うのでしょうか?

  int (*n)[MAX]; // 配列へのポインタ
  int i;

  /* MAX個のint型の配列の領域を確保して
   * その先頭の用へのポインタを返す */
  n=(int (*)[MAX])calloc(MAX,sizeof(int));

  /* 適当な値を代入 */
  for(i=0;i<MAX;i++)
    *n[i]=i+10;  // 添字による各領域へのアクセス



No.1619

Re:動的に確保された複数の領域は配列なのか?
投稿者---たか(2004/04/28 20:32:22)


>動的に確保された領域は配列のように連続しているのでしょうか?
>以下のコードのような配列の添字によるアクセスは正しいでしょうか?

/* MAX個のint型の領域を確保して
* その先頭の要素へのポインタを返す */
n=(int*)calloc(MAX,sizeof(int));

/* 適当な値を代入 */
for(i=0;i<MAX;i++)
n[i]=i+10; // 添字による各領域へのアクセス

calloc()で要求されたメモリブロックは、calloc()関数がNULLを返さない
限り、連続していて、しかも中身が0でクリアされています。NULLを返した
場合は連続したメモリブロックの確保に失敗した事を示し、その場合は
ブロックが確保されていませんので使ってはなりません。

>また、次のコードとどう違うのでしょうか?
int (*n)[MAX]; // 配列へのポインタ
int i;

/* MAX個のint型の配列の領域を確保して
* その先頭の用へのポインタを返す */
n=(int (*)[MAX])calloc(MAX,sizeof(int));

/* 適当な値を代入 */
for(i=0;i<MAX;i++)
*n[i]=i+10; // 添字による各領域へのアクセス

これは、間違っています。int (*n)[MAX]は、nが int [MAX]で表される
一次元配列へのポインタという意味になり、n+1はnにMAX * sizeof(int)
が足され、すなわちcalloc()で確保したメモリブロックの範囲を飛び出し
てしまいます。n == 0の時にのみ安全です。その場合はn[0][0]にアクセス
しているのと同じです。n == 1だとn[1][0]にアクセスしている事になり
ます。


No.1632

Re:動的に確保された複数の領域は配列なのか?
投稿者---Misae(2004/05/04 14:01:08)


Misaeです。

理解が浅いので、返事が遅くなってしまいました。


そもそも、以下の型キャスト自体も間違いなのでしょうか?

n=(int (*)[MAX])calloc(MAX,sizeof(int));


また、最初に書いた以下の ポインタ変数 n に対しての、
配列の添字 n[i] か ポインタを進める *(n++) でのアクセスは正しいでしょうか?

int *n=NULL;
int i;

n=(int*)calloc(MAX,sizeof(int));

/* 適当な値を代入 */
for(i=0;i&lt;MAX;i++)
n[i]=i+10; // 添字による各領域へのアクセス




No.1633

Re:動的に確保された複数の領域は配列なのか?
投稿者---YuO(2004/05/04 16:06:06)


>そもそも、以下の型キャスト自体も間違いなのでしょうか?
> n=(int (*)[MAX])calloc(MAX,sizeof(int));

nがint (*)[MAX]型でない限り間違いです。

int (*)[MAX]という型は,「『MAX個のint型の要素からなる配列型』へのポインタ型」になります。
この型は,例えば次のように使います。
int array1[MAX];     /* int n;     */
int array2[10][MAX]; /* int a[10]; */
int (*p)[MAX];       /* int *p;    */

p = &array1;         /* p = &n;    */
p = array2;          /* p = a;     */

原理はコメントに書いたことと一緒です。
つまり,int [MAX]がひとかたまりです。
callocで得るなら,
p = calloc(10, sizeof(int [MAX]));
のようになります。

ちなみに,配列型へのポインタ型という型は,明示して使うことは滅多にないです。


>また、最初に書いた以下の ポインタ変数 n に対しての、
>配列の添字 n[i] か ポインタを進める *(n++) でのアクセスは正しいでしょうか?

nがint *型であり,nが参照するオブジェクトがint [MAX]型の配列の先頭要素である場合,
iが範囲[0, MAX)の間においてn[i]というアクセスは可能です。

また,n++という式自体はnが配列要素を参照している場合は有効な式です。
ただし,
> n=(int*)calloc(MAX,sizeof(int));
と,nをalias目的に使っているので,n++というiteration目的の操作はすべきではないです。