Visual C++ 2005のC++/CLIでプログラム作成しています。
C言語で書かれたプログラムを組み込みたい為に、
マネージコードでテキストファイル読み込みをして、2次元配列に格納し、
int型に変換してネイティブコードの配列にコピーしたいのですが、上手く書けません。。
テキスト内容は数字のみで2次元に並んでおり、1文字ずつ配列に入れたいです。
エラー出ているのですが、下記にコードを載せます。
#include<string>
#include<vcclr.h>
using namespace System;
using namespace System::IO;
int main(void){
//ファイルオープン
StreamReader^ sr = gcnew StreamReader("hoge.txt");
int x, y;
//ファイルの内容読込み
for(y=0;;y++){
String^ line = sr->ReadLine();
//データ末尾まで読み込んだらループ終了
if(line == nullptr) break;
array<array<String^>^>^ table = gcnew array<array<String^>^>(line->Length);
int X=line->Length;
int Y=table->Length;
//読み込んだ内容を表示
Console::WriteLine("<System::String表示>" + table);
//System::Stringのline内容(文字列)をコピーする変数
char tmp[128];
sprintf(tmp,"%s",line);
printf_s("<char配列> tmp=%s\n",tmp);
//char*変数の内容表示
array<array<int>^>^ data= gcnew array<array<int>^>(Y,X);
//int型に変換
for(x=0;x<X;x++){data[y][x]=atoi(table[y][x]);}
}
//ファイルのクローズ
sr->Close();
return 0;
}
汚く読みづらいコードで大変申し訳ありません。。
元はdefineで成分数(X,Y)を宣言していました。
しかし、読み込むファイル内容によって変えたく、arrayでLengthを使いました。
またこれ以外でいい方法がございましたら、どうか教えてください。
どなたか、ご教授よろしくお願いします。
No.3ベストアンサー
- 回答日時:
こんばんは。
補足を頂きました。合点が行きました。ファイルによってXとYが可変するという事は、少なくともdata[y][x]は動的に割り当てないと対応できないのでは。
なるべくString^やarray<T>^を利用して、寸前までC言語への変換を遅らせた方が良いかもしれません。
array<array<String^>^>^ table
とされていますが、実際には
array<String^>^ table
で十分だと思います。ストリームリーダへ1ライン毎に読み込ませながら、tableを拡大して行けば良いと思います。
y = table->Length
x = line->Length
を使って、int data[y][x]を動的に割り当てて、
data[y][x] = int::Parse(table[y][x].ToString())
としていけば、atoi()を使用せずとも簡単に変換出来ます。
複雑化して来ているので、なるべくフェーズ毎に関数へ分解した方が最終的には取り扱いが楽になります。
後、ループはfor each in構文を使用した方が、良い事もあります。
以下参考程度です。
因みに此れ、例えば、
2547379780
6972206030111
7920373017
2
11
657
などでも受け付けます。array<T>^やString^を使用しているので、そう言った事が簡単に出来ます。
もしかしたら、間違いがあるかもしれませんが、そこはご勘弁です。
#include<string.h>
#include<vcclr.h>
#include<stdlib.h>
using namespace System;
using namespace System::IO;
//2次元配列のハンドル
struct Array2DHandle
{
int width;//Xの事
int height;//Yの事
int** data;//data[y][x]で使用する
};
//2次元配列を割り当てる
void AllocateArray2D(Array2DHandle* handle)
{
//縦幅を割り当てる
handle->data = new int*[handle->height];
//横幅を割り当てる
for(int y = 0; y < handle->height; ++y)
{
handle->data[y] = new int[handle->width];
}
}
//2次元配列を開放する
void Array2DFree(Array2DHandle* handle)
{
//横幅を開放する
for(int y = 0; y < handle->height; ++y)
{
delete [] handle->data[y];
handle->data[y] = NULL;
}
//縦幅を開放する
delete [] handle->data;
handle->data = NULL;
}
//String^テーブルからint[y][x]に変換する
void ConvertArray2DFrom(Array2DHandle* handle, array<String^>^% table)
{
int y = 0;
for each(String^ line in table)
{
printf("<int配列> ");
int x = 0;
for each(Char wc in line)
{
handle->data[y][x] = int::Parse(wc.ToString());
printf("%d", handle->data[y][x]);
++x;
}
printf("\n");
++y;
}
}
//ストリームリーダーを読み込んで、String^テーブルを作成する
array<String^>^ ConvertTableFrom(StreamReader^% sr)
{
array<String^>^ table = gcnew array<String^>(0);
String^ line = nullptr;
while(!sr->EndOfStream)
{
line = sr->ReadLine();
//読み込んだ内容を表示
Console::WriteLine("<System::String表示>" + line);
//String^テーブルを拡大して読み込んだ内容を入れていく
table->Resize(table, table->Length + 1);
table[table->Length - 1] = line;
}
return table;
}
//String^テーブルの最大横幅を調べる
int GetTableMaxWidth(array<String^>^% table)
{
int width = 0;
for each(String^ line in table)
{
//比較しながら一番文字数が多かったString^がdata[y][x]のxに必要な幅
if(width > line->Length)
continue;
width = line->Length;
}
return width;
}
int main(void)
{
//ファイルオープン
StreamReader^ sr = gcnew StreamReader("hoge.txt");
//ファイルが無い
if(sr == nullptr)
return 0;
//String^の配列に変換する
array<String^>^ table = ConvertTableFrom(sr);
//ファイルのクローズ
sr->Close();
//配列が拡張されなかった
if(table->Length == 0)
return 0;
//2次元配列の作成準備
//サイズ固定={X, Y}で入力する
//Array2DHandle handle = {10, 3};
//こっちは、読み込んだ文字列の行数と一番大きな文字列数からdata[y][x]のyとxを決定する
Array2DHandle handle = {GetTableMaxWidth(table), table->Length};
//割り当てる
AllocateArray2D(&handle);
//String^の配列からint[y][x]に変換する
ConvertArray2DFrom(&handle, table);
//開放する
Array2DFree(&handle);
return 0;
}
この回答への補足
こんばんは。すばらしいコードありがとうございます!!
> ストリームリーダへ1ライン毎に読み込ませながら、tableを拡大して行けば良いと思います。
tableを拡大するという考えがあったのですね。最初から2次元で作ろうという考えしかなかったので、びっくりしました。
Parseを使っての変換は文字の型変換でしか使用してなかったし、for each構文は表示でしか利用してませんでしたので、
とても参考になります。
また、ジャグ配列も対応してるなんて、すごいです!
さっそく実行してみました。
2次元配列を割り当てるところまでは問題ないようなのですが、
関数ConvertArray2DFromで、エラー「入力文字列の形式が正しくありません」となってしまいます。
> for each(Char wc in line)
このCharをcharに変えると、実行はできるのですが、
表示する文字が違うものになってしまいます。
もう少し色々と模索してみようと思いますが、
よろしかったらここの改善方法お願いします。。
ずうずうしくて申し訳ありません。
コード、本当にありがとうございました。
すみません><
もう一度ちゃんとやってみたら、上手く表示されました!
読み込むファイルの問題でした;
お騒がせして申し訳ありません。。
この度は大変お世話になりまして、ありがとうございました。
これで、次のステップにようやく進めることができます。
本当にありがとうございました。
No.2
- 回答日時:
動作確認した訳では、ないけど、少しだけ、回答しておきます。
> //読み込んだ内容を表示
> Console::WriteLine("<System::String表示>" + table);
配列 table にデータを読み込んでいる処理は見当たりませんよ?
読み込んだ内容を表示する前に、tableにはデータを入れておく必要があると思われます。
> //System::Stringのline内容(文字列)をコピーする変数
> char tmp[128];
> sprintf(tmp,"%s",line);
> printf_s("<char配列> tmp=%s\n",tmp);
データ型の変換をしている処理でしょうか?
Stringからcのデータ型へ変換するなら、
System::Runtime::InteropServices::Marshalクラス
に便利そうなメソッドがあるようです。調べてください。
例えば、StringToHGlobalAnsi()とか、StringToHGlobalUni()。
> for(x=0;x<X;x++){data[y][x]=atoi(table[y][x]);}
atoi()関数のパラメタ型は、Stringではなくchar*だと思います。
どれも、Webで検索すれば、すぐに解決方法を見つけられるはずですよ。
この回答への補足
遅くなって申し訳ありません。
回答ありがとうございました!
> 読み込んだ内容を表示する前に、tableにはデータを入れておく必要があると思われます。
元あったプログラムを書き換えていたので、中途半端に出力を残してしまっていました。
確認で出力表示していたので、この部分は必要ないのですが、
tableにはデータを入れないと後にも使えませんね;
ご指摘ありがとうございました!
> Stringからcのデータ型へ変換するなら、
> System::Runtime::InteropServices::Marshalクラス
調べが足りなかったようで。。こんな便利なクラスがあったんですね。
これを使って書き換えてみます。ありがとうございます。
> atoi()関数のパラメタ型は、Stringではなくchar*だと思います。
これもMarshalクラスを使って変換した配列ならできそうですね。
まだ色々といじっている所で、まだ意図したようにはできていないのですが、
教えてくださった所をがんばってみます。
本当にありがとうございました
No.1
- 回答日時:
こんばんは。
うう~む、コンパイルには通せましたが・・・。
Hoge.txtの中身の並びと、其れがInt型の配列になった時にどんな感じになるのかを記載して頂ければ協力出切るかもしれません。
この回答への補足
遅くなって申し訳ありません;
回答ありがとうございました!
hoge.txtの内容は以下のような感じです。
2547379780
6972206030
7920373017
実際のものとは違いますが、このように数値が並んでいます。
この例ではX=10,Y=3というように、XとYはファイルごとに成分数が違います。
このファイル内容をInt型の配列に1文字ずつ格納して、他のCのプログラムで参照できるようにしたいのです。
ファイル内容によって成分数を変えたくて、このような混在したコードを使おうと思った次第です;
よろしくお願いします。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# c言語の問題です 課題1 (二分探索木とセット) 大きさ size の配列 array を考える。す 2 2023/01/10 21:08
- C言語・C++・C# このプログラミング誰か教えてくれませんか 1 2022/06/02 15:27
- PHP 配列の値の更新方法について 1 2022/08/05 09:49
- Java javaでのプログラム(配列)について質問です. 2 2022/10/14 22:27
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
- C言語・C++・C# プログラミング c言語 4 2023/03/07 01:05
- C言語・C++・C# C言語プログラム変更 2 2022/12/21 15:03
- C言語・C++・C# c言語 プログラムのエラー 1 2023/02/11 20:31
- C言語・C++・C# pythonのファイルの並びでの読み込みとリストについて 4 2022/04/13 03:52
- C言語・C++・C# C言語の課題が出たのですが自力でやっても分かりませんでした。 要素数がnであるint型の配列v2の並 3 2022/11/19 17:41
関連するカテゴリからQ&Aを探す
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
関数から配列を返すには?
-
C言語において、 配列要素をひ...
-
構造体のextern方法
-
C言語についてです 5人のテスト...
-
define で 配列
-
c言語 構造体
-
C#で構造体の配列を持った構造...
-
配列の要素数に変数を入れたい...
-
char型配列をint型に代入するには
-
fclose()でセグメンテーション違反
-
const で宣言してるのに、値が...
-
MFC - ダイアログボックスのPic...
-
DxlibのLoadgraph()を使ったsta...
-
コンボボックスでデフォルト値...
-
C言語 構造体でつまずいています
-
C言語から質問です。
-
C言語入門者です。アドレス演算...
-
C#で配列が空かを判定するには?
-
c言語
-
C言語の課題丸投げ
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
おすすめ情報