• ベストアンサー

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);   } }

質問者が選んだベストアンサー

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

★3次元配列のポインタ宣言が間違っています。 ・3次元配列のポインタは『static unsigned char (*In)[ysize][xsize];』と宣言しますよ。 ・ちなみに、3次元配列は『static unsigned char ln[round][ysize][xsize];』と同じになります。 ・分かりますか?→多次元配列のポインタはなれないと難しいですよ。考え方が。宣言方法がね。 ・『Input.h』内の『Input_task』の引数宣言も『unsigned char (*In)[ysize][xsize]』とします。 ★その他 ・640×480の画像を180枚ということは 55,296,000 バイト(約53Mバイト)ですよ。メモリ容量は大丈夫? ・『効率』良くというのならば、『getc』ではなく『fread』で一度に『640×480=307,200』バイトを  読み込みます。→メモリを確保しているので出来ますよ。あとは、180枚分をループして読み込みます。 ・サンプルを載せておきます。解説しませんので読み取って下さい。 /* main関数のサンプル */ void main() {  static unsigned char (*In)[ysize][xsize];    if ( (In = (unsigned char (*)[ysize][xsize])malloc(round * ysize * xsize)) == NULL ){   printf( "メモリが足りません。\n" );   exit( 255 );  }  Input_task( In );  free( In ); ←忘れずに! } /* Input.hの中身 */ void Input_task( unsigned char (*In)[ysize][xsize] ) {  char filename[30];  int i;  FILE *fp;    for ( i = 0 ; i < round ; i++ ){   sprintf( filename, "b20_%04d.raw", i );      if ( (fp = fopen(filename,"rb")) != NULL ){    fread( In[i], xsize, ysize, fp );    fclose( fp );   }  } } 最後に: ・回答者 No.1 さんと同じくヘッダにはソースは記述してはいけません。→トラブルの原因になるから。 ・また、単純に1次元配列を確保して自分で掛け算してアクセスするのも方法の1つですよ。 ・以上。

noconan
質問者

補足

回答ありがとうございました。 実際まだポインタに慣れていないので、自分の理想とするものを作ることガで木津にいたのですが、この返答は理想に近いもので驚きました。 本当にありがとうございました。

その他の回答 (1)

  • venzou
  • ベストアンサー率71% (311/435)
回答No.1

>In=(unsigned char***)malloc(sizeof(unsigned char)*round); In=(unsigned char***)malloc(sizeof(unsigned char **)*round); >In[i]=(unsigned char**)malloc(sizeof(unsigned char)*ysize); In[i]=(unsigned char**)malloc(sizeof(unsigned char *)*ysize); InとIn[i]はポインタの配列ですよ。 私なら・・・ 単純に一次元配列で確保して unsigned char *In; In = (unsigned char*)malloc(sizeof(unsigned char)*round*ysize*xsize); Input_taskの代入部分 *In++ = (unsigned char)getc(fp); 後から参照する時は In[i*ysize*xsize + j*xsize + k] あと、ヘッダファイルにはプログラムは書かないですね。

noconan
質問者

お礼

的確な回答ありがとうございました。 確かに、一次元配列で確保したほうがいいですね。 まだ慣れていないせいもあり、苦労しているところですTT

