C言語でとある計算プログラムを作成しました。

mainの中でFileAを読込み、1行づつ同じ計算をFileAの最終行まで演算し、出力しています。
同じ計算をしている部分はmain関数の外で作っており、mainの中で呼び出しています。

出来上がったKeisan.cというファイルを、gccでコンパイルして、Keisan.exeというものにして、「./Keisan.exe FileA > ResultA.txt」といったコマンドで利用しています。

改修を進めていくうちにとても長いプログラムになってしまったので、main関数の外で繰り返し呼び出している部分を別のファイルにして呼び出せないものかと悩んでいます。
「Keisan.exe」から「KeisanhojoA.c(もしくは.exe?)」を呼び出して同じ計算結果としたいのですが、どうすればいいのかさっぱりです。

こういうことを解説しているwebサイト、または書籍をご存知でしたらご教示いただきたく。
今やっている処理を正式になんと言うか、また今回やりたいことはなんと呼ばれているものなのか分からないために、分かりにくい質問になってしまいましたが、よろしくお願いいたします。

このQ&Aに関連する最新のQ&A

A 回答 (3件)

C言語は関数に分割することで別ファイルに分けることが出来ます。



1.たくさんの関数にmainを分割する。まず1つのソースファイルに複数の関数を入れる。
http://www.f-kmr.com/clang/clang-2.htm
http://www.geocities.co.jp/SiliconValley-Cuperti …
http://daimaru.sakura.ne.jp/c_room7.html

2.それでも関数が多すぎたら、機能単位に別のファイルに分割する。
http://www-ise3.ise.eng.osaka-u.ac.jp/miura/prog …
http://www.geocities.jp/ky_webid/c/032.html

この回答への補足

たくさんのリンクありがとうございます!

とても参考になります。

補足日時:2009/05/22 19:14
    • good
    • 0
この回答へのお礼

色々なサイトを教えていただき、ありがとうございます。

今回以外のことにも利用できるサイトで大変たすかりました。

ありがとうございました!

お礼日時:2009/05/26 20:44

ファイルを分割したいということですね


コンパイル時には呼び出す関数の戻り値と引数の型だけわかっていれば関数の実体はなくても出来ます
リンク時に関数の実体をリンクできればいいです
/* Keisan.c */
int Keisanhojo(int);
int main(int argc, char**argv)
{
int a, b = 0;
a = Keisanhojo( b );
return 0;
}
-------------------
/* KeisanhojoA.c */
int Keisanhojo(int var)
{
return var * 2;
}

$ gcc -o Keisan Keisan.c KeisanhojoA.c

この回答への補足

実例付きでありがとうございます。

$ gcc -o Keisan Keisan.c KeisanhojoA.c
このコンパイルで「Keisan.c」と「KeisanhojoA.c」の2つが合わさって「Keisan」というファイルになるわけですね?

ということは3つのファイルを統合したい場合、以下のようでいいでしょうか?
$ gcc -o Tougou.exe Keisan.c KeisanhojoA.c KeisanhojoB.c

補足日時:2009/05/22 19:10
    • good
    • 0
この回答へのお礼

実例付きのお陰で、分割できました。

3つ以上に分けた場合も、並べて指定することで可能でした。

ありがとうございました!

お礼日時:2009/05/26 20:43

現在は、Keisan.cという1個のファイルに、


main関数や他の関数を書かれているのですか?

何という関数があって、各関数はどういう機能を持っているかを
教えていただけますか?

この回答への補足

そうです。main関数と一緒に他の自作関数を書いています。

mainの中では、FileA(1秒毎の数値)の読込み、自作関数の呼び出し、戻り値の整理をしています。
自作関数Aで、各秒時毎数値の判定計算をしてmainに0、1を返しています。

あまり詳しいことが言えなくて申し訳ないです。

補足日時:2009/05/22 19:16
    • good
    • 0
この回答へのお礼

詳しいことを書けずに申し訳なかったです。

会社のPCを見ないとよく覚えていないというのが一番の問題なのですが・・・

せめて自分のプログラムくらい覚えているように努力します。

ありがとうございました!

お礼日時:2009/05/26 20:46

このQ&Aに関連する人気のQ&A

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

Qファイル出力の場所を指定

