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

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

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

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

Q&A

解決済

1回答

699閲覧

c言語 ファイル読み込み 1行ずつ 多次元配列

shumpei0902

総合スコア2

C

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

0グッド

0クリップ

投稿2023/02/02 13:42

編集2023/02/03 10:16

大学の課題でファイル読み込み、ある処理を行うプログラムを作成しています。
空白で区切られた1行8つの値を多次元配列を用いて4つずつ表示させようとしています。
表示した際、同じ値が表示されてしまう部分があるのですが、何が原因なのでしょうか。
4列目の値が5列目の値と同じになってしまいます。

読み込むファイル(in.dat)該当箇所のみ
数字が1万行ほど羅列されているので、大きすぎて最初のほうしか貼ることが出来ませんでしたが、このままでもプログラムは動くと思います。

4846 15677 0 0 1.000E+03 23 34 35 36 70 73 72 56 66 61 64 58 33 46 40 44 58 56 72 73 73 78 58 60 75 53 65 60 64 78 66 58 19 8 1283 20 25 18 17 19 78 64 66 62 68 46 75 60 76 61 60 75 19 20 1283 14 66 76 62 75 15 9 20 1283 15 4 9 1283 23 32 36 24 34 23 21 32 62 78 74 76 76 66 78 58 73 78 71 58 14 26 16 25 13 2 1 3 21 23 24 32 61 76 60 58 64 71 72 56 65 61 75 60 26 16 25 27 39 50 49 37 17 19 1283 14 8 18 6 7 56 64 71 57 13 12 11 1 42 25 30 29 34 23 35 22 20 15 1283 14 6 17 18 1283 68 76 60 75 8 18 19 1283 40 37 33 49 17 19 18 1283 37 39 27 33 25 18 30 29 30 19 25 31 28 37 27 33 77 62 57 78 42 25 29 37 41 50 37 49 28 25 16 27 76 66 58 61 14 26 15 16 70 56 71 57 43 64 47 48 36 47 35 48 58 56 64 72 35 34 47 36 21 23 13 24 72 56 71 70 64 78 71 57 38 50 39 37 4 1283 14 5 62 78 76 66 57 70 77 71 77 62 78 74 14 26 20 15 71 64 72 58 54 46 68 40 8 18 7 19 42 37 41 50 34 23 32 36 64 78 58 71 68 44 49 40 62 64 57 78 31 37 42 38 25 18 19 30 48 64 56 43 76 74 62 75 48 47 43 36 9 8 20 1283 60 46 44 68 60 53 46 75 40 37 28 33 33 39 44 49 33 44 40 49 17 19 14 25 15 4 1283 14 4 6 1283 5 2 12 13 1 39 37 49 33 42 25 37 31 72 73 71 58 42 25 31 30 76 78 60 58 41 37 42 29 23 34 21 22 57 64 43 56 46 68 40 44 78 68 76 60 39 37 27 38 66 61 76 75 78 57 77 71 28 25 27 37 25 18 29 17 37 50 42 38 30 41 42 29 1283 17 14 5 8 18 1283 6 6 17 1283 5 78 71 69 73 11 10 13 1 3 13 10 1 11 23 12 22 24 23 13 12 19 14 25 20 20 14 25 26 31 25 1338 19 31 37 1338 25 31 19 1338 20 31 20 1338 26

該当のソースコード

c

