• ベストアンサー

C言語の配列のサイズ

Oh-Orangeの回答

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

★私もマクロ関数を作って利用していますね。 ・回答者 No.6 さんのマクロ定義と同じです。→マクロ名は違いますが…。  #define ArrayOf(s) (sizeof(s) / sizeof((s)[0]))  と定義して使っています。 ・使い方は『unsigned char test1[100][30][5];』の場合は  (1)ArrayOf(test1).........[100]の添え字の要素数を返す  (2)ArrayOf(test1[0])......[30]の添え字の要素数を返す  (3)ArrayOf(test1[0][0])...[5]の添え字の要素数を返す ・『ArrayOf()』マクロ関数はどんな型でも構造体などの配列でも添え字の要素数をコンパイル前に  自動的に計算してくれます。定義内容から『sizeof』演算子を使っています。  三次元配列の場合『ArrayOf(test1)』と指定すると[100]という添え字の要素数を計算しますが  これは sizeof(test1) / sizeof(test1[0]) を計算しています。  =sizeof(test1) / sizeof(test1[0])  =[100]x[30]x[5] / [30]x[5]  =15000 / 150  =100 ・多次元配列の各要素数を計算したい場合は  ArrayOf(test1)  ArrayOf(test1[0])  ArrayOf(test1[0][0])  ArrayOf(test1[0][0][0]) ←三次元配列の場合、これはエラーですよ。注意!  などとします。 ・『unsigned char test1[][30];』のような要素数を省略すると二次元の部分が『可変長』という  感じで宣言されます。つまり『test1[1][30]』~『test1[100][30]』など二次元の添え字部分は  固定にしないため場合によっては便利な記述です。 ・例えば  static const char *string[] = {   "文字列1",   "文字列2",    :   "文字列n",   NULL,  };  という定義を見たことありませんか?  これと同じですよ。→任意要素数を定義している。 ・ただし、この指定は一番大きい外側の次元部分のみしか許されません。  つまり、『test1[100][][30];』などはエラーです。『test1[][10][30];』としか記述できません。 最後に: ・回答者 No.1、No.3、No.7 さんのように添え字の数に『[0]』以外を指定しても正しくコンパイル  できます。また、動作にも悪影響はありません。でも『sizeof(ary[100][30][5]);』という指定方法は  誤解を招きやすいと思います。『破綻する』か、『破綻しない』とかの問題ではありません。  可読性です。ぱっと見て『間違い?』と見えるような記述はしない方が良いと言うことです。 ・以上。おわり。

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

  • C言語でunsigned char配列を連結する方法ってありますか?

    C言語でunsigned char配列を連結する方法ってありますか? 例えば unsigned char test[]={0x00,0x02,0x03}; unsigned char test2[]={0x05,0x06}; という配列があったとして test[]という配列のあとにtest2の配列を追加することは可能でしょうか? {0x00,0x02,0x03,0x05,0x06}という配列になればOKです。 よろしくお願いします。

  • C言語の型と配列

    char* str[10]={"a","b"}; char* str2="c"; としたときにstr=str2とすると 型が合わないといったエラーが出ます。 でもstrって結局はポインタの配列の先頭要素のアドレスですよね。 ポインタにポインタを入れているので通るのかなと思ったんですけど、 配列で宣言するとポインタにも型がつくのでしょうか? この例だと strは char * を10個持つ配列をさすポインタ  で、 str2はchar *をさすポインタ みたいなかんじです。 質問の意味がわかりにくいですが、ご指摘をいただければ補足しますので よろしくお願いします。

  • 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]’ このような書き方はやはりやめたいいのでしょうか。 また、その際はサイズ別に関数を作るしかないのでしょうか。 他にいい方法があれば教えていただけると助かります。

  • ポインタと配列の法則

    ポインタと配列の法則がまだ、理解していません。 char *test1[] = { "あいうえお", "かきくけこ" }; と char test2[][20] = { "あいうえお", "かきくけこ" }; は、どちらも正しいでしょうか? 下は、sizeof(test[0])とすると20となりますが、上はなりません。 メモリの格納されている状態など知りたいです。 CではPHPのような var_dump関数は無いのでしょうか?

  • c言語 型変換について

    c言語 型変換について 下記のように文字コードは、unsigned int型('B')をunsigned char 型(str[1] ) 格下げする型変換する規則を教えてください。 *質問ソースプログラム: int main(void) { char str[4]; /* 文字列を格納する配列 */ str[0] = 'A'; /* 代入 */ str[1] = 'B'; /* 代入 */ ・・・・・・ printf("size B %u\n",(unsigned)sizeof('B')); printf("size str[1] %u\n",(unsigned)sizeof(str[1])); * 実行結果 size B 4 size str[1] 1

  • C言語でのコンパイルエラー

    初心者です。 非常に基本的な質問かもしれませんが、 ご回答いただけたらうれしいです。 void test1(unsigned char* data) { } void test2(unsigned char** data) { } int main(void) { unsigned char data1[6]; unsigned char data2[6][6]; test1(data1); test2(data2); } としてtest1はうまくいくのに、 test2はコンパイルエラーになります。 どっちもポインタになると思うのですが…。 また、unsigned char data2[6][6]を 他の関数の引数とする場合は どうすればよろしいのでしょうか? 宜しくお願いいたします。

  • C言語について教えてください。

    二次元配列でまとめられた「配列で実現する文字列」の文字と文字列を表示する関数を定義し、その関数の機能を確認するプログラムを作成する。 ただし、以下の例のように文字列の個数が変更されても処理できる関数を作成する。 また、文字列の文字の個数は最大9とする(一次元配列の要素数は10とする) さらに、関数printf()をできるだけ用いない。 (1)二次元配列でまとめられたすべての文字列を「一度に」表示する関数を定義する (2)二次元配列でまとめられたすべての文字列の文字を「一度に」表示する関数を定義する。このとき、前回の課題で定義した「すべての文字を表示する関数print_all_char()」を新しく定義する関数から呼び出して用いる。 (3)二次元配列に各文字列を格納してまとめるとき、初期化ではなく、配列の宣言・定義の後で、関数strcpy()を用いること(例では、初期化によりまとめている) [例] char astr[][10] = { "ABCD", "EFGHIJ", }; [実行結果の例] すべての文字列の表示 ABCD EFGHIJ すべての文字列の文字の表示 A B C D E F G H I J [ヒント] (1)二次元配列でまとめられた文字列の文字あるいは文字列を表示する関数<返却値型><関数名>(二次元配列の受け渡しに対応した仮引数の宣言、文字列の数) (2)文字列の数を求める。二次元配列のすべての要素に文字列が格納されている場合、文字列の数=二次元配列の要素数(一次元配列の数) =sizeof(astr)/sizeof(astr[0]) ただし、sizeof演算子の生成する型はsize_t型である。 この問題について教えてください。問題丸投げだとは分かっていますがどうしても分かりません。教えてください。ちなみに前回の課題の定義は下の通りです。 void print_all_char(char *chs) { while(*chs!='\0') { printf("%c\n",*chs); chs++; } } よろしくお願いします。

  • unsigned char の配列で途中で0を含む時のstrlen

    表題のようにunsigned char a[10]; の配列で、文字列ではなくデータとして扱っている時、どうしても途中で0が混じります。そこでstrlen(a) を取ると途中までの長さの値しか取れません。 sizeof(a) としてもunsigned char のsize=4 になるだけです。 この回避策はあるでしょうか。

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