テキストファイルの同じ行どおしの足し算

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
アナログー

テキストファイルの同じ行どおしの足し算

#1

投稿記事 by アナログー » 9年前

皆様、はじめまして

シミュレーション結果をまとめるために複数のテキストファイルの同じ行のすべての数字を足し算する必要になりました。ファイル数が少なければexcelを使うのが簡単なのですが、実験結果のファイル数は100個以上あり、1つ1つをexcelに張り付けるには非常に手間がかかるのでC言語のプログラムをつくることにしました。
しかしプログラム初心者の私にはとても困難で、いろいろなサイトや文献を見ながら作った下記のプログラムはコンパイルすることもできません。おそらくこの掲示板の方々から見てもなにがやりたいのかわからないプログラムになっているかとおもいます。

コンパイル時のメッセージは
plus.c: 関数 `main' 内:
plus.c:26: error: invalid operands to binary +
で、OSはLinuxそしてコンパイラはgccを使用しています。

どうかアドバイスをお願い致します。
ちなみに下記のプログラムは試作で読み込むファイルは2つにしており、テキストファイルは
0.000458178716724
0.000602568058547
0.000017878041971
0.000365531605123
0.000634661729389
0.000637913861752
0.000466100732644
0.000251665389012
0.000086174078951
0.000007442193411
0.000012706840213



このような感じに1行に1つ数値が入っており、これが999行目まで続いてます。

コード:

#include<stdio.h>
typedef struct{
  char suti1[1000];
  char suti2[1000];
} jikken;

main(){
  FILE *f1, *f2, *fk;
  int i=0,n;
  char buf[256];
  jikken simu1[1000];
  jikken simu2[1000];
  f1=fopen("1.txt", "r");
  f2=fopen("2.txt", "r");
  fk=fopen("kekka.txt", "r");
  while((fgets(buf,15000,f1))!=NULL){
    sscanf(buf,"%2.15lf\n",&simu1[i].suti1);
    i++;
  }
  while((fgets(buf,15000,f2))!=NULL){
    sscanf(buf,"%2.15lf\n",&simu2[i].suti2);
    i++;
  }
  n=i;
  for(i=0;i<n;i++){
    fprintf(fk,"%2.15lf\n",simu1[i].suti1+simu1[i].suti2);
  }
  fclose(f1);
  fclose(f2);
  fclose(fk);
}

アバター
bitter_fox
記事: 607
登録日時: 9年前
住所: 大阪府

Re: テキストファイルの同じ行どおしの足し算

#2

投稿記事 by bitter_fox » 9年前

アナログー さんが書きました:

コード:

typedef struct{
  char suti1[1000];
  char suti2[1000];
} jikken;

main(){
  char buf[256];
  fk=fopen("kekka.txt", "r");
  while((fgets(buf,15000,f1))!=NULL){
    sscanf(buf,"%2.15lf\n",&simu1[i].suti1);
    i++;
  }
  while((fgets(buf,15000,f2))!=NULL){
    sscanf(buf,"%2.15lf\n",&simu2[i].suti2);
    i++;
  }
  n=i;
  for(i=0;i<n;i++){
    fprintf(fk,"%2.15lf\n",simu1[i].suti1+simu1[i].suti2);
  }
}

コード:

fk=fopen("kekka.txt", "r");
おそらくkekka.txtは出力ファイルでしょうが、"r"で開くと読み取り専用で書き出せません。

まず、
char buf[256]としているにもかかわらず、
fgets(buf, 15000, _)として最大15000文字まで取得するのはバッファオーバーフロの危険性があります。
またこれらの処理は、

コード:

while (fscanf(fp, "%lf", &simu1[i].suti1) != EOF)
{
	while (getchar() != '\n');
	i++;
}
でできます。

また、二つ目のファイルの読み取りでは、iの値は一つ目のファイルから読み込んだ値の数になったままです。
ちゃんと、初期化をしましょう。

あと、jikkenのメンバは一つで大丈夫ですし、メンバsuti1などは文字列になってます。
ここは、読み取るのは実数なので、double型などでないと正常に動作しません。

[hr][追記]
わざわざ、配列に値を保存してから足すのではなく、
両方のファイルの各行ごとの値を取得して、逐次足した値を出力する方がいいかもしれません。

アナログー

Re: テキストファイルの同じ行どおしの足し算

#3

投稿記事 by アナログー » 9年前

bitter_foxさん
返信ありがとうございます。
右も左もわからない私にとってありがたい助言でした。

bitter_foxさんのおっしゃている
『両方のファイルの各行ごとの値を取得して逐次足した値を出力する』
とは具体的にどのようにかえればよろしいのでしょうか?
未熟者ですみません。

maru
記事: 150
登録日時: 9年前

Re: テキストファイルの同じ行どおしの足し算

#4

投稿記事 by maru » 9年前

複数のファイルの同じ行を演算したいのですよね。
以下のプログラムではどうでしょうか。
C++ですがgccでコンパイルできますよね。

入力ファイルのフォーマット(ファイルの名前、位置は実際に存在するものにしてください。)

コード:

data1.txt
data2.txt
data3.txt
...以下、対象のファイルをいくつでも
上記の形式で全てのファイルをテキスト化しておき、file.lstと言う名称で保存し、プログラムを実行すればoutput.txtが作成されると思います。
windows環境で確認していますが、多分Linuxでも問題はないと思います。
コードを適切にいじれば、入出力ファイル名やファイル間の演算を変更することもできるでしょう。

コード:

#include <stdio.h>
#include <tchar.h>

#include <fstream>
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

const size_t	max_line_of_data = 999;	// 最大データ数

/*
 *1ファイルを配列に読み込む
 *
 *復帰値:true:読み込み成功
 */
bool	read_file_data
	(	const char* const file_name	// 対象のファイル名
	,	double *p_data				// データを読み込む配列の先頭ポインタ
	,	size_t max_number			// 最大格納サイズ(配列の大きさ)
	)
{
	bool	result(false);	// 結果を偽で初期化
	ifstream	data_file(file_name);	// 入力ファイルをストリームで読み込み
	if (data_file.fail())		// ファイルを正しく開けなかったか?
	{
		cout << "File name:" << file_name << " can not open!" << endl;
	} else
	{
		while (!data_file.eof() && max_number > 0)
		{
			data_file >> *p_data;	// データを読み込み、配列に書き込み
			++p_data;		// 書き込みポインタを更新
			--max_number;	// サイズを現象
		}
		result = true;	// 結果を真にする(読み込み成功)
	}
	return result;
}

int main()
{
	vector<double>	sum(max_line_of_data, 0.0);	// 必要な数の演算結果を保持する配列、0.0で初期化

	string	list_file_name("file.lst");		// 演算対象のファイルリスト
	ifstream	file_list(list_file_name);		// 入力ファイルリストストリーム
	if (file_list.fail())  // ファイルを開くことができなかったか?
	{	// ファイルを開くことができない!エラーメッセージ出力
		cout << "File name:" << list_file_name.c_str() << " can not open!" << endl;
	} else
	{	// ファイルを読み出して演算を実行
		while (!file_list.eof())	// ファイルリストが終わりになるまで
		{
			char	file_name[_MAX_FNAME];		// データファイル名
			file_list.getline(file_name, _MAX_FNAME);	// データファイル名を取り出す
			vector<double>	buffer(max_line_of_data);	// ファイルのデータを読み込むバッファ
			// 関数を使ってファイルの内容を一気にバッファに読み出す
			if (read_file_data(file_name, &buffer[0], max_line_of_data))
			{
				for (size_t i = 0; i < max_line_of_data; ++i)
				{	// バッファのデータを順次加算
					sum[i] += buffer[i];
				}
			}
		}
	}
	string	output_file_name("output.txt");	// 出力ファイル名
	ofstream	output_file(output_file_name);	// 出力ファイルストリーム

	// sumの内容を順次ファイルに書き出し(反復子を使用)
	for (vector<double>::const_iterator	i = sum.begin(); i != sum.end(); ++i)
	{
		output_file << *i << endl;
	}
	return 0;
}

アナログー

Re: テキストファイルの同じ行どおしの足し算

#5

投稿記事 by アナログー » 9年前

maruさん
アドバイスありがとうございます。

さっそくそのプログラム(ファイル名:plus.cpp)をつくり、gccでコンパイルしたところ
plus.cpp:2:19: tchar.h: そのようなファイルやディレクトリはありません
plus.cpp: function 内の `int main()':
plus.cpp:47: error: no matching function for call to `std::basic_ifstream<char,
std::char_traits<char> >::basic_ifstream(std::string&)'
/usr/include/c++/3.3/iosfwd:89: error: candidates are:
std::basic_ifstream<char, std::char_traits<char> >::basic_ifstream(const
std::basic_ifstream<char, std::char_traits<char> >&)
/usr/include/c++/3.3/fstream:519: error:
std::basic_ifstream<_CharT, _Traits>::basic_ifstream(const char*,
std::_Ios_Openmode) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/include/c++/3.3/fstream:504: error:
std::basic_ifstream<_CharT, _Traits>::basic_ifstream() [with _CharT = char,
_Traits = std::char_traits<char>]
plus.cpp:55: error: `_MAX_FNAME' undeclared (first use this function)
plus.cpp:55: error: (Each undeclared identifier is reported only once for each
function it appears in.)
plus.cpp:56: error: `file_name' undeclared (first use this function)
plus.cpp:69: error: no matching function for call to `std::basic_ofstream<char,
std::char_traits<char> >::basic_ofstream(std::string&)'
/usr/include/c++/3.3/iosfwd:92: error: candidates are:
std::basic_ofstream<char, std::char_traits<char> >::basic_ofstream(const
std::basic_ofstream<char, std::char_traits<char> >&)
/usr/include/c++/3.3/fstream:644: error:
std::basic_ofstream<_CharT, _Traits>::basic_ofstream(const char*,
std::_Ios_Openmode) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/include/c++/3.3/fstream:627: error:
std::basic_ofstream<_CharT, _Traits>::basic_ofstream() [with _CharT = char,
_Traits = std::char_traits<char>]
と表示されました。
私の利用しているLinuxは非常に古いのでそれが原因なのでしょうか?

