質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

ファイル

ファイルとは、文字列に基づいた名前又はパスからアクセスすることができる、任意の情報のブロック又は情報を格納するためのリソースです。

Q&A

2回答

1487閲覧

C言語 ソースファイルを分ける方法について

alice331

総合スコア11

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

ファイル

ファイルとは、文字列に基づいた名前又はパスからアクセスすることができる、任意の情報のブロック又は情報を格納するためのリソースです。

0グッド

1クリップ

投稿2021/09/05 15:20

以下の作成したソースファイルをヘッダファイル(test.h)とmain.c,swap_Data.c,bubble_sort.c,read_file.c,show_result.cというようにファイルを分割したいです。いろいろなサイトを参考に作成しましたが、なかなか実行できません。
恐らく変数や関数の宣言がちゃんと出来ていないことが原因かと思いますが、よくわかりません。
ご教授よろしくお願いいたします。
簡単でも構いませんので、分け方のソースを書いていただけるとありがたいです。

C言語

1#include <stdio.h> 2#include <stdlib.h> 3 4#define N 100 5 6typedef struct data { 7 char student_no[128]; 8 int score_japanese; 9 int score_math; 10 int score_science; 11 int score_society; 12 int score_sum; 13} Data; 14 15void swap_Data(Data *x, Data *y){ 16 Data tmp = *x; 17 *x = *y; 18 *y = tmp; 19} 20 21 22void bubble_sort(Data *df, int n) { 23 for (int i = 0; i < n-1; i++) { 24 for(int j = n-1; j > i; j--) { 25 if(df[j].score_sum - df[j-1].score_sum > 0) { 26 swap_Data(&df[j-1], &df[j]); 27 } 28 } 29 } 30} 31 32void read_file(char *filename, Data *df, int *n) { 33 FILE *fp; 34 int ret; 35 int cnt = 0; 36 37 fp = fopen(filename, "r" ); 38 if (fp == NULL) { 39 printf( "cannot open %s\n", filename); 40 exit(1); 41 } 42 43 while((ret = fscanf(fp, "%[^,],%d,%d,%d,%d ", 44 df[cnt].student_no, &df[cnt].score_japanese, &df[cnt].score_math, & 45 df[cnt].score_science, &df[cnt].score_society)) != EOF) { 46 47 df[cnt].score_sum = df[cnt].score_japanese + df[cnt].score_math 48 + df[cnt].score_science + df[cnt].score_society; 49 50 cnt++; 51 } 52 53 *n = cnt; 54} 55 56void show_result(Data *df, int n) { 57 int i; 58 59 printf("番号 国語 数学 理科 社会 合計\n"); 60 printf("----------------------------------\n"); 61 for (int i = 0; i < n; i++) { 62 printf("%s %5d%6d%6d%6d%6d\n", 63 df[i].student_no, df[i].score_japanese, df[i].score_math, 64 df[i].score_science, df[i].score_society, df[i].score_sum); 65 } 66} 67 68int main(void) { 69 int n; 70 Data score_data[N]; 71 72 read_file("test_result.txt", score_data, &n); 73 74 bubble_sort(score_data, n); 75 76 show_result(score_data, n); 77 78 return 0; 79}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hidezzz

2021/09/05 15:39

試行錯誤の過程で分割したソースコードはあったりしますか? そのソースコードをビルド(コンパイル)しようとした際に出るエラーメッセージ等を提示することはできますか?
guest

回答2

0

分割する手順:

  1. 物理的に複数のファイルに記述を切り分ける
  2. 各ファイルにコンパイルを通すために必要な記述を補う
  3. 纏めたいものをまとめるとかする

(例)とりあえず関数 bubble_sort の定義を別のファイルに分けることをやってみる.

まずは手順1
bubble_sort.c なるファイルに丸ごと関数の記述(定義)を持っていく

C

1// bubble_sort.c 2 3//bubble_sortの定義 4void bubble_sort(Data *df, int n) { 5 for (int i = 0; i < n-1; i++) { 6 for(int j = n-1; j > i; j--) { 7 if(df[j].score_sum - df[j-1].score_sum > 0) { 8 swap_Data(&df[j-1], &df[j]); 9 } 10 } 11 } 12}