関連するQ&A

  • 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分確保するのは失敗だったのでしょうか?

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

    ポインタの配列の動的確保について教えてください。 入力した数値をポインタ配列に入れるプログラムです。 下記のように書いてみました。(見づらくてごめんなさい) #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));   ・・・ ポインタの配列を宣言して、配列の各要素に動的確保するのと ポインタのポインタを宣言し、ポインタ配列を動的確保して、再度配列の要素に動的確保するのとでは、何か違いがあるのでしょうか? ポインタのポインタを宣言し、ポインタ配列を確保する必要性が良く分かっていないのです。 ネット等で調べて見たのですが、理解力がないのかよく分かりませんでした。 どうか教えてください。

  • プログラム(C)

    #include <stdio.h> #include <stdlib.h> #define FNAME "smp.bmp" #define WSIZE 256 #define HSIZE 256 #define BSIZE 1024 int main(void) { struct BMPFILEHEADER { ・   ・ }; struct BMPINFOHEADER { ・   ・ }; unsigned char img[HSIZE][WSIZE][3]; unsigned char buf[BSIZE]; struct BMPFILEHEADER lpHead; struct BMPINFOHEADER lpInfo; FILE *fp; int i; int j; int k; fp = fopen(FNAME,"rb"); if (fp==NULL) { printf("ファイルをオープンできません\n"); return 0; } fread(&lpHead.bfType, sizeof(unsigned short),1,fp); fread(&lpHead.bfSize, sizeof(unsigned int),1,fp); fread(&lpHead.bfReserved1, sizeof(unsigned short),1,fp); fread(&lpHead.bfReserved2, sizeof(unsigned short),1,fp); fread(&lpHead.bf0ffBits, sizeof(unsigned int),1,fp); fread(&lpInfo, sizeof(struct BMPINFOHEADER),1,fp); for(i=0;i<HSIZE;i++) { fread(buf,sizeof(unsigned char),WSIZE*3,fp); for(j=0;j<WSIZE;j++) { for(k=0;k<3;k++) { img[HSIZE-1-i][j][k]=buf[j*3+k]; } } } fclose; return 0; } このプログラムはBMP画像を読み込むプログラムなんですが このプログラムに画素値を出力するプログラムにしたいのですがうまくできません。 結果は(真っ白な画像の時)255255255・・・255255と出力したいのです。白黒画像なのでR=G=Bで1画素値は255だけでいいのですが。どうしても255255255や25500などとでてしまいます。 アドバイスお願いします。(800字までなので構造体の宣言は抜いてしましました) 。

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

    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をこのまま出力すると変?な画像となって出力されてしまいました。 上のように記述した場合、矛盾する場所はあるでしょうか? そして、この方法以外に配列を確保する方法はあるでしょうか?

  • 2次元配列とポインタの引数受け渡しについて

    2次元配列を関数に渡すときは、引数に渡す2次元配列と同じサイズを指定、もしくは2次元目のサイズのみ合わせて渡す方法がありますが、両方とも違うサイズで同じ関数を使いたいです。 最初は中身が同じで引数で受け取る2次元配列のサイズだけ、それぞれに合わせた引数を持つ関数を2つ作っていたのですが、なんだか冗長な気がしました。 そこで、2次元配列の先頭ポインタとサイズを受け取るようにすればいいのかと思い、テストとして次のプログラムを作成してみました。 #include <stdio.h> void func(unsigned char *a, int y, int x); int main(void) { unsigned char a[10][10]; func(a, 10, 10); printf("%d\n", a[7][4]); return 0; } void func(unsigned char *a, int y, int x) { int i, j; for (i = 0; i < y; i++) { for (j = 0; j < x; j++) { *(a + i*y + j) = i * j; } } } もちろんこれでも動くのですが、やはりこういう書き方はルールにはないので、コンパイルで警告が出ます。 a.c: In function ‘main’: a.c:10: warning: passing argument 1 of ‘func’ from incompatible pointer type a.c:4: note: expected ‘unsigned char *’ but argument is of type ‘unsigned char (*)[10]’ このような書き方はやはりやめたいいのでしょうか。 また、その際はサイズ別に関数を作るしかないのでしょうか。 他にいい方法があれば教えていただけると助かります。

  • 「動的確保した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){ //ここをどう書いたらいいかわからない }

  • C言語でファイル読み書きを早くしたい。

    いつも利用させてもらって助かっています。 あるプログラムを作成しているのですが、ファイル入力の部分がネックとなってしまって、全体が使いものにならない状況に陥っています。 たくさんのデータをfread1回で読み込むことにより、読み込み速度はずいぶんと改善されましたが、まだ圧倒的に遅い状況です。システムコールを使いましたが、ほとんど改善されませんでした。 読み込み/書き込みの速度を改善する方法として,SSDメモリを使ったりする方法があると思いますが,プログラムの観点から改善できるところはないでしょうか? 下に、ファイル読み込みの部分だけ記述したコードを添付させて頂いたので、改善できる点があれば、御指摘頂けると助かります。 なお、前提として, (1)データはスタック領域だと不足するので、ヒープ領域に確保 (2)データファイルは改行無しの一連のデータ とします。 ちなみに、環境は OS   : CentOS5.3 memory   : 6GB コンパイラ : gcc です。 よろしくお願いします。 //----------------------------------------------------- //通常バージョン #include <stdio.h> #include <stdlib.h> #define SIZE (512*1024*1024) //500MB int main(void) { unsigned long int i; unsigned char *data; FILE *fp; data = (unsigned char *)malloc(SIZE); if(data == NULL) { printf("メモリが確保できません\n"); exit(EXIT_FAILURE); } fp = fopen("filein.dat", "rb"); fread( data, sizeof( unsigned char), (int)SIZE, fp ); fclose(fp); /* //表示 for( i=0; i<SIZE; i++ ){ printf("%2x", data[i]); } puts(""); */ fp = fopen("fileout.dat", "w"); fwrite( data, sizeof( unsigned char), (int)SIZE, fp); fclose(fp); free(data); return 0; } //----------------------------------------------------- //readシステムコールを使ったバージョン #include <stdio.h> #include <stdlib.h> #define SIZE (512*1024*1024) //500MB int main(void) { unsigned long int i; unsigned char *data; data = (unsigned char *)malloc(SIZE); if(data == NULL) { printf("メモリが確保できません\n"); exit(EXIT_FAILURE); } int fd; fd = open( "filein.dat" ); read( fd, data, sizeof(unsigned char)*SIZE); close(fd); /* //表示 for( i=0; i<SIZE; i++ ){ printf("%2x", data[i]); } puts(""); */ FILE *fp; fp = fopen("fileout.dat", "w"); fwrite( data, sizeof( unsigned char), (int)SIZE, fp); fclose(fp); free(data); return 0; }

  • バイナリファイル(画像)のよみこみ

    レポートで1024×1024ピクセルの画像を、間引いて256×256の画像にしろというのが出されました。画像はrawファイルです。 それで、とりあえず画像を読み込んで、出力するプログラムを書いてみたんですが、コンパイルは出来るのに実行すると不正な処理とけいこくがでてきてしまいます。 ソースは #include<stdio.h> main() { unsigned char in[1024][1024],out[1024][1024]; FILE *fp; int i,j; fp=fopen("aaa.raw","rb"); fread(in,sizeof(unsigned char),1024*1024,fp); fclose(fp); for(i=0;i<1024;i++){ for(j=0;j<1024;j++) out[i][j]=in[i][j]; } fp=fopen("bbb.raw","wb"); fwrite(out,sizeof(unsigned char),1024*1024,fp); fclose(fp); } です。 どこがいけないのかアドバイスいただきたいです。よろしくお願いします。

  • 画像を読み込んでヒストグラムを作るプログラム

    2値化画像を読み込んで、ヒストグラムを表示させるプログラムを作りたいのですが、 以下のソースを作成したのですが実行中にエラーが発生して困っています。 よろしくお願いします。 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <conio.h> #define width 640 #define height 480 int main(int argc, char* argv[]) { unsigned char image[640*480]; unsigned char header32[1078];//ビットマップ情報 int i; int *histogram; FILE *fp1; unsigned char buffer1[640*480]; for(i=0; i<640*480; i++) { image[i]=0; buffer1[i]=0; } fp1=fopen("koshimizu1.bmp","rb"); // fread(image,1,640*480,fp1); fread(header32,1,1078,fp1); fread(buffer1,width,height,fp1); fclose(fp1); for(i=0;i<256;i++){ histogram[i]=0; } for(i=0;i<640*480;i++){ histogram[image[i]]++; } for(i=0;i<256;i++){ printf("%d %d \n",i,histogram[i]); } return 0; }

  • 行毎の黒のドット(ピクセル)数を教えていただけませんか?

    開発環境Microsoft Visual Studio .NET 2003 2値画像を読み込んだ時、各行毎の黒のピクセル(ドット)数を表示する プログラムを組もうとしているのですがわかりません。 画像読み込みまではできたのですがその後のプログラムがわかりません 誰か組んでいただけないでしょうか? #include <stdio.h> #include <process.h> #define Y_SIZE 3648 // 処理できる最大画像 #define X_SIZE 3648 #define HIGH 255 // 画像の最大強度値 #define LOW 0 // 画像の最小強度値 #define LEVEL 256 // 画像の強度レベル値 // BMPファイルのフォーマットに従って用意した変数 typedef unsigned short WORD; typedef unsigned long DWORD; WORD bfType; DWORD bfSize; WORD bfReserved1, bfReserved2; DWORD bfOffBits; DWORD biSize, biWidth, biHeight; WORD biPlanes, biBitCount; DWORD biCompression, biSizeImage, biXPelsPerMeter, biYPelsPerMeter, biClrUsed, biClrImportant; unsigned char image_in[Y_SIZE][X_SIZE][3]; // 入力カラー画像配列 unsigned char image_out[Y_SIZE][X_SIZE][3]; //出力カラー画像配列 unsigned char image_bw[Y_SIZE][X_SIZE]; //濃淡画像配列 unsigned char data_rgb[Y_SIZE][X_SIZE][3]; // RGB画像配列 //******************************************** // 24Bitビットマップファイル読み込み * //******************************************** void readBMP( char *filename, // BMPファイル名 unsigned char image[Y_SIZE][X_SIZE][3] // 24ビットRGB画像配列 ) { FILE *fp; int i, j, k; // ファイルオープン if ((fp = fopen(filename, "rb"))==NULL) { printf("readBmp: Open error!\n"); exit(1); } printf("input file : %s\n", filename); // ヘッダー情報読み込む fread(&bfType, sizeof(bfType), 1, fp); fread(&bfSize, sizeof(bfSize), 1, fp); fread(&bfReserved1, sizeof(bfReserved1), 1, fp); fread(&bfReserved2, sizeof(bfReserved2), 1, fp); fread(&bfOffBits, sizeof(bfOffBits), 1, fp); fread(&biSize, sizeof(biSize), 1, fp); fread(&biWidth, sizeof(biWidth), 1, fp); fread(&biHeight, sizeof(biHeight), 1, fp); fread(&biPlanes, sizeof(biPlanes), 1, fp); fread(&biBitCount, sizeof(biBitCount), 1, fp); fread(&biCompression, sizeof(biCompression), 1, fp); fread(&biSizeImage, sizeof(biSizeImage), 1, fp); fread(&biXPelsPerMeter, sizeof(biXPelsPerMeter), 1, fp); fread(&biYPelsPerMeter, sizeof(biYPelsPerMeter), 1, fp); fread(&biClrUsed, sizeof(biClrUsed), 1, fp); fread(&biClrImportant, sizeof(biClrImportant), 1, fp); // RGB画像データ読み込む for (i=0; i<(int)biHeight; i++) for (j=0; j<(int)biWidth; j++) { for (k=0; k<3; k++) { //fread(&image[i][j][2-k], 1, 1, fp); fread(&image[biHeight-i][j][2-k], 1, 1, fp); } } fclose(fp); } //********************************************** // RGBカラー画像を256諧調白黒濃淡画像へ変換 * //********************************************** void BMPto256BW( unsigned char image[Y_SIZE][X_SIZE][3], unsigned char image_bw[Y_SIZE][X_SIZE] ) { int y, x, a; for (y=0; y<(int)biHeight; y++) for (x=0; x<(int)biWidth; x++) { a = (int)(0.3*image[y][x][0] + 0.59*image[y][x][1] + 0.11*image[y][x][2]); if (a<LOW) a = LOW; if (a>HIGH) a = HIGH; image_bw[y][x] = a; } } //***************************************** //各行の黒色判定 //***************************************** //**************************************** // 白黒濃淡画像配列のコピー * //**************************************** void imageCopyBW( unsigned char image1[Y_SIZE][X_SIZE], unsigned char image2[Y_SIZE][X_SIZE] ) { int x, y; for (y=0; y<(int)biHeight; y++) for (x=0; x<(int)biWidth; x++) image2[y][x] = image1[y][x]; } void main(void) { char input[100], output[100]; int intensity; printf("入力画像ファイル名(*.bmp):"); scanf("%s", input); readBMP(input, image_in); // 画像の入力,RGB24ビットカラーBMP画像を配列に格納 //一列各行の黒色の数出力 }

専門家に質問してみよう