またmaruさんのおっしゃる
『全てのファイルをテキスト化しておき、file.lstと言う名称で保存』というのはdata1.txtの999行目の次の行にdata2.txtの1行目を入力されたテキストを保存するということなのでしょうか?
何も知識がなくて本当に申し訳なく思います。

maru
記事: 150
登録日時: 9年前

Re: テキストファイルの同じ行どおしの足し算

#6

投稿記事 by maru » 9年前

アナログー さんが書きました:plus.cpp:2:19: tchar.h: そのようなファイルやディレクトリはありません
Windows用のヘッダファイルを指定してしまいました。
<ctype>か<ctype.h>に変えてみてください。
アナログー さんが書きました:plus.cpp: function 内の `int main()':
アナログーさんの環境ではmain()で通るのでしたら、intを取ってきてください。
アナログー さんが書きました:plus.cpp:47: error: no matching function for call to `std::basic_ifstream<char,
std::char_traits<char> >::basic_ifstream(std::string&)'
/usr/include/c++/3.3/iosfwd:89: error: candidates are:
std::basic_ifstream<char, std::char_traits<char> >::basic_ifstream(const
std::basic_ifstream<char, std::char_traits<char> >&)
/usr/include/c++/3.3/fstream:519: error:
std::basic_ifstream<_CharT, _Traits>::basic_ifstream(const char*,
std::_Ios_Openmode) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/include/c++/3.3/fstream:504: error:
std::basic_ifstream<_CharT, _Traits>::basic_ifstream() [with _CharT = char,
_Traits = std::char_traits<char>]
plus.cpp:55: error: `_MAX_FNAME' undeclared (first use this function)
plus.cpp:55: error: (Each undeclared identifier is reported only once for each
function it appears in.)
plus.cpp:56: error: `file_name' undeclared (first use this function)
plus.cpp:69: error: no matching function for call to `std::basic_ofstream<char,
std::char_traits<char> >::basic_ofstream(std::string&)'
/usr/include/c++/3.3/iosfwd:92: error: candidates are:
std::basic_ofstream<char, std::char_traits<char> >::basic_ofstream(const
std::basic_ofstream<char, std::char_traits<char> >&)
/usr/include/c++/3.3/fstream:644: error:
std::basic_ofstream<_CharT, _Traits>::basic_ofstream(const char*,
std::_Ios_Openmode) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/include/c++/3.3/fstream:627: error:
std::basic_ofstream<_CharT, _Traits>::basic_ofstream() [with _CharT = char,
_Traits = std::char_traits<char>]
これはよくわからないのですが、先頭の#include <tchar.h>が影響しているかもしれません。
ヘッダファイルを変えてもコンパイルが通らないようならば、ストリーム入出力をあきらめてファイルIOにする必要がありますね。
アナログー さんが書きました:『全てのファイルをテキスト化しておき、file.lstと言う名称で保存』というのはdata1.txtの999行目の次の行にdata2.txtの1行目を入力されたテキストを保存するということなのでしょうか?
いいえ、違います。「実験結果のファイル数は100個以上」とのことなので、そのファイル名を一覧にしておけばよいです。
そのファイルリストを読んで、そのリスト通りにファイルを読みだして足し算をして、最後にファイルに出力するプログラムです。
コンパイルが通ったら、最初は2つのファイル名だけを書いて結果を確認するようにすればよいでしょう。
[hr][追記]
ファイルリストを作成する際は、くれぐれも自分で入力しないこと!
ファイルリストの入力ミス探しで楽しい時間を送ることができます。
ファイルの一覧を表示するコマンド(ls?)を使用し、その出力をリダイレクトしてファイルにすることをお勧めします。

閉鎖

“C言語何でも質問掲示板” へ戻る