この時点でコンパイルが通らないハズ.おそらくコンパイラは

bubble_sort.c に対して,
「 "Data" って何だよ? 意味わかんねぇ!」
「 "swap_Data" って何だよ? 意味わかんねぇ!」
と言い出すでしょう.

また,bubble_sort 関数の定義を失った大元のソース側に対しても,
「 "bubble_sort" って何だよ? 意味わかんねぇ!」
と言うことになるでしょう.

つまり「コンパイラに意味がわかるように」両ファイルに何かを書き添える必要があるわけです.
それが手順2です.

手順2
「何だよ?」って言われている物について,「何なのか」を書いてやる.

C

1// bubble_sort.c 2 3//Data とは何か? を書いてやる. 4typedef struct data { 5 /*略*/ 6} Data; 7 8//swap_Data とは何か? を書いてやる. 9//選択肢としては, 10// (1) 関数swap_Dataの実装コードを丸ごと元のソースからここに移動させてくる 11// (2) 関数swap_Dataのプロトタイプ宣言を書く 12//くらいが考えられるが, 13//この例では後者側とした. 14void swap_Data(Data *x, Data *y); 15 16//bubble_sortの定義 17void bubble_sort(Data *df, int n) { 18 /*略*/ 19}

C

1//大元のコードの側 .c 2 3#include <stdio.h> 4#include <stdlib.h> 5 6#define N 100 7 8typedef struct data { 9 /* 略 */ 10} Data; 11 12/* 略 */ 13 14//bubble_sort とは何か? を書いてやる. 15//関数 bubble_sort の定義は別のソースファイル(bubble_sort.c)にあるので, 16//bubble_sort のプロトタイプ宣言を書く. 17void bubble_sort(Data *df, int n); 18 19//main 20int main(void) { 21 /* 略 */ 22}

「何なのか?」を示してやったので,コンパイラも満足するだろう.
これでコンパイル(とリンク)が通れば成功だ.

手順3
2つのソースファイルに

C

1typedef struct data { 2 /* 略 */ 3} Data;

っていうのがあるのはどうなの? 纏めたいんですけど?
とか思うなら,纏める.
この部分をある1つのファイル(ここではファイル名を data.h とする)に記述し,
2つのソースファイルでは,この記述の代わりに #include "data.h" と書く.

C

1//data.h 2 3typedef struct data { 4 /* 略 */ 5} Data;

C

1// bubble_sort.c 2 3//Data とは何か? が書かれているファイルをincludeする 4#include "data.h" 5 6//swap_Data とは何か? を書いてやる. 7//選択肢としては, 8// (1) 関数swap_Dataの実装コードを丸ごと元のソースからここに移動させてくる 9// (2) 関数swap_Dataのプロトタイプ宣言を書く 10//くらいが考えられるが, 11//この例では後者側とした. 12void swap_Data(Data *x, Data *y); 13 14//bubble_sortの定義 15void bubble_sort(Data *df, int n) { 16 /*略*/ 17}

C

1//大元のコードの側 .c 2 3#include <stdio.h> 4#include <stdlib.h> 5 6#define N 100 7 8//Data とは何か? が書かれているファイルをincludeする 9#include "data.h" 10 11/* 略 */ 12 13//bubble_sort とは何か? を書いてやる. 14//関数 bubble_sort の定義は別のソースファイル(bubble_sort.c)にあるので, 15//bubble_sort のプロトタイプ宣言を書く. 16void bubble_sort(Data *df, int n); 17 18//main 19int main(void) { 20 /* 略 */ 21}

