• ベストアンサー

配列の動的確保

No.847223 reallocについて No.847300 ポインタについて と質問させてもらい、御回答をいただき、理解した(つもりな)のですが、以下のことが実現できなくこまっております。 (以前の質問はこれを実現するために質問しました。) まず配列array[1][20]を用意します(つまり文字列最高20字格納できる要素数1個の配列を用意)。 そして動的にこの配列のサイズを変更して、なにか文字列を入力する毎に、代入するスペースを逐次確保したいわけです。(メモリが溢れない限りスペースを確保しまくる) そこでcallocやreallocの記述の仕方に困っています。 まず、callocについて char array[1][20]; char *pn, *pn2; pn = (char *)calloc(sizeof(array)/sizeof(char),sizeof(char)); このボイドポインタをキャストする部分にchar* と char** のどちらを使えばいいか、です。 そしてreallocについて、 if( (pn2 = (char *)realloc(pn, sizeof(array)*cnt)) == NULL ){ printf("メモリの確保失敗!\n"); exit(0); } pn=pn2; strcpy(pn[cnt],input); 【ただし、cntは毎回1づつ増加する。】 【inputはchar型の配列で、なんらかの文字列がはいっている。】 としているのですが、これもキャストの仕方がわかりませんし、strcpyで、セグメンテーションフォルトになります。構造体を使ったリスト形式も考えたのですが、reallocの使いかたを覚えたいのであえてこの形式で実現しようとしています。 結局どうしたいかというと、realloc部をforループさせて、cntを1ずつ増加させ、 pn[1][20] つぎは pn[2][20] つぎは pn[3][20] とどんどん増やしていきたいわけデス。 すこしわかりにくい説明だとおもいますが、不明点や、言い回しがオカシイ箇所があればご指摘下さい。

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

  • ベストアンサー
  • nyan5504
  • ベストアンサー率42% (6/14)
回答No.3

おっしゃるとおり、第一引数がNULLの場合の動作はmallocです。 typedefをしない場合は、それぞれ char (*pn)[20] = NULL; と pn = (char(*)[20])realloc(pn, sizeof(char[20])*cnt); となるのかな。ちと自信ないですが。

unchikun
質問者

お礼

再び御回答ありがとうございました。 (char(*)[20]) という風にキャストするんですね... (char [20] *)とやっていたのでエラーにひっかかって困ってました^^; char (*pn)[20] とは、「char型の要素数20個の配列へのポインタ」を宣言しているわけですよね? なんとなくわかってきました! #1の方にアドバイスしていただいた方法での解決方法もきになるのでそちらのほうもがんばってみます。

その他の回答 (3)

noname#9119
noname#9119
回答No.4

『「20字格納できる配列」を指すポインタの配列』を増やすので。 char **array=NULL; int i; int n =5; for (i=0; i<n; i++) { array = (char**)realloc(array, sizeof(char*) * (i+1)); array[i] = (char *)calloc(20,1); } これで char array[5][20]; であるかのように使える。

unchikun
質問者

お礼

やはりこの方法だと多次元配列のように、array[0],array[1]の表すポインタが等間隔(20バイト)にならぶようなメモリ配置はできないんですね^^;最初は24バイト間隔になっていました。 mihano様の方法だと、 reallocでchar型ポインタの配列、array[0],array[1]と逐次確保していき、あたらしく割り当てられたarray[i]に、callocによって動的確保したchar型の要素数20個の配列の先頭アドレスをセットする。 こういう解釈でよろしいでしょうか。よろしければこの確認だけお願いします。 ところでこの方法でも、array[5][1]というアクセスができるのは驚ろきました。array[][]と記述は多次元配列しかできないとおもっていたのですが、(array[5])[1] という風に考えるとなっとくできました。

  • nyan5504
  • ベストアンサー率42% (6/14)
回答No.2

まず、arrayがサイズの決定にしか使われていないようなので typedef char ARRAY[20]; などするべきです。その上で、pnの型は ARRAY* pn = NULL; です。reallocでの確保は、 pn = (ARRAY*)realloc(pn, sizeof(ARRAY)*cnt); となります。pn1は必要ありませんし、mallocやcallocも使う必要はありません。

unchikun
質問者

お礼

nyan5504様の方法でとりあえずできました。ありがとうございます。 「C言語 関数の使いかた+作り方 完全制覇」という書籍をまた改めて確認したところ、pn部分には「NULLを指定してもよい」とかいてありました^^;また見落していました、すいません。。。 NULLを指定したときの動作はMALLOCと同じと考えてよろしいでしょうか? ひとつだけ疑問なのですが、もしこれにtypedefを用いなければどうかけるのでしょう。。 頭が混乱して疑問ばかりが生じてしまって申し訳ないです。

