
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で質問しましょう!
似たような質問が見つかりました
- Gmail PCのGmailから、他サーバーメールを読みに行き、Gmailに取り込める方法を詳しく教えて下さい。 2 2022/04/02 10:49
- ノートパソコン iTunesで取り込んだ音楽が音飛びします。 2 2022/05/05 21:37
- Android(アンドロイド) 音楽ファイルが同期されていない。 1 2022/06/01 13:08
- iPhone(アイフォーン) CDジャケットの取り扱い説明書(曲名や、その曲についての詳しい説明書)をiPhoneに取り込む方法を 1 2023/02/21 21:32
- Android(アンドロイド) youtube の音楽を、ソニースマホXperi1とウォークマンに取り込みたい。 3 2023/02/23 14:33
- Access(アクセス) CSVファイルの「0落ち」にVBA 6 2023/02/02 15:27
- システム 外付けHDDの初期化について 4 2023/03/05 21:19
- プリンタ・スキャナー 書類スキャン方法 コピー機故障中 3 2022/12/19 20:08
- システム 外付けHDDの初期化について 4 2023/03/05 20:00
- 音楽・動画 パソコンでDVDの動画を保存していますが動画へ字幕を入れたいと思っています。いろんなアプリ、ソフトあ 1 2022/07/31 09:26
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
C言語 配列の長さの上限
-
先頭アドレスとは何ですか?
-
C# Listを使わずに2次元配列の...
-
【速いブラインドタッチ】手を...
-
C言語で特定列だけを抽出して配...
-
C言語初心者 構造体 課題について
-
配列と乱数を使ったプログラム
-
ポインタの配列のコンマについて
-
スマホの数字キーをISOの配置に...
-
配列を使わずに、変数名を動的...
-
複数の選択範囲の行番号を個別...
-
Excel、VBAのユーザーフォーム...
-
C++ vectorに配列をプッシュしたい
-
電子書籍を見るためにはどうし...
-
if文で「配列a[i]が小数ならば...
-
メモリの初期値
-
プログラムが書けません。
-
配列の要素数に変数を入れたい...
-
関数から配列を返すには?
-
C言語のポインタに直接アドレス...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
C言語 配列の長さの上限
-
配列を使わずに、変数名を動的...
-
C# Listを使わずに2次元配列の...
-
【速いブラインドタッチ】手を...
-
配列をEraseしてもメモリが開放...
-
テキストファイルから文字列を...
-
先頭アドレスとは何ですか?
-
配列で格納したものをmsgboxで...
-
複数の選択範囲の行番号を個別...
-
C# 配列の変数宣言について。
-
C++ vectorに配列をプッシュしたい
-
配列を含む構造体の初期値について
-
VBで構造体の配列を関数に渡す...
-
C言語で特定列だけを抽出して配...
-
キーボードのキー配列について
-
ExcelVBAで質問です。離れた二...
-
2次元配列を戻り値とする関数?
-
unsigned char配列への入力の仕方
-
【C言語】配列の中に配列を入れ...
-
Redimした動的配列はEraseする...
おすすめ情報