1#include <stdio.h> 2#include <stdlib.h> 3 4#define N 256 //1行の最大文字数(1バイト) 5 6int main(void) { 7 8 FILE *fp; // FILE型構造体 9 char fname[] = "in.dat"; 10 char youso[N]; //1行目に読み取る数値を格納する配列 11 int x,y,a1,a2; //1行目に使用 x:節点数 y:要素数 12 float a3; 13 int f1,f2,f3,f4,f5,f6,f7,f8; 14 15 //結果をファイルに出力 16 FILE *outputfile; // 出力ストリーム 17 outputfile = fopen("in_p.dat", "w"); // ファイルを書き込み用にオープン(開く) 18 if (outputfile == NULL) { // オープンに失敗した場合 19 printf("cannot open\n"); // エラーメッセージを出して 20 exit(1); // 異常終了 21 } 22 23 fp = fopen(fname, "r"); // ファイルを開く。失敗するとNULLを返す。 24 if(fp == NULL) { 25 printf("%s file not open!\n", fname); 26 return -1; 27 } 28 29 //1行目の読み取り 30 fgets(youso, N, fp); //1行のみ読み取り 31 sscanf(youso, "%d %d %d %d %f", &x,&y,&a1,&a2,&a3); //なぜか最後の数値だけfloat型でないとちゃんと出力されない 32 fprintf(outputfile,"%d %d %d %d %0.f\n", x,y,a1,a2,a3); //表示 33 //printf("%s", youso); 34 35 //要素の読み取り 36 int setten[y-1][3]; //各要素が使う節点番号を格納する配列;setten[0]には要素番号1の要素が使う節点を格納 37 //要素数が偶数か奇数かによって場合分け 38 if (y%2==0){ //偶数の時 39 for(int i=0;i<y/2;i++){ //要素数/2の回数だけ行単位で読み取る 40 fgets(youso, N, fp); //1行のみ読み取り 41 int s = 2*i; 42 int t = 2*i+1; 43 //配列に格納 44 sscanf(youso, "%d %d %d %d %d %d %d %d", &setten[s][0],&setten[s][1],&setten[s][2],&setten[s][3],&setten[t][0],&setten[t][1],&setten[t][2],&setten[t][3]); 45 //表示 46 fprintf(outputfile,"%d %d %d %d %d %d %d %d\n", setten[s][0],setten[s][1],setten[s][2],setten[s][3],setten[t][0],setten[t][1],setten[t][2],setten[t][3]); 47 } 48 } 49 if (y%2==1){ //奇数の時 50 for(int i=0;i<y/2;i++){ //要素数/2の回数だけ行単位で読み取る 51 fgets(youso, N, fp); //1行のみ読み取り 52 int s = 2*i; 53 int t = 2*i+1; 54 55/* 56 sscanf(youso, "%d %d %d %d %d %d %d %d", &f1,&f2,&f3,&f4,&f5,&f6,&f7,&f8); 57 58 int tmp1[] = {f1, f2, f3, f4}; 59 for(int j = 0; j < 4; j++) { 60 setten[s][j] = tmp1[j]; 61 } 62 int tmp2[] = {f5, f6, f7, f8}; 63 for(int j = 0; j < 4; j++) { 64 setten[t][j] = tmp2[j]; 65 } 66 67 printf("%d %d %d %d %d %d %d %d\n", setten[s][0],setten[s][1],setten[s][2],setten[s][3],setten[t][0],setten[t][1],setten[t][2],setten[t][3]); 68 69*/ 70 71 sscanf(youso, "%d %d %d %d %d %d %d %d", &setten[s][0],&setten[s][1],&setten[s][2],&setten[s][3],&setten[t][0],&setten[t][1],&setten[t][2],&setten[t][3]); 72 //fprintf(outputfile,"%d %d %d %d %d %d %d %d\n", setten[s][0],setten[s][1],setten[s][2],setten[s][3],setten[t][0],setten[t][1],setten[t][2],setten[t][3]); 73 } 74 //残った最後の一行 75 fgets(youso, N, fp); 76 sscanf(youso, "%d %d %d %d", &setten[y-1][0],&setten[y-1][1],&setten[y-1][2],&setten[y-1][3]); 77 fprintf(outputfile,"%d %d %d %d\n", setten[y-1][0],setten[y-1][1],setten[y-1][2],setten[y-1][3]); 78 } 79 80 //節点座標の読み取り 81 double zahyou[x][2]; //節点のx,y,z座標を格納する配列 82 for(int i=0;i<x;i++){ //節点数の回数だけ行単位で読み取る 83 84 fgets(youso, N, fp); //1行のみ読み取り 85 sscanf(youso, "%lf %lf %lf", &zahyou[i][0],&zahyou[i][1],&zahyou[i][2]); 86 //fprintf(outputfile,"%f %f %f\n", zahyou[i][0],zahyou[i][1],zahyou[i][2]); 87 88 } 89 90 //printf("%f %f %f\n", zahyou[0][0],zahyou[0][1],zahyou[0][2]); 91 92 for(int i=0;i<x;i++){ 93 //fprintf(outputfile,"%f %f %f\n", zahyou[i][0],zahyou[i][1],zahyou[i][2]); 94 } 95 96 97 //使われていない節点の座標を表す行を削除したい 98 99 //新しい配列において使われている節点の節点番号に該当する箇所に1を格納 100 //使われていない節点の節点番号に該当する配列には0を格納 101 102 int bangou[x-1]; //新しい配列 103 int s=0; 104 int i,j; 105 //使われている節点の節点番号に該当する箇所に1を格納 106 for (i=0;i<y;i++){ 107 for (j=0;j<3;j++){ 108 s = setten[i][j]; 109 bangou[s-1]=1; 110 } 111 } 112 //使われていない節点の節点番号に該当する配列には0を格納 113 for (i=0;i<x;i++){ 114 if (bangou[i]!=1){ 115 bangou[i]=0; 116 } 117 } 118 /* 119 //表示 120 for (i=0;i<x;i++){ 121 printf("%d\n", bangou[i]); 122 } 123 */ 124 /* 125 //使われていない節点の座標を格納した配列に0を格納 126 for (i=0;i<x;i++){ 127 if (bangou[i]==0){ 128 zahyou[i][0] = 0; 129 zahyou[i][1] = 0; 130 zahyou[i][2] = 0; 131 } 132 //printf("%f %f %f\n", zahyou[i][0],zahyou[i][1],zahyou[i][2]); //表示 133 134 } 135 136 */ 137 138 /* 139 //使われていない節点の座標が書かれた行を削除して表示 140 for (i=0;i<x;i++){ 141 if (zahyou[i][0]!=0&&zahyou[i][1]!=0&&zahyou[i][2]!=0){ 142 printf("%f %f %f\n", zahyou[i][0],zahyou[i][1],zahyou[i][2]); 143 } 144 } 145 */ 146 147 148 for (i=0;i<x;i++){ 149 if (bangou[i]==1){ 150 fprintf(outputfile,"%f %f %f\n", zahyou[i][0],zahyou[i][1],zahyou[i][2]); 151 } 152 } 153 154 155 fclose(fp); // ファイルを閉じる 156 157 fclose(outputfile); // ファイルをクローズ(閉じる) 158 return 0; 159}

