No.3ベストアンサー
- 回答日時:
そもそも「ヘッダファイルから二次元配列を読み込む」という発想自体がよくないですね。
Fookyさんも言われている通り、通常ヘッダファイルに定義は書きません。(C++では例外も多々ありますが)
恐らくメインとなるソース以外の場所にあるマスターデータを、メインソースから使う方法を知りたいのでしょうが、マスターデータそのものを参照して使うのか、ローカル変数にコピーして使うのかということがはっきりしません。
Fookyさんは前者を前提に回答されているので、私は後者を前提に回答させていただきます。
・どちらの場合にせよ、データ及び関数の定義はソースファイルに書きます。
この場合、他のソースからも参照できるようにするための宣言をした、ヘッダファイルも必要になります。
・またマスターデータを、毎回ローカルな二次元配列として初期化するのはムダが多いので、グローバル宣言をして初期化します。
・マスターからデータを取得する関数ですが、Cでは配列を返すことはできないので、配列のポインタを渡し、値をセットするように実装します。
・二次元配列を引数に取る場合、ムリにポインタ表現しなくても、配列表現が許されているので、そのように書きましょう(ROW側は指定してもしなくても無視されます)。
/* data.h */
#define ROW 10
#define COL 10
void init_nijigen(char [ROW][COL]);
/* data.c */
#include <string.h>
#include "data.h"
static const char master[ROW][COL] = {
{・・・},
:
};
void init_nijigen(char p[ROW][COL])
{
memcpy(p, master, ROW * COL);
}
/* main.c */
#include <stdio.h>
#include "data.h"
int main(void)
{
int ir, ic;
char nijigenn2[ROW][COL];
init_nijigen(nijigenn2);
for (ir = 0; ir < ROW; ir++) {
for (ic = 0; ic < COL; ic++)
printf("%c", nijigenn2[ir][ic]);
putchar('\n');
}
return 0;
}
※補足ですが、Fookyさんのソースは、file.cをfile.cppに変えないと、通常の環境ではコンパイルエラーになります。
(Cでは、配列のサイズ指定には定数しか指定できません。const変数が許されるのはC++の言語仕様です。)
No.2
- 回答日時:
確かにCで2次元配列を扱うのは少し難しいんですが、それ以前に色々と問題
があるコードですね。
1.関数file()の戻り値がvoidになっている
これは2次元配列を返す関数のつもりで書かれているんではないんでしょう
か?それならば、void(戻り値なし)ではなく、2次元配列に相当するものを
返すように宣言しなければなりません。関数の戻り値の指定(void)とreturnの
中に書く変数の型は当然ながら一致していないといけません。
2.それじゃ、2次元配列をどうやって返すのか?
ここが難しいところなんですが、Cでは配列を一つのモノ(オブジェクト)
として扱うという考え方はしません。RAMの中で配列が格納されているメモ
リの場所(アドレス)を受け渡しします。この、アドレスを入れる変数をポイ
ンタと言います。したがって、file()関数は、10×10配列が格納されてい
るアドレスを指すポインタを返す関数にしないといけません。こんな説明を書
き出すと切りがないので、答え(と言ってもまだまだ間違えています)を書く
と、
char (*file())[10]
{
char nijigen[10][10] = {
{'#','#','#',...,'#'},
....,
{'#','#','#',...,'#'}};
return(nijigen);
}
配列を指すポインタ変数とそれを返す関数の書き方は、
char (*変数名)[10]:「10個のchar型が格納されているメモリを指すポインタ」
型の変数。
char (*関数名(関数の引数))[10]:「10個のchar…ポインタ」型を返す関数
となります。
3.file()の戻り値を受けるポインタ変数の宣言
nijigenの宣言は合ってましたが、char nijigen2[10][10];は間違いです。
こう書くと、Cは、新たに10×10の配列をメモリ上に用意します。今、や
りたいことはそれではないはずです。file()の中で用意された10×10配列
を扱いたいんですから。
nijigen[10][10]が正解なのは、nijigen[10][10]のところでは実際に
メモリ上に配列を用意するから正解なのです。
正解は、
char (*nijigen2)[10];
nijigen2 = file();
4.表示が転置されてる?
printf("%c", nijigen2[a][b]);
となってますが、これだと縦がa+1番目、横がb+1番目の要素が
表示されますが良いんですか?
5.局所変数を戻り値にしている
これは大問題です。file()の中の変数は、file()を出るときに全て解体され
ます。ということは、file()の中でメモリ上に作った10x10配列は、file()か
らreturnするときに消えてなくなります。したがって、ここは、nijigenを大
域変数として定義するのが良いでしょう。
~file.h~
...
static char nijigen[][10] = {
{'#', ..., '#'},
...};
6.ヘッダファイルの使い方がおかしい?
ヘッダファイルには普通、関数の中身(定義)は書きません。もう少し規模
の大きいプログラムになると即問題が発生します。ヘッダファイルを複数の.c
ファイルから読み込んだときに、同じ名前の関数が2箇所で重複して定義され
ていることになります。変数も同様です。上のstaticというのは、この変数は
今の.cファイルの中だけの話しですよ、ということを示すことによって、
file.hが複数の.cファイルから読まれても大丈夫なようにしています。(その
代わり、読まれた回数だけメモリを消費します)
ふぅ。何にせよ、本を一冊買ってポインタの辺りを勉強することをお勧めしま
す。
私がこのコードを書くと下のように成ります。当然ながらベストとは言いませ
ん。私の好みということです。2次元配列をつくるための「10個のchar…ポイ
ンタ」はできるだけ使わない方が、char (*nijigen2)[10];みたいなややこし
い宣言を使わなくて済みます。
~file.h~
static const int RowNum = 10;
static const int ColNum = 10;
static const char nijigen[RowNum][ColNum] = {
{...},
...
};
~file.c~
int
main(int argc, char **argv)
{
int r, c;
const char *pointer = nijigen[0];
for( r = 0 ; r < RowNum ; r++ ){
for( c = 0 ; c < ColNum ; c++, pointer++ )
printf("%c", *pointer);
printf("\n");
}
}
No.1
- 回答日時:
こんにちは。
itohhといいます。どのように、取り込もうとしたのかもう少し書いてください。
(2次元配列の定義部分や#include文の書き方など)
あと、うまくいかないとはどうなるのでしょうか?
(コンパイルエラーになる?実行時にうまく参照できない?)
このへんのことも、詳しく書いた方がアドバイスしやすいですよ。
この回答への補足
~file.h~
#include<stdio.h>
void file(){
char nijigenn[10][10]={{'#','#'・・・・・・'#','#'},
{'#','#'・・・・・・'#','#'},
・
・
・
{'#','#'・・・・・・'#','#'}};
return(nijigenn);
}
~file.c~
#include<stdio.h>
#include"file.h"
main(){
int a,b;
char nijigenn2[10][10];
nijigenn2=file();
for(b=0;b<10;b++){
for(a=0;a<10;a++){
printf("%c",nijigenn2[a][b])
}}
}
こんな感じで作ってみたんですけど、コンパイルが上手くできませんでした。
よろしくお願いします。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・人生のプチ美学を教えてください!!
- ・10秒目をつむったら…
- ・あなたの習慣について教えてください!!
- ・牛、豚、鶏、どれか一つ食べられなくなるとしたら?
- ・【大喜利】【投稿~9/18】 おとぎ話『桃太郎』の知られざるエピソード
- ・街中で見かけて「グッときた人」の思い出
- ・「一気に最後まで読んだ」本、教えて下さい!
- ・幼稚園時代「何組」でしたか?
- ・激凹みから立ち直る方法
- ・1つだけ過去を変えられるとしたら?
- ・【あるあるbot連動企画】あるあるbotに投稿したけど採用されなかったあるある募集
- ・【あるあるbot連動企画】フォロワー20万人のアカウントであなたのあるあるを披露してみませんか?
- ・映画のエンドロール観る派?観ない派?
- ・海外旅行から帰ってきたら、まず何を食べる?
- ・誕生日にもらった意外なもの
- ・天使と悪魔選手権
- ・ちょっと先の未来クイズ第2問
- ・【大喜利】【投稿~9/7】 ロボットの住む世界で流行ってる罰ゲームとは?
- ・推しミネラルウォーターはありますか?
- ・都道府県穴埋めゲーム
- ・この人頭いいなと思ったエピソード
- ・準・究極の選択
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
C言語 配列の長さの上限
-
先頭アドレスとは何ですか?
-
C# 配列の変数宣言について。
-
CSVファイルのデータを2次元配...
-
2次元配列を戻り値とする関数?
-
C言語初心者 ポインタについて...
-
配列をEraseしてもメモリが開放...
-
市販のビンゴカードについて
-
なぜ配列は0から始まるのです...
-
複数の選択範囲の行番号を個別...
-
VB2010でのコントロール多次元...
-
VBで構造体の配列を関数に渡す...
-
Functionの戻り値を2次元配列...
-
配列を使わずに、変数名を動的...
-
LGノートPCグラムについて
-
ポインタの配列のコンマについて
-
if文の判定条件に配列
-
配列内の文字間を排他的論理和...
-
配列の参照渡しで型が一致しま...
-
テキストファイルから文字列を...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
C言語 配列の長さの上限
-
配列を使わずに、変数名を動的...
-
配列で格納したものをmsgboxで...
-
C# Listを使わずに2次元配列の...
-
C# 配列の変数宣言について。
-
先頭アドレスとは何ですか?
-
C言語で特定列だけを抽出して配...
-
配列の参照渡しで型が一致しま...
-
VBで構造体の配列を関数に渡す...
-
C++ vectorに配列をプッシュしたい
-
【速いブラインドタッチ】手を...
-
unsigned char配列への入力の仕方
-
配列をEraseしてもメモリが開放...
-
【C言語】配列の中に配列を入れ...
-
ExcelVBAで質問です。離れた二...
-
4勤2休のシフト作成
-
Functionの戻り値を2次元配列...
-
Redimした動的配列はEraseする...
-
配列を含む構造体の初期値について
-
複数の選択範囲の行番号を個別...
おすすめ情報