• 締切済み

2次元配列の動的確保

ある画像を読み込むため、その画像を格納できる幅、高さを持った配列を動的に確保しようと考えています。 幅をxsize、高さをysizeで次のように記述しました。 unsigned char **src; int i; src = (unsigned char**)malloc(sizeof(unsigned char*) * ysize); src[0] = (unsigned char*)malloc(sizeof(unsigned char) * xsize * ysize); for(i=1; i<ysize; i++) src[i] = (src[0] + i * xsize); わざわざポインタのポインタを使用したのは、動的に確保した配列を2次元的なアクセスをしたかったためです。 画像の読み込み時は fread(src[0], sizeof(unsigned char), xsize * ysize, fp); としています。 上に記述したソースは問題なく動作しました。 しかし、上の場合だと全ての配列を連続して確保することができません。つまりsrcでmallocを一回、src[0]でmallocを一回使っているため、ポインタの配列の直後に配列を確保する保障がありません。そこでいっぺんに確保することを考えました。 unsigned char **src; int i; src = (unsigned char **)malloc(sizeof(unsigned char *) * ysize + sizeof(unsigned char) * xsize * ysize); for(i=0; i<ysize; i++) src[i] = (unsigned char *)(src + sizeof(unsigned char *) * ysize + i * xsize); このように組み上げ、読み込み時は上のfreadと同様に記述したところエラーが出てしまいました。 やはり一行目のmallocで無理やりsizeof(unsigned char *) * ysize + sizeof(unsigned char) * xsize * ysize分確保するのは失敗だったのでしょうか?

みんなの回答

  • ninigi
  • ベストアンサー率43% (10/23)
回答No.3

2次元配列のアドレスをセットする    src[i] = (unsigned char *)(src + sizeof(unsigned char *) * ysize + i * xsize);   の最後の i * xsize が原因ではないでしょうか。 ポインタ変数は4バイトなので、ポインタのポインタであるsrcに例えば src + 1 などとするとアドレスに4が加算されてしまいます。 i * xsize を足したつもりが、その4倍の値が足されている訳です。 ためしに、上記コードの直後に    for(i = 0; i < ysize; i++){ printf("%d\n", src[i]); }   などとして、ポインタが指すアドレスを確かめてみて下さい。 以下のように書き換えると正しく動作すると思います。    src[0] = (unsigned char *)(src + sizeof(unsigned char *) * ysize);  for(i = 1; i < ysize; i++)  {   src[i] = src[i-1] + xsize;  }     ちなみに蛇足ですが、なぜ2次元配列のようにアクセスしたいのでしょうか? もしコードが簡単になるとか見やすくなるとか思っているのでしたら、それは勘違いです。 他人や一ヵ月後の自分は、ダブルポインタを使ったデータ構造を見て、難しいプログラムだと感じるでしょう。 あまり技巧に凝ったコードはシンプルに書かれたコードに比べて読みづらいものです。   し・か・し、 このように技巧に凝っていろいろ試行錯誤を繰り返す事は、自分の経験値アップに大いに役立ちます。 人に見せたり後世に残す必要の無いプログラムであれば、どんどん試してください。  

回答No.2

根本的には C言語の多次元配列をよく理解されていないために生じる思い違いですな。 結構、こういう方は多いですね。 実はC言語の多次元配列は、他の言語と大きく異なります ひとことで表現すると、それは 「C言語の配列は、ツリー構造を成している」 ということです。 手持ち無沙汰な時に、この表現を呪文みたいに唱えて よく考えてみましょう。 他の言語の多次元配列は、連続した領域をコンパイラーのほうで読み込みマクロを作ってくれているようなものなので、このようなC言語のような 気苦労はありませんわ。

  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.1

★アドバイス ・過去に同じような質問に回答しました。  ので下のリンクを参考に。  http://oshiete1.goo.ne.jp/qa3022605.html→『callocで二次元配列を作成するには?』  ↑http://oshiete1.goo.ne.jp/qa2619388.html→『3次元配列でのポインタ 』  |  これを参考にして下さい。回答 No.1 の方です。 ・以上。