現在C++にてhtmlファイルを出力するプログラムを作っているのですが、出力場所を指定することはできるのでしょうか?(現在はそのプログラムソースが保存されている場所と同じファイル内に出力されますが、それをデスクトップに出力するなど。)
もし、方法がありましたら、教えてください。
ソースや参考HPのURLなどのせていただけたらありがたいです。
環境はVisualStudio.NET2003です。
よろしくお願いします。

Aベストアンサー

単にファイル名の前にパスを指定する。

絶対パス指定
fp=fopen("c:/temp/test.txt","w");

相対パス指定
fp=fopen("./hoge/test.txt","w");


デスクトップはOSやユーザによって場所が異なるので、少し面倒です。
XPの場合環境変数を利用してこんな感じで出来ると思います。

例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void main(void)
{
FILE *fp;
char fname[1024];
strcpy(fname,getenv("USERPROFILE"));
strcat(fname,"/デスクトップ/test.txt");
fp=fopen(fname,"w");
//処理
fclose(fp);
}

Qsleep()関数について

"数秒おきに警報をn回鳴らすプログラム"をC言語で作成しようと
考えています。

プログラム実行環境はWindowsですが、
sleep()関数は使用できないのでしょうか??

仮に使用できない場合、この関数に代わる関数や代替方法が
あれば教えて頂けませんでしょうか? 宜しくお願いします。

Aベストアンサー

正確な動作でも構わなければ
windows.hをインクルードして
Sleep()関数を使いましょう.
http://rararahp.cool.ne.jp/cgi-bin/lng/vc/vclng.cgi?print+200207/02070061.txt

しかし,正確に数秒おきに動作を行いたい場合はマルチメディアタイマ等を使いましょう.
マルチメディアタイマはミリ秒間隔でコールバック関数を呼び出すことができます.
timeSetEventを用いてコールバック関数の登録を行うことができます.
timeKillEventでコールバック関数の解除を行うことができます.

多分他にも方法があると思うのですが…私はこれぐらいしか知りません^^;

参考URL:http://www.katto.comm.waseda.ac.jp/~katto/Class/GazoTokuron/code/time.html

Q引数 戻り値 return文について

今、C言語を初めて勉強してます。

勉強していて、引数と戻り値、return文

についてよくわかりません。

どなたか詳しく素人にもわかるように教えて

頂けないでしょうか?よろしくお願いします。

Aベストアンサー

まず、関数とは何らかの処理をして結果を返してくれるものです。わざとらしい例ですが二つの数を足してその結果を返す関数を見てみましょう。

#include <stdio.h>

int add( int hoge, int piyo ){
return hoge + piyo;
}

int main(void){
int data;

data = add( 253, 434 );
printf( "%d", data );

return 0;
}

見てわかると思いますが、引数とは関数内の処理に使うデータです。
このデータは関数を呼び出すときに与えます。

add( 253, 434 )

すると与えられたデータは関数に渡され仮引数と言うものに格納されます。
この例では hoge に 253、piyo に 434 が格納されます。