実行結果(該当箇所一部抜粋)

23 34 35 70 70 73 72 56 66 61 64 33 33 46 40 44 58 56 72 73 73 78 58 60 75 53 65 64 64 78 66 58 //省略

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

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

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

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

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

y_waiwai

2023/02/02 14:02

コードが不足すぎて意味不明です 全体を載せましょう
jimbe

2023/02/02 14:28 編集

実行して結果が確認出来る状態のコード・データをご提示ください。
shumpei0902

2023/02/02 18:21

ソースコードをそのまま貼ってみました。読みにくかったら申し訳ありません。
jimbe

2023/02/02 18:45

有難うございます。 質問と関係有りませんが、 sscanf より fscanf 使った方が簡単そうですね。
shumpei0902

2023/02/02 19:43

ありがとうございます。 fscanfでも作成してみたいと思います。
guest

回答1

0

ベストアンサー

書かれてないsettenの宣言が間違っているんでしょうね。1次元目のサイズが3とか。
書かれてない部分にもっと他の間違いがあるのかも知れませんが。

投稿2023/02/02 16:00

otn

総合スコア84457

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

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

shumpei0902

2023/02/02 18:17

ソースコードをすべて貼りなおしました。多次元配列の宣言が足りていないのでしょうか。
jimbe

2023/02/02 18:41

>int setten[y-1][3]; 思いっきり 3 ですね。
shumpei0902

2023/02/02 19:41

4に直したら正しく実行できました! 配列の宣言の仕方について勘違いがありました… (0,1,2,3でサイズ4になってると) ありがとうございます!
otn

2023/02/03 01:16

改善点としては、scanf系関数の返値のチェックをすることです。 例えば端末からの手入力に単にscanfを使う場合で、返値をチェックしてないのは欠陥プログラムです。 今回はファイルからの入力で、fgets+sscanfもしくはfscanfなので、条件によっては返値チェックを省略しても良いです。条件というのは、想定通りでない形式のデータが入っていることが絶対無いことに自分の命を賭けてもいい場合。私はそんなことに命を賭けないですが。 あと優秀なプログラムにしたければ、 > 空白で区切られた1行8つの値を多次元配列を用いて4つずつ表示させようとしています。 が、例えば10個の値を5つずつという風に前提の個数が変わった場合に、 #define KOSUU 4 みたいなのを #define KOSUU 5 に変えるだけで、プログラムの他の部分を全く修正しなくていいようにする。この課題だとそこまで求めてない気もしますが。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問