noname#9119
noname#9119
回答No.1

char array[1][20]; このような静的配列のサイズを変更することはできません。 逆に言えば、動的に確保すればreallocを使えるわけです。 char **array=(char**)malloc(sizeof(char*)); array[0] = (char *)calloc(20,1); 足りなくなったらarrayをreallocで確保しなおしていく。 キャストの仕方がわからないのは、確保したものが何で、何に使おうとしているのか分かっていないということでしょう。

unchikun
質問者

お礼

>char **array=(char**)malloc(sizeof(char*)); >array[0] = (char *)calloc(20,1); これを元にreallocを考えたのですが、どうしても思い付きませんでした。 array = (char **)realloc(20*cnt); でしょうか?これだけではたとえばcnt=2のとき、array[1]の値はNULLだったので、array[1]=array[0]+20;としなくてはいけませんでした。さらにarray[1][0]という記述ができなかったので、たぶんこれもだめですよね。 array[1]=(char *)realloc(20*cnt); ともやってみましたが、これは自分でもちがうのはわかります。 array[0]=(char *)realloc(20*cnt); これもたぶんだめですよね。 mihano様の記述方法だと、どうreallocをつかって確保すればいいのでしょうか....

関連するQ&A

  • 多元配列について(ANSI C)

    動的多元配列で、 Voidポインタに、多種の型がぶら下がった多元配列を作り、 読み書きをしたいのですがどのようにしたらよろしいでしょうか。 具体的には、 x[0][1]は、intで「2」が入っている x[0][4]は、intで「9」が入っている x[1][2]は、charでしかも文字列の配列で「goo」が入っている x[1][5]は、charでしかも文字列の配列で「教えて」が入っている x[0]は、int型の配列。X[1]は、文字列型の配列。 というようなものです。 一応ソースは作ってみたのですが、int型では問題なくいくのですが、 文字列は、コンパイルはできますが、実行すると予期せぬことが起きます。 #include <stdio.h> #include <stdlib.h> #include <string.h> int main (void) {      void **topPointa;      int * iDataInput;      int * iDataOutput ;      char * chDataInput;      char * chDataInput2;      char * chDataOutput1 ;      // ポインタアドレス用のメモリ確保      topPointa = (void *) calloc (10 , sizeof(void *));      if(topPointa == NULL) {           printf("メモリが確保できません\n");           exit(-1);      }      //int配列のメモリ確保      iDataInput = (int * ) calloc (10 , sizeof(int));      if(iDataInput == NULL) {           printf("メモリが確保できません\n");           exit(-1);      }      iDataInput[0] = 3 ;      iDataInput[1] = 4 ;      topPointa[0] = (void * ) &iDataInput;      //int配列の取り出し      iDataOutput = *(int *) topPointa[0];      printf( "int: %d\n", iDataOutput[0] );      printf( "int: %d\n", iDataOutput[1] );      //char配列 のメモリ確保      chDataInput = (char * ) calloc (10 , sizeof(char *));      if(chDataInput == NULL) {           printf("メモリが確保できません\n");           exit(-1);      }      chDataInput2 = (char * ) calloc (10 , sizeof(char));      if(chDataInput2 == NULL) {           printf("メモリが確保できません\n");           exit(-1);       }      strcpy(chDataInput2 , "hoe");      chDataInput[0] = &chDataInput2;      topPointa[1] = (void * ) &chDataInput;      //char配列の取り出し      chDataOutput1 = *(char *) topPointa[1];      printf( "char: %S\n", chDataOutput1[0] );      free(iDataInput);      free(chDataInput);      free(chDataInput2);      return 0; } 言語は、C言語ANCI Cでお願いします。 以上。よろしくお願いします。

  • mallocで char *型の配列を確保したい

    char *方の配列を動的確保する必要が出たのですが、 char **array=(char **)malloc((char *) * 10); としてうまくいきません どうすれば確保できるのでしょうか 知っている方がいましたら教えてください ちなみに確保した配列はこの様に使えるようにしたいです strcpy(array[0],"testest");

  • reallocでメモリを再確保するには?

    こんにちわ, 今, 「すでに動的確保しているメモリをその型分1サイズだけ増やす」というプログラムを考えています。 具体的には, char* str_p; a=calloc(str_p, sizeof(char)); /*ここから問題のプログラム(実際はずっと動くので無理です*/ while(1) { a=realloc(str_p, sizeof(str_p)+sizeof(char)); } ・・・・・・ これだと,私的にはsizeof(str_p)で今のサイズを調べ,それにsizeof(char)を加えることで次々に1サイズ大きいメモリを再確保できると思ったのですが,ポインタのサイズを指していてそれにchar型のサイズをたしていていつも固定サイズになるみたいでうまくいきません。 どうすれば,char*などポインタ型の変数の大きさを調べられるのでしょうか。 また,どうすれば,1サイズずつ大きくできるのでしょうか。 よろしくおねがいします。

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

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

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

  • 動的に確保した配列のファイルへの書き出し

    動的に確保した配列を、ファイルに書きだそうとしています。 int i, arraysize = 10; int **array; array = new int*[ arraysize ]; for (i = 0 ; i < arraysize ; i++) array[ i ] = new int [ arraysize ]; ofstream out("filename", ios::out | ios::binary); out.write((char *) array, sizeof( array )); これでは array のポインタが書き込まれるだけ、なのかな ? ということで、配列を書き込む目的を果たせておりません。このように動的に確保した多次元配列 (要素数は既知) をファイルに書き込むためにはどうすればよろしいでしょうか。

  • 2次元配列の動的確保について、アドバイス下さい

    今、大容量の2次元配列を造りたいので、 メモリの動的確保の勉強をしてました。 昔は、サイズ分mallocで確保して、配列の各行の先頭アドレスを それぞれ対応させていって、行列としてポインタを扱えるようにしてたのですが、 調べていると、もっと簡単に2次元配列のメモリを確保できるみたいなので、その方法を調べていました。 その中で、 if(!(ptr = (int (*)[RETSU])calloc(GYOU*RETSU, sizeof(int)))) こういう例題を見つけたんですけど、 これの、(*)[RETSU])のところが、理解できません。 これは何をしているのでしょうか? どういう言葉で検索すれば、説明が出てくるのか解らなかったので質問させて頂きました。 この(*)[RETSU]の感じの書き方をすると、結構簡単にメモリ確保できるみたいなので、解説、または説明サイトなど教えて頂けると助かります。 または、例題を書いていただけるとスゴク助かります。 ちなみに私が造りたいのは、 100行300000列 ほどの配列です。 是非、よろしくお願いします。

  • 動的に配列を確保した時の操作の仕方

    ---------------- ヘッダ ------------------- typdef struct _TAG { char *mes; // メッセージの先頭アドレス確保 } *pTAG; pTAG ptag; // ポインタ上に長さが違う文字列を確保 char *local_mes[] = { "テスト文字列だよ", "文字列は長さが違うよ", "教えて!goo", }; ------------------------------------------- ---------------- ソース ------------------- void main( void ) { // 先頭アドレスを確保する。 ptag->mes = *local_mes; 【ptag->mesを使い、文字列描画がしたい!】 } ------------------------------------------- ソースコードを長く書いてしまいそうなので、要点だけ絞りました。 【やりたい事】としては、 ptag->mes = *local_mes で、 ptag->mesから文字列を全て描画したいのですが、上手く行きません。 調べたところ、ptag->mesが一次元配列化してるらしく、 "テスト文字列だよ" <-- 16バイト + 1バイト 17バイトptag->mesを進めると、次の行まで行き着きますが、 sizeof関数も上手く扱えません。 sizeof( ptag->mes ) = 4 <? 是非とも解決策をお願いします。 開発環境は、 borland C++ compiler 5.5です。

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

  • 動的に生成した文字列の配列を返す関数について

    動的に生成した文字列の配列を返す関数について お世話になります。 動的に文字列の配列を生成する関数を作ったのですが、 配列をうまく受け渡すことができず困っています。 以下のように入力された件数の数だけ "abc 0"~"abc n"という文字列を生成を行っています。 関数自体は期待通りの動作をしているようなのですが、 (Test1関数の最後でbfを確認しました) 呼び出し側にうまく配列を渡すことができません。 以下にソースを掲載いたしますのでどなたかご教示いただけたらと思います。 環境はVisualStudio2005です。 よろしくお願いします。 #include <stdio.h> #include <string.h> #include <stdlib.h> void Test1(char **bf, int *cnt) { int i; int kensu; int charlength; char num[10]; char **nm1 = NULL; char **nm2 = NULL; printf("件数を入力:"); scanf("%d",&kensu); for(i=0; i < kensu; i++) { nm2 = (char**)realloc(nm1, sizeof(char*) * (i + 1)); nm1 = nm2; charlength=128; nm1[i] = (char*)malloc(sizeof(char) * (charlength)); strcpy(nm1[i], "abc "); itoa(i, num, 10); strcat(nm1[i], num); } bf = nm1; *cnt = i; return ; } void main() { int cnt; char **bf = NULL; Test1(bf, &cnt); printf("START\n"); printf("全部で%d件。\n", cnt); for(int i=0;i < cnt;i++) { printf("%s\n",bf[i]); } free(bf); printf("END\n"); }