int add( int hoge, int piyo ){

この仮引数は普通の変数のように使うことが可能なのです。

hoge + piyo

そしてこの結果を戻り値として return 文で返してやります。

return hoge + piyo;

返すとは具体的にどこへ返すのかと言うと呼び出したところへです。
ここでは main 関数内の呼び出し元です。

data = add( 253, 434 );

data と言う変数へは関数によって返された戻り値(関数値とか返却値とかとも言ったりします)が格納されます。つまり 253 と 434 を足した数です。

引数も戻り値も結局はデータです。処理させたいデータが引数で、処理した結果であるデータが戻り値です。

return は呼び出し元へ結果を返すためのものです。


C言語の関数にはいろいろな種類があります。

引数も戻り値もあるもの。

int add( int hoge, int piyo ){
return hoge + piyo;
}

引数はあるが戻り値のないもの。

void add( int hoge, int piyo ){
printf( "%d", hoge + piyo );
}

戻り値はあるが引数のないもの。

#include <stdlib.h>
#include <time.h>

int getRandNum(void){
srand( time( NULL ) );
return rand() % 500;
}

戻り値も引数もないもの。

void print(void){
printf( "%d + %d = %d", 253, 434, 253 + 434 );
}

これらの使い分けはデータの内容や型、処理の内容により適宜必要なものを使ってください。

まず、関数とは何らかの処理をして結果を返してくれるものです。わざとらしい例ですが二つの数を足してその結果を返す関数を見てみましょう。

#include <stdio.h>

int add( int hoge, int piyo ){
return hoge + piyo;
}

int main(void){
int data;

data = add( 253, 434 );
printf( "%d", data );

return 0;
}

見てわかると思いますが、引数とは関数内の処理に使うデータです。
このデータは関数を呼び出すときに与えます。

add( 253, 434 )

すると与...続きを読む

Q改行までの一文字ずつのファイル読み込み

こんにちは。
C言語で現在ある入力ファイルを読み込んで計算し、
ファイルを出力するというプログラムを作成中なのですが、
ファイルを読み込む場合に、
改行までの値を一文字ずつ読み込むという作業をさせたいと思っています。
データは、
abc

defgh

ijk

.....

といった感じで入力されており、

while((c = fgetc(fp)) != '\n'){
fscanf(fp, "%c", &q[i]);
}

と書いたのですが、セグメント例外が出て強制終了してしまいます。
初歩的なことで申し訳ないのですが、教えていただきたいと思います。よろしくおねがいします。

Aベストアンサー

(1)fgetc() の時点でもう既に1文字データを読んでいるので、
fscanf() で'再度取得'することはできません。
q[i] には c の値をそのまま代入してください。

(2)i はインクリメントしなくてよいのでしょうか?

(3)行の終端 '\n' を検出して while を抜けた後、
printf 文などでそのまま表示させていませんか?
文字列 q[] の終端にヌル文字を入れる必要があります。
(q[]が予めゼロクリアされているのなら入れる必要はありません)

(4)それと、feof() でファイル終端をチェックしながらやった方がいいです。

オーバーフローを起こさない為に q[] には大きめの配列を確保してください。

char q[1024];
int i = 0, c;

while( !feof( fp ) )
{
  if( ( c = fgetc( fp ) ) == '\n' )
    break;
  q[i++] = c;
}
q[i++] = '0';

みたいな感じ。

(1)fgetc() の時点でもう既に1文字データを読んでいるので、
fscanf() で'再度取得'することはできません。
q[i] には c の値をそのまま代入してください。

(2)i はインクリメントしなくてよいのでしょうか?

(3)行の終端 '\n' を検出して while を抜けた後、
printf 文などでそのまま表示させていませんか?
文字列 q[] の終端にヌル文字を入れる必要があります。
(q[]が予めゼロクリアされているのなら入れる必要はありません)

(4)それと、feof() でファイル終端をチェックしながらやった方が...続きを読む

QC言語 ファイルの指定された行を表示

こんにちは。
回答お願いします。
今私は作業の高効率化を目指すためプログラムを考えています。
まだぜんぜんできていませんが・・
ファイルの指定された行を表示する関数がないだろうか?
もしくは似たような方法はないだろうかと考えています。

できれば例題とともに教えていただければ幸いです。
具体的にどういう風にしたいのかというと
----test.txt-------
aaaa
bbbbb
cccccc
dddd
eeeeeeee
ffffff
-------------------
というファイルがあったとしたらgetsで4と入れてやったら
四行目のddddが表示されるようにしたいのです。
まだまだ初心者ですのでさっと考えることができません。
どうかご教授お願いします。

Aベストアンサー

★高効率を目指しているの?
・固定長データなら高効率で1行を取得できたりします。
 例えば
 ----test.txt-------
 aaaaa
 bbbbb
 ccccc
 ddddd
 eeeee
 fffff
 -------------------
 という固定長データ(5文字×6行)の場合は
 int no = 4; ←4行目を取得したい時
 fseek( fp, ((no - 1) * 7), SEEK_SET ); ←5文字+\r+\n=『7』
 fgets( buff, sizeof(buff), fp );
 ↑
 これなら行番号で指定した1行を fgets() 関数で取得可能です。
 ※なおバイナリモードでオープンして下さい。
・可変長データの場合は行の先頭のオフセット位置を最初の読み込みで管理します。
 例えば
 ----test.txt-------
 aaaa
 bbbbb
 cccccc
 dddd
 eeeeeeee
 ffffff
 -------------------
 という可変長データ(4,5,6,4,8,6文字)の場合は
 オフセット位置の配列を行数分用意します。→事前に分かれば楽ですね。行数。
 long offset[ 100 ]; ←100行だと仮定
 int max;
 
 for ( max = 0 ; !feof(fp) ; max++ ){
  if ( max >= 100 ){ ←安全対策
   break;
  }
  offset[ max ] = ftell( fp );
  fgets( buff, sizeof(buff), fp );
 }
 ↑
 ここまでがオフセット位置の読み込みです。次は読み出しです。
 int no = 4; ←4行目を取得したい時
 fseek( fp, offset[no - 1], SEEK_SET );
 fgets( buff, sizeof(buff), fp );
 ↑
 これで行番号で指定した1行を fgets() 関数で取得可能です。
 ※やっぱりバイナリモードでオープンして下さい。
・あと行数の指定時に 1~max の範囲になるように補正処理も入れたほうが良いかも。
 例えば
 if ( no < 1 ){
  no = 1;
 }
 else if ( no >= max ){
  no = max;
 }
 ↑
 こんな感じで。
・以上を参考にして下さい。
 下の『参考URL』もどうぞ。

参考URL:http://www9.plala.or.jp/sgwr-t/lib/fseek.html

★高効率を目指しているの?
・固定長データなら高効率で1行を取得できたりします。
 例えば
 ----test.txt-------
 aaaaa
 bbbbb
 ccccc
 ddddd
 eeeee
 fffff
 -------------------
 という固定長データ(5文字×6行)の場合は
 int no = 4; ←4行目を取得したい時
 fseek( fp, ((no - 1) * 7), SEEK_SET ); ←5文字+\r+\n=『7』
 fgets( buff, sizeof(buff), fp );
 ↑
 これなら行番号で指定した1行を fgets() 関数で取得可能です。
 ※なおバイナリモードでオープンして下さ...続きを読む

Qセグメンテーション違反

C言語を使用しています。

構造体に値をいれようとしたら、コンパイルは出来るのですが、実行時に
「セグメンテーション違反です (core dumped)」
となってしまい、それ以上行えません。

構造体と代入したい変数との型は、合っています。

いろいろ本などで見ましたが、何が原因かわからず困っています。
教えてください。
宜しくお願いします。

Aベストアンサー

OSは何でしょうか。コンパイラは何を使用していますか?
通常、デバッグオプションをつけて実行すると、異常の発生したソースの箇所で止まりますので、それが手がかりになります。またNo1の方が言われてますように、ソースが公開できるのであれば、ソースを提示するのが良いかと思います。

Q構造体の初期化のmemsetの第三引数

memset(&lvitem, 0, sizeof(LVITEM));
memset(&lvitem, 0, sizeof(lvitem));
LVITEMに特化した質問ではなく構造体の初期化について、この2つの書き方によるソース管理やコンパイルでのメリットとデメリットを教えてください。

Aベストアンサー

(1)memset(&lvitem, 0, sizeof(LVITEM));
この書き方は、構造体LVITEMを初期化しているんだな、と分かりやすい。
(2)memset(&lvitem, 0, sizeof(lvitem));
この書き方はとにかく変数lvitemを初期化するんだな、という感じだが、型が分からないので宣言しているところを参照しなければならない。
それともう一つ、ただ単に何回も初期化するんでなければ、こういう書き方もできる。
(3)LVITEM lvitem = {0};

結局どれがいいのかといえば、個人的にはケースバイケースですねえ。初期化を1回すればいいような感じなら(3)、構造体名を明示した方が調べる手間がなくなるようなら(1)、そうでなければ(2)を使います。
コンパイルでのメリット、デメリットは特にないんじゃないかなあ。アセンブラがまだ全盛だった頃ならともかく、いまじゃどのコンパイラだって最適化オプションで同じようなコードはくでしょう。
気にするほどでもないと思うけど…

Qint型からchar型への変換

タイトル通り、int型からchar型への変換の仕方がわかりません!><
どうしたらいいのでしょうか?

Aベストアンサー

#include <stdio.h>


char buf[5];
int no;

no = 10;
sprintf(buf, "%d", no);

Q間接参照のレベルが異なっています

単語を昇順でソートするプログラミングでエラーが出て困っている者です。
エラーが出てる箇所のみ抜粋して、あとは省略したものが下記です。
下記の2つの関数の下の方の関数で

間接参照のレベルが'char **'と'char[10][20]'で異なっています

read_wordsの型が2の仮引数および実引数と異なります

と言うエラーが現れます。main関数内のsortword関数、display_words関数でも同様にエラーが現れます。
これらの原因は何でしょう。また、僕は何がわかってないですか?
ここどこを勉強しろ、等のアドバイスでも結構ですのでぜひご指導ください。お願いします。


#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define LINE_SIZE 20
#define MAX_LINES 10


char line[MAX_LINES][LINE_SIZE];


int num;
int read_words(char *fname,char **line,int num)//用意した構造に文字列を格納
{
FILE *fp;//ファイルポインタの宣言

int i = 0;//繰り返し変数の初期化

if((fp = fopen(fname,"r")) == NULL)//ファイルがあるかの確認
{
printf("ファイルを開けません\n");//ファイルが無い時はエラーメッセージを出す
exit(1);//エラー時は強制終了
}

fp=fopen(fname,"r");
fscan(fp,"%d",&line);
for(i=0;i<MAX_LINES;i++)//1列ずつ文字列を入れる制御構造
{
fscanf(fp,"%s",&line[i]);//ファイルから文字列を変数に入力
i++;//繰り返し変数の増加
}
num=line[0];//単語数を戻り値とする
fclose(fp);//ファイルのクローズ
}




int main(int argc,char *argv[])
{
read_words(argv[1],line,int num);
sortword(line,num);
display_words(line,num);
}

単語を昇順でソートするプログラミングでエラーが出て困っている者です。
エラーが出てる箇所のみ抜粋して、あとは省略したものが下記です。
下記の2つの関数の下の方の関数で

間接参照のレベルが'char **'と'char[10][20]'で異なっています

read_wordsの型が2の仮引数および実引数と異なります

と言うエラーが現れます。main関数内のsortword関数、display_words関数でも同様にエラーが現れます。
これらの原因は何でしょう。また、僕は何がわかってないですか?
ここどこを勉強しろ、等のアドバ...続きを読む

Aベストアンサー

開発環境が書かれていませんが、書いた方が回答者が回答しやすいと思います。

> int read_words(char *fname,char **line,int num)
この関数の第2引数はchar **型なのに、

> char line[MAX_LINES][LINE_SIZE];
> read_words(argv[1],line,int num);
呼び出すときの型が char[MAX_LINES][LINE_SIZE]型になってしまっています。

関数の引数を以下のどれかに変更すればとりあえずそのエラーは出なくなると思います。
int read_words(char *fname,char line[MAX_LINES][LINE_SIZE] ,int num)
int read_words(char *fname,char line[][LINE_SIZE] ,int num)
int read_words(char *fname,char *line[LINE_SIZE] ,int num)

なお、このことに関する詳しいことは下記のページを見てください。
http://www.st.rim.or.jp/~phinloda/cqa/cqa17.html


あと気になったところとして、
> char line[MAX_LINES][LINE_SIZE];
グローバル変数にする必要がないので、main関数内で宣言した方がよい。

> fscan(fp,"%d",&line);
・fscanになっている。
・%dなのに&lineが整数型でない。(&lineはchar *型)
・仮に%sの間違いの場合、
&lineは間違いではないけど、意味的にline[0]にした方が分かりやすそう。
(後ろでline[0]で使ってますし。)

> fscanf(fp,"%s",&line[i]);//ファイルから文字列を変数に入力
・lineがchar **型でもchar[MAX_LINES][LINE_SIZE]型でも
&line[i]の型はchar型になる。
ここに要求されるのはchar *型なのでline[i]とするべき。

> num=line[0];//単語数を戻り値とする
・戻り値と書いてあるのにreturnで返していない。(コメントが嘘)
ここはグローバル変数numを作らなくてもコメント通りreturnで返せばよいと思いますよ。
そうすればnumをグローバル変数にする必要もなくなります。
・int型のnumにchar *型のline[0]を代入するのは変。(ポインタが代入されるけどそれでいいの?)

> read_words(argv[1],line,int num);
・int numはおかしい(intはいらない)。


> また、僕は何がわかってないですか?
あえて言えば、ポインタ・配列が絡んだ"型"がよく分かっていないなという感じがしました。

開発環境が書かれていませんが、書いた方が回答者が回答しやすいと思います。

> int read_words(char *fname,char **line,int num)
この関数の第2引数はchar **型なのに、

> char line[MAX_LINES][LINE_SIZE];
> read_words(argv[1],line,int num);
呼び出すときの型が char[MAX_LINES][LINE_SIZE]型になってしまっています。

関数の引数を以下のどれかに変更すればとりあえずそのエラーは出なくなると思います。
int read_words(char *fname,char line[MAX_LINES][LINE_SIZE] ,int num)
int read...続きを読む

Q構造体の初期化方法について

こんばんわ。
何度も申し訳ありません。

VC++.NET 2003を用いてコンソールプログラミングを行っています。前回この掲示板を利用して複数回実行するプログラムを作成し、そこに構造体を用いたプログラムを作成しました。以下に概要を示します。

グローバルで構造体を宣言しているため、複数回実行を行うプログラムでは前回の値が格納されたままであると思い、毎回実行時に構造体の初期化を行いたいと思っています。

そこで、以下に示します構造体の初期化はどのように記述すればよいのでしょうか?0で初期化したいと思っています。

よろしくお願い致します。

#define MAX 2000
//グローバル
struct tag{
int Npkt;
int gettime;
int rPkt;
int lossPkt;
}rdata[MAX];

main(){
  //for文で複数回実行処理
  for(i=0;i<=5;i++){
  //ここで構造体の初期化を記述する
//例として、5回プログラムを実行する
  }
}

こんばんわ。
何度も申し訳ありません。

VC++.NET 2003を用いてコンソールプログラミングを行っています。前回この掲示板を利用して複数回実行するプログラムを作成し、そこに構造体を用いたプログラムを作成しました。以下に概要を示します。

グローバルで構造体を宣言しているため、複数回実行を行うプログラムでは前回の値が格納されたままであると思い、毎回実行時に構造体の初期化を行いたいと思っています。

そこで、以下に示します構造体の初期化はどのように記述すればよいのでしょうか?0で初...続きを読む

Aベストアンサー

★まとめ
・既に『memset』関数や、『ZeroMemory』関数の回答があるので構造体の全体、1部の
 初期化の記述例を紹介します。
・それと『#include <memory.h>』を記述しないとメモリ関係の関数が利用できません。
 『ZeroMemory』関数の場合は『#include <windows.h>』があればそのまま利用できます。

●構造体全体を初期化
ZeroMemory( rdata, sizeof(rdata) ); または、
memset( rdata, 0, sizeof(rdata) ); です。

●構造体一部を初期化
ZeroMemory( &rdata[i], sizeof(struct tag) ); または、
memset( &rdata[i], 0, sizeof(struct tag) ); です。
※rdata[i]の1データだけ初期化します。

余談:
・『ZeroMemory』関数は Win32 API と分類されていますが、実体は『memset』関数に
 『#define』されているだけです。でも、戻り値を『VOID』型にキャストされているので
 『memset』関数のリターン値を取得できません。→第一引数のアドレスが『memset』関数
 ではリターンします。
・以上。おわり。

参考URL:http://taka.no32.tk/tips/Win32/ZeroMemory.html

★まとめ
・既に『memset』関数や、『ZeroMemory』関数の回答があるので構造体の全体、1部の
 初期化の記述例を紹介します。
・それと『#include <memory.h>』を記述しないとメモリ関係の関数が利用できません。
 『ZeroMemory』関数の場合は『#include <windows.h>』があればそのまま利用できます。

●構造体全体を初期化
ZeroMemory( rdata, sizeof(rdata) ); または、
memset( rdata, 0, sizeof(rdata) ); です。

●構造体一部を初期化
ZeroMemory( &rdata[i], sizeof(struct tag) ); または、
m...続きを読む


このQ&Aを見た人がよく見るQ&A

人気Q&Aランキング

おすすめ情報