参考URL:
http://oshiete1.goo.ne.jp/qa3022605.html

関連するQ&A

  • 画像を読み込む配列の確保。

    C言語について質問です。 画像を読み込む時、その画像の幅、高さを入力し、そのサイズに見合った配列を確保します。その後ファイル名を入力し、配列に読み込むプログラムを作成しました。 メインの部分のみ記述します。 int xsize, ysize, i; unsigned char **src; char filename[30]; FILE *fp; printf("ファイル名を入力してください:"); scanf("%s", filename); printf("画像の幅:");scanf("%d", &xsize); printf("画像の高さ:");scanf("%d", &ysize); src = (unsigned char **)malloc(sizeof(unsigned char *) * ysize); for(i=0; i<ysize; i++) src[i] = (unsigned char *)malloc(sizeof(unsigned char) * xsize); fp = fopen(filename, "rb"); fread(src[0], sizeof(unsigned char), xsize * ysize, fp); このように記述し、エラーもなく実行できたのですが、srcをこのまま出力すると変?な画像となって出力されてしまいました。 上のように記述した場合、矛盾する場所はあるでしょうか? そして、この方法以外に配列を確保する方法はあるでしょうか?

  • 3次元配列でのポインタ

    唐突ですみません。 サイズが640*480の画像を180枚読み込むプログラムをポインタを使って作成しようと考えています。 以下で示すプログラムは画像を読み込むための作成したものですが、エラーが出てしまい実行することができません。 間違えている箇所があればご指摘お願いします。 また、そのほかに効率の良いやり方などがありましたらご教授願います。 #include <stdio.h> #include <stdlib.h> #include <math.h> #define xsize 640 #define ysize 480 #define round 180 #include "Input.h" void Input_task(unsigned char ***In); void main() {   static unsigned char ***In;   int i,j;   In=(unsigned char***)malloc(sizeof(unsigned char)*round);   for(i=0;i<round;i++)   {     In[i]=(unsigned char**)malloc(sizeof(unsigned char)*ysize);     for(j=0;j<ysize;j++)     {       In[i][j]=(unsigned char*)malloc(sizeof(unsigned char)*xsize);     }   }   Input_task(In); } Input.hの中身 void Input_task(unsigned char ***In) {   char filename[30];   int i,j,k;   FILE *fp;   for(i=0;i<round;i++)   {     sprintf(filename,"b20_%04d.raw",i);     fp=fopen(filename,"rb");    for(j=0;j<ysize;j++)     {       for(k=0;k<xsize;k++)       {         *(*(*(In+i)+j)+k)=(unsigned char)getc(fp);       }     }    fclose(fp);   } }

  • 「動的確保した2次元配列のメモリ解放」を関数化したい

    質問タイトルの通りですが、 「動的確保した2次元配列のメモリ解放」をC言語で関数化したいと思っています。しかし、関数の引数には動的確保した配列の先頭アドレスのみ渡す形にしたいです。そのような場合の関数化は可能ですか? どうもうまくいかず、困っています。 以下、具体的に、サンプルソースを記述します。 わかる方、よろしくお願いします。 //====================================================// #include<stdio.h> unsigned char** AllocByteArray2d(int column, int row); void FreeByteArray2d(unsigned char** box); int main(voidls){ unsigned char array**; array = AllocByteArray2d(2, 3); FreeByteArray2d(array); return 0; } unsigned char** AllocByteArray2d(int column, int row){ unsigned char* box; box = (unsigned char**)malloc( sizeof(unsigned char*)*column ) int i; for(i=0; i<column; i++){ box[i] = (unsigned char*)calloc( row, sizeof(unsigned char)); if(box[i] == NULL) exit(EXIT_FAILURE); } return box; } //引数では配列の先頭アドレスだけ渡す形にしたい void FreeByteArray2d(unsigned char** box){ //ここをどう書いたらいいかわからない }

  • ポインタ配列の動的確保

    ポインタの配列の動的確保について教えてください。 入力した数値をポインタ配列に入れるプログラムです。 下記のように書いてみました。(見づらくてごめんなさい) #include<stdio.h> #include<stdlib.h> #define kensu 3 main() { char abc[kensu+1]={'A','B','C','\0'}; char *ptr[kensu]; int i; printf("3つの整数を入力して下さい。\n"); for(i=0;i<kensu;i++){ ptr[i]=(char*)malloc(sizeof(char)*10); if(ptr[i]==NULL){ printf("メモリの取得に失敗しました"); exit(1); } printf("整数%c:",abc[i]); fgets(ptr[i],10,stdin); if(ptr[i][strlen(ptr[i])-1]=='\n') ptr[i][strlen(ptr[i])-1]='\0'; } for(i=0;i<kensu;i++) free(ptr[i]); } ちゃんと動いているようです。 しかし、ポインタ配列の動的確保をネットで調べてみると、ポインタのポインタ(?)を使って、下記のように2度mallocしています。 #include <stdio.h> #include <stdlib.h> #define N 3 int main(void) { char** arr; int i,j; arr = (char**)malloc(N * sizeof(char*)); /* ポインタ配列を確保 */ /* 配列の要素それぞれにつき、メモリ領域を確保 */ for(i=0;i<N;i++) arr[i] = (char*)malloc(N * sizeof(char));   ・・・ ポインタの配列を宣言して、配列の各要素に動的確保するのと ポインタのポインタを宣言し、ポインタ配列を動的確保して、再度配列の要素に動的確保するのとでは、何か違いがあるのでしょうか? ポインタのポインタを宣言し、ポインタ配列を確保する必要性が良く分かっていないのです。 ネット等で調べて見たのですが、理解力がないのかよく分かりませんでした。 どうか教えてください。

  • アドレス格納のための二次元配列のメモリ動的確保

    アドレス格納のための二次元配列のメモリ動的確保 二次元配列のためにメモリを動的確保しなければならないのですが、 その配列に格納したいものが 「DATA型のポインタ」です。(DATA型はtypedefした構造体です。) プログラム実行中にmallocで確保した、数あるDATA型の構造体の、その先頭アドレスを リストアップするための配列です。 この場合、どのような形でmallocすればよいのでしょうか? 教えていただけるとありがたいです。よろしくお願いいたします。 -- たとえば m×n のint型の配列は、 ◆ int *i; ◆ i = (int *)malloc( m * n * sizeof(int) ); となりますよね。 この要領がでやるのが一般的にわかりやすいものだとするならその方法でやりたい (後発の人が自分のソースコードを読む可能性があるため)のです。 -- 同様にm×nの「DATA型のポインタを格納するための二次元配列」を動的確保したい場合、 ◆ DATA *d; ◆ d = (DATA *)malloc( m * n * sizeof(DATA) ); この文にどのように付け加えたら良いのでしょう? もうあと一歩な気がするのですが(笑)。しかし参考書等で勉強しましたがわかりませんでした・・・。 わかる方、どなたかよろしくお願いいたしますm(_ _)m あとこれだけ通ればコンパイルが通るんです!!!!! たぶん(笑)

  • とあるプログラムを教えてほしいのですが

    はじめましてこんばんは hommado と申します。 じつは先週の授業でこんな問題を出されたんですがもしできたらとあるプログラムを教えてほしいのです。 問題は 「キーボードから何階調にするのかを読み込むことで、入力画像LAX.bmpを任意の階調数に変換する」という プログラムです。 一応下に素体のプログラムをおいたんで、其のプログラムに何か付け足す感じでお願いします。「/*******↓基本的には、この範囲に画像処理プログラムを書く****/」から 「 /********↑**************************************************/」の中にプログラムを書くかんじなのでもし分かったら教えてください。お願いします。 あと何か他の所に付け足すようなところがあったら教えてください ここから元のプログラム // Bitmapファイルを読み込んで, // 別のファイルに出力するだけのプログラムです #include<stdio.h> #define XSIZE 256 /* 画像の横サイズ*/ #define YSIZE 256 /* 画像の縦サイズ*/ void main(void) { int x,y; char fni[40],fno[40]; /* 入力ファイルと出力ファイルの名前を格納するための配列*/ unsigned char head[1078],buf[YSIZE][XSIZE]; /* 入力ファイル(ビットマップファイル)のヘッダ情報と輝度値情報を格納するための配列*/ unsigned char in_image[YSIZE][XSIZE]; /* 入力画像の画素の輝度値を格納するための配列*/ unsigned char out_image[YSIZE][XSIZE]; /* 出力画像の画素の輝度値を格納するための配列*/ FILE *fp,*fp2; /* ファイルポインタ*/ printf("ファイル名を入れてください:"); scanf("%s",fni); fp=fopen(fni,"rb"); /* 読み込み& バイナリモードでオープンする*/ /* 配列head にビットマップファイルのヘッダ情報が格納されます*/ fread(head,sizeof(unsigned char),1078,fp); /* unsigned char 型のデータ×個を配列head に読み込む*/ /* 配列buf にビットマップファイルの輝度値情報が格納されます*/ fread(buf,sizeof(unsigned char),XSIZE*YSIZE,fp); for(y=0;y<YSIZE;y++){ for(x=0;x<XSIZE;x++){ in_image[y][x]=buf[y][x]; /* 画像の左下の画素が座標buf[0][0] です*/ } } printf("読み込み終了しました!\n"); printf("出力ファイル名を入れてください:"); scanf("%s",fno); /*******↓基本的には、この範囲に画像処理プログラムを書く****/       ここにプログラムを書いてください!      (もしここ以外で、他の所で付け足すプログラムがあったら何行目に       何を書くのかも教えてください) /********↑**************************************************/ fp2=fopen(fno,"wb"); /* 書き込み& バイナリモードでオープンする*/ /* 配列head の内容を出力ファイルに書き込む*/ fwrite(head,sizeof(unsigned char),1078,fp2); /* 配列out_image の内容を出力ファイルに書き込む*/ fwrite(out_image,sizeof(unsigned char),XSIZE*YSIZE,fp2); fclose(fp); /* ファイルをクローズする*/ fclose(fp2); /* ファイルをクローズする*/ printf("作業完了!\n"); }

  • 困りました。

    現在SDKにて画像処理ソフトを作成しています。 そして最近フィルタリングの機能をつけてみようと思いました。 知識として3×3の配列を利用するフィルタ処理で、ラプラシアン、ノイズ除去などを行うやりかた(アルゴリズム)は知っているのですが、配列の確保に問題が出てきました。 プログラムの仕様として、入力画像の輝度情報は入力時にその情報量分のメモリを確保し、ポインタとして格納しています。つまり配列として扱うには1次元配列となってしまいます。もちろん配列をあやつる変数部分を変えるだけで、2次元的な表現はできるのですが、フィルタリング処理をする際複雑になってしまい、コーディングするのが困難になってしまっています。 そこでポインタとしての1次元配列を2次元配列に格納したいのですが、単に格納だけならできるのですが、格納する2次元配列も動的にメモリ確保を行いたいのです。 色々とごちゃごちゃした言い回しになってしまいましたが、第一の問題は2次元配列として扱えるよう動的にメモリを確保したいということです。つまり src[i][j] このように扱えるようメモリを確保したいということです。 以前メモリ確保についてここで質問させてもらいましたが、2次元配列の場合、宣言として (*src)[256] とした場合少なくとも縦が256の画像を読み込むことができます。しかしこの場合は”256”と決まった量を与えているため記述できるのですが、自分が行いたいのは関数の引数で画像サイズを取得し、その量のメモリを動的に確保したいため、画像サイズに応じて確保するメモリの量が変わってきてしまいます。そのため(*src)[256]と書くことができませんが、しかし自分では確保したメモリ配列を2次元配列として扱いたいため(*src)[256]と書かなければなりません。 つまりこれが壁になっています。 関数の引数で受け取った画像サイズ分のメモリ確保を行い、かつそのメモリ空間をを2次元配列として扱いたい場合、どのように記述すればよいでしょうか? ひとつ考えたことが **src としてポインタのポインタを使用し、 src = (unsigend char **)GlobalAlloc(GHND, sizeof(unsigned char *) * height); for(i=0; i<height; i++)   src[i] = (unsigned char *)GlobalAlloc(GHND, sizeof(unsigned char) * width); for(i=0; i<height; i++){     for(j=0; j<width; j++){ src[i][j] = Input[width * i + j];     } } このように定義してみたんですけど、src[i][j]と記述はできたのですが実行時にエラーが出てしまいました。 なにか効率の良い方法はないでしょうか?

  • 2次元配列の動的確保について

    共分散行列を2次元配列に格納しようとしているのですが、 その要素は、左下半分と右上半分が同じになるため 対角要素と、どちらか半分だけを格納してメモリを節約したいと考えています。 以下のように動的確保することでメモリは節約できているでしょうか? if( (a = (double **)malloc(sizeof(double *) * (N) ))==NULL ){ fprintf(stderr, "error malloc for a\n"); exit(0); } for( i=0; i<NN; i++ ){ if( ( a[i] = (double *)malloc(sizeof(double) * (i+1) ))==NULL ){ fprintf(stderr, "error malloc for a\n"); exit(0); } } *節約しない場合は、i+1 が N になります。 確保できているのなら、どのように参照すればいいのでしょうか?データの並び(?)は、a[0][0],a[1][0],a[1][1],a[2][0],a[2][1],a[2][2],,,というように並んでいるでしょうか? 例えば、a[0][1]を参照しようとすると、シグメンテーションフォルトなど起こりうるでしょうか。必要であれば、上プログラム内Nは、3000程度と考えてください。 そして、もし他にメモリを節約する上で良い方法があれば、ご教授していただけたらと思います。 よろしくお願い致します。

  • 三次元配列の動的メモリの確保?

    const int SLICE=2; const int SIZE=256; signed short int *matrix=new signed short int[SLICE][SIZE][SIZE]; for(int i=0; i<SLICE; i++){ for(int j=0; j<SIZE; j++){ for(int k=0; k<SIZE; k++){ fin.read((char*) &matrix[SLICE][SIZE][SIZE],sizeof(signed short int)); } } } delete[] data; 三次元データを読み込むために、三次元配列を使って読み込もうとしたのですが、上手く読み込めません。 三行目の所で、error C2440: '初期化中' : 'short (*)[256][256]' から 'short *' に変換できません。 七行目の所で、error C2109: 配列または、ポインタでない変数に添字が使われました。 というエラーがでます。動的メモリの確保の仕方がまずいのでしょうか? どなたか教えて頂けますでしょうか?よろしくお願いします。

  • 2次元配列を動的に確保する方法

    /*ネットの*/ w = (double **)malloc(sizeof(double*) * h); w[0] = (double *)malloc(sizeof(double) * v * h); for(i=0; i<h; i++) w[i] = w[0] + i *v; /*自分の*/ w = (double **)calloc(h, sizeof(double *)); for(i = 0; i < h; i++){ w[i] = (double *)calloc(v, sizeof(double)); 自分は初心者です。自分は下のようなコードで書いていたのですが ネットで見つけたコードで上のようにデータの領域を全部確保してから 2番目以降のポインタを割り当てるようなやり方をしていました。 そのやり方は初めて見たのですが、こっちのほうが一般的なやり方なんでしょうか? それと何かメリットはあるんでしょうか? 一度に確保した方が確実に連続領域に割り当てられるとかかなぁとか予想してるんですが・・・

専門家に質問してみよう