include とは単なるコピペ機能であり,
#include "data.h" とは,「これを書いた箇所に,コンパイル前にdata.hの内容を張り付けてくれや」というだけの話である.
(なので,例えば,「main関数の上に書いたbubble_sort のプロトタイプ宣言もどこかに移したいなあ」とか思うならば,
その記述を適当なファイルに移し,#include "そのファイルの名前" とすればよい.)

投稿2021/09/06 06:29

fana

総合スコア11996

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fana

2021/09/06 06:33

他の関数群も個別のソースに分けたいなら,同じようにやればいい. 「インクルードガード」については話的に必須ではないのでここでは述べない. 適宜調査されたい.
fana

2021/09/06 06:38

分割された結果だけだと「何でそういう形になったのか」がわからんかもしれないので,とっかかり的な話の部分を示した.
guest

0

こんな感じでしょうか。

h

1// test.h 2 3// 多重インクルード防止 4#ifndef TEST_H 5#define TEST_H 6 7// 型定義 8typedef struct data { 9 char student_no[128]; 10 int score_japanese; 11 int score_math; 12 int score_science; 13 int score_society; 14 int score_sum; 15} Data; 16 17// プロトタイプ宣言 18void swap_Data(Data *x, Data *y); 19void bubble_sort(Data *df, int n); 20void read_file(char *filename, Data *df, int *n); 21void show_result(Data *df, int n); 22 23#endif

c

1// swap_Data.c 2#include "test.h" 3 4void swap_Data(Data *x, Data *y){ 5 Data tmp = *x; 6 *x = *y; 7 *y = tmp; 8}

c

1// bubble_sort.c 2#include "test.h" 3 4void bubble_sort(Data *df, int n) { 5 for (int i = 0; i < n-1; i++) { 6 for(int j = n-1; j > i; j--) { 7 if(df[j].score_sum - df[j-1].score_sum > 0) { 8 swap_Data(&df[j-1], &df[j]); 9 } 10 } 11 } 12}

c

1// read_file.c 2#include <stdio.h> 3#include "test.h" 4 5void read_file(char *filename, Data *df, int *n) { 6 FILE *fp; 7 int ret; 8 int cnt = 0; 9 10 fp = fopen(filename, "r" ); 11 if (fp == NULL) { 12 printf( "cannot open %s\n", filename); 13 exit(1); 14 } 15 16 while((ret = fscanf(fp, "%[^,],%d,%d,%d,%d ", 17 df[cnt].student_no, &df[cnt].score_japanese, &df[cnt].score_math, & 18 df[cnt].score_science, &df[cnt].score_society)) != EOF) { 19 20 df[cnt].score_sum = df[cnt].score_japanese + df[cnt].score_math 21 + df[cnt].score_science + df[cnt].score_society; 22 23 cnt++; 24 } 25 26 *n = cnt; 27}

c

1// show_result.c 2#include "test.h" 3 4void show_result(Data *df, int n) { 5 int i; 6 7 printf("番号 国語 数学 理科 社会 合計\n"); 8 printf("----------------------------------\n"); 9 for (int i = 0; i < n; i++) { 10 printf("%s %5d%6d%6d%6d%6d\n", 11 df[i].student_no, df[i].score_japanese, df[i].score_math, 12 df[i].score_science, df[i].score_society, df[i].score_sum); 13 } 14}

c

1// main.c 2#include <stdio.h> 3#include "test.h" 4 5#define N 100 6 7int main(void) { 8 int n; 9 Data score_data[N]; 10 11 read_file("test_result.txt", score_data, &n); 12 13 bubble_sort(score_data, n); 14 15 show_result(score_data, n); 16 17 return 0; 18}

<参考>
■ C言語 ヘッダファイルの書き方
https://monozukuri-c.com/langc-headerfile/
■ 最小限の分割 - 苦しんで覚えるC言語
https://9cguide.appspot.com/20-01.html
■ インクルードガード
http://www.02.246.ne.jp/~torutk/cxx/file/includeguard.html

投稿2021/09/05 15:37

編集2021/09/06 03:53
cx20

総合スコア4648

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

cx20

2021/09/05 16:49

> 恐らく変数や関数の宣言がちゃんと出来ていないことが原因 「プロトタイプ宣言」について調べてみてください。
fana

2021/09/06 01:10 編集

> #define N 100 コレは main 関数内のローカルな配列のサイズを決めているだけと見えるので, test.h に書くべき物ではないでしょう. (あとは, stdio.h とか stdlib.h がどこで必要でどこでは不要か,というあたりに問題ありそうかな)
cx20

2021/09/06 03:10

> > #define N 100 > > コレは main 関数内のローカルな配列のサイズを決めているだけと見えるので, > test.h に書くべき物ではないでしょう. そうですね。main 関数でしか使用しないのであれば共通ヘッダに入れる必要はなさそうです。回答修正しておきました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問