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

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

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

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

ファイル

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

Q&A

解決済

1回答

1017閲覧

座標の値の重複を削除し、座標点の番号を更新したい

退会済みユーザー

退会済みユーザー

総合スコア0

C

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

ファイル

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

0グッド

0クリップ

投稿2021/01/16 07:48

編集2021/01/20 08:05

前提・実現したいこと

C言語で2つのdatファイル(in.dat1,in.dat2)を読み込み、結合して新しいファイル(in.dat)に出力するプログラムを作ってます。それぞれのファイルには、決まったフォーマットで、節点数、要素数が書き込まれてあり、それらを合わせていつのファイルにしたいです。
節点のx座標、y座標、z座標に重複があった場合に重複をなくして出力し、節点番号(下にファイルのフォーマットがあります。)を更新して出力しなければならないのですが、どのようなコードで書けばいいのかわかりません。
ファイルのフォーマットとそれぞれのファイルの内容も載せておきます。
質問2回目です。質問等が伝わりにくかったらごめんなさい。お願いします。

該当のソースコード

C

1#include <stdio.h> 2#include <stdlib.h> //exit関数を用いるために必要 3 4int main() 5{ 6 //readfは読み込むファイル,writefは書き込むファイル 7 FILE *readf_in1, *readf_in2, *writef_in; 8 9 char in1[] = "in.dat1"; 10 char in2[] = "in.dat2"; 11 12 int point1[1024][16];//配列の数は適当です。 13 int point2[1024][16]; 14 float fpoint1[1024][4]; 15 float fpoint2[1024][4]; 16 double epoint1[1024][3]; 17 double epoint2[1024][3]; 18 double ecomb2[1024][3]; 19 20 //読み込むファイルをopen 21 readf_in1 = fopen(in1,"r"); 22 if(readf_in1 == NULL){//エラー処理 23 printf("error in.dat1\n"); 24 exit(1); //強制終了 25 } 26 else{ 27 printf("read in.dat1\n"); 28 } 29 //読み込むファイルをopen 30 readf_in2 = fopen(in2,"r"); 31 if(readf_in2 == NULL){//エラー処理 32 fclose(readf_in1); 33 printf("error in.dat2\n"); 34 exit(1); //強制終了 35 } 36 else{ 37 printf("read in.dat2\n"); 38 } 39 40 //書き込むファイルをopen 41 writef_in = fopen("in.dat", "w"); 42 if(writef_in == NULL){//エラー処理 43 fclose(readf_in1); 44 fclose(readf_in2); 45 printf("error in.dat\n"); 46 exit(1); //強制終了 47 } 48 else{ 49 printf("write in.dat\n"); 50 } 51 52 for(int i = 0; i < 4; i++) {//配列に保存 53 fscanf(readf_in1,"%d", &(point1[0][i])); 54 } 55 for(int i = 0; i < 4; i++) {//配列に保存 56 fscanf(readf_in2,"%d", &(point2[0][i])); 57 } 58 for(int i = 0; i < 1; i++) {//配列に保存 59 fscanf(readf_in1,"%E", &(fpoint1[0][i])); 60 } 61 for(int i = 0; i < 1; i++) {//配列に保存 62 fscanf(readf_in2,"%E", &(fpoint2[0][i])); 63 } 64 for(int i = 1; i < point1[0][1]+1; i++){//配列に保存 65 for(int j = 0; j < 4; j++){ 66 fscanf(readf_in1,"%d", 67 &(point1[i][j]), 68 &(point1[i][j+1]), 69 &(point1[i][j+2]), 70 &(point1[i][j+3]) 71 ); 72 } 73 } 74 for(int i = 1; i < point2[0][1]+1; i++){//配列に保存 75 for(int j = 0; j < 4; j++){ 76 fscanf(readf_in2,"%d", 77 &(point2[i][j]), 78 &(point2[i][j+1]), 79 &(point2[i][j+2]), 80 &(point2[i][j+3]) 81 ); 82 } 83 } 84 for(int i = 1; i < point1[0][0]+1; i++){//配列に保存 85 for(int j = 0; j < 3; j++){ 86 fscanf(readf_in1,"%lf", //lfは倍精度実数で読み取る 87 &(epoint1[i][j]), 88 &(epoint1[i][j+1]), 89 &(epoint1[i][j+2]) 90 ); 91 } 92 } 93 for(int i = 1; i < point2[0][0]+1; i++){//配列に保存 94 for(int j = 0; j < 3; j++){ 95 fscanf(readf_in2,"%lf", //lfは倍精度実数で読み取る 96 &(epoint2[i][j]), 97 &(epoint2[i][j+1]), 98 &(epoint2[i][j+2]) 99 ); 100 } 101 } 102 103/* -- ここからわかりません -- */ 104 int k = 0; 105 for(int i = 0; i < point2[0][0]; i++){ 106 for(int j =0; j < point1[0][0]; j++){ 107 if(epoint1[i][0] == epoint2[j][0] && epoint1[i][1] == epoint2[j][1] && epoint1[i][3] == epoint2[j][3] ){ 108 printf("match\n"); 109 } 110 else{ 111 k = k + 1; 112 ecomb2[k][0] = epoint2[j][0]; 113 ecomb2[k][1] = epoint2[j][1]; 114 ecomb2[k][2] = epoint2[j][2]; 115 } 116 } 117 } 118 119 fprintf(writef_in,"%8d\n", k);//確認用 120 for(int i = 0; i < k; i++){ 121 fprintf(writef_in,"%24.13E%24.13E%24.13E\n", 122 ecomb2[i][0], ecomb2[i][1], ecomb2[i][2] 123 ); 124 } 125/* -- ここまでわかりません -- */ 126 127 //ファイルをclose 128 fclose(readf_in1); 129 fclose(readf_in2); 130 fclose(writef_in); 131}

ファイルのフォーマット

dat

1 節点数  要素数 0 0 1.000E+03 2 要素1を形成する節点番号4つ  要素2を形成する節点番号4つ 3 要素3を形成する節点番号4つ  要素4を形成する節点番号4つ 4 要素5を形成する節点番号4つ  要素6を形成する節点番号4つ 5 . 6 . 7 . 8 要素23を形成する節点番号4つ  要素24を形成する節点番号4つ 9 節点1のx座標  節点1のy座標  節点1のz座標 10 節点2のx座標  節点2のy座標  節点2のz座標 11 節点3のx座標  節点3のy座標  節点3のz座標 12 . 13 . 14 . 15 節点18のx座標  節点18のy座標  節点18のz座標
in.dat1(入力ファイル)

dat

1 6 3 0 0 1.000E+03 2 1 2 3 4 5 6 1 2 3 3 4 5 6 4 11 11 11 5 12 12 12 6 13 13 13 7 14 14 14 8 15 15 15 9 16 16 16
in.dat2(入力ファイル)

dat

1 9 5 0 0 1.000E+03 2 1 2 3 4 5 6 7 8 3 9 1 2 3 4 5 6 7 4 8 9 1 2 5 21 21 21 6 13 13 13 7 15 15 15 8 22 22 22 9 23 23 23 10 24 24 24 11 16 16 16 12 25 25 25 13 26 26 26
in.dat(出力ファイル)

dat

1 12 8 0 0 1.000E+03 2 1 2 3 4 5 6 1 2 3 3 4 5 6 7 3 5 8 4 9 6 10 11 12 7 3 5 5 8 9 6 10 11 12 7 3 6 11 11 11 7 12 12 12 8 13 13 13 9 14 14 14 10 15 15 15 11 16 16 16 12 21 21 21 13 22 22 22 14 23 23 23 15 24 24 24 16 25 25 25 17 26 26 26

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

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

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

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

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

kozuchi

2021/01/16 08:19

重複の定義がよくわかりません。 重複をなくすべきなのは、「節点全体で重複があった場合」「1つの要素の中で構成する節点の座標に重複があった場合」いずれでしょうか? また、座標値が浮動小数点数ですが、重複の定義はどうなりますか?許容誤差などは考えず、完全一致で考えていいのですか?
dodox86

2021/01/16 08:25

恐らく前の質問の問題の発展形なのかと思いますが、 [座標の値の重複を削除したいです C言語] https://teratail.com/questions/315989 そこでいただいた回答での指摘事項などが反映されていない(消化できていない?)ように見えますが、そんなことはありませんでしょうか。
退会済みユーザー

退会済みユーザー

2021/01/16 08:45

重複の定義は座標点での重複です。 誤差は考えずに完全一致でいいです。 前回質問した部分を反映したコードは重複を見つけて削除するだけだったので、新しいコードに追加するのは良くないと思い前のコードのままにしておきました。 コードの不備は直しておきます。
kazuma-s

2021/01/16 08:53

> in.dat2は文字数の関係で載せられませんでした。 節点数や要素数を小さくした例で、期待する結果も含めて、3つのファイルを提示してください。 コンパイラは何ですか? どんなコンパイラでもコンパイルエラーになるはずですが。
退会済みユーザー

退会済みユーザー

2021/01/16 09:37

ファイルを3つ提示しました。 コンパイラはCです。
dodox86

2021/01/16 09:59

>@質問者さん 私宛のコメントではありませんでしたが、返信させていただきます。 > コンパイラはCです。 ここで問われているコンパイラとは、CとかC++とかJavaとかプログラミング言語の話ではなく、gcc とか clangとかVisual Studio(C++)とか、 Cコンパイラの種類、製品、バージョンを指します。kazuma-sさんの「どんなコンパイラでもコンパイルエラーになるはずですが。」との指摘通り、 C言語のコードに不備がある為、コンパイルエラーになっています。 ここから>>>> $ gcc --version gcc (GCC) 10.2.0 Copyright (C) 2020 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. $ gcc -Wall t8.c t8.c: 関数 ‘main’ 内: t8.c:45:12: エラー: ‘readf_sin1’ undeclared (first use in this function); did you mean ‘readf_in1’? 45 | fclose(readf_sin1); | ^~~~~~~~~~ | readf_in1 t8.c:45:12: 備考: 未宣言の識別子は出現した各関数内で一回のみ報告されます t8.c:46:12: エラー: ‘readf_sin2’ undeclared (first use in this function); did you mean ‘readf_in2’? 46 | fclose(readf_sin2); | ^~~~~~~~~~ | readf_in2 t8.c:68:24: 警告: 書式への引数が多すぎます [-Wformat-extra-args] 68 | fscanf(readf_in1,"%d", | ^~~~ t8.c:78:24: 警告: 書式への引数が多すぎます [-Wformat-extra-args] 78 | fscanf(readf_in2,"%d", | ^~~~ t8.c:88:24: 警告: 書式への引数が多すぎます [-Wformat-extra-args] 88 | fscanf(readf_in1,"%lf", //lfは倍精度実数で読み取る | ^~~~~ t8.c:97:24: 警告: 書式への引数が多すぎます [-Wformat-extra-args] 97 | fscanf(readf_in2,"%lf", //lfは倍精度実数で読み取る | ^~~~~ t8.c:7:45: 警告: 使用されない変数 ‘writef_sin’ です [-Wunused-variable] 7 | FILE *readf_in1, *readf_in2, *writef_in, *writef_sin; | ^~~~~~~~~~ <<<ここまで このような不完全なコードでは、実際に実行して確認してみようという回答者さんらにとって使えませんし、質問者さんがどこまでコードを理解されているかも推し量ることができません。
退会済みユーザー

退会済みユーザー

2021/01/16 10:12

ごめんなさい。理解不足でした。 コードは修正しておきました。 gcc (MinGW.org GCC-6.3.0-1) 6.3.0 Copyright (C) 2016 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
ppaul

2021/01/16 13:02

見たところ、in.dataはin.data2と全く同じですね。 目的とするin.dataを書いていただかないと、回答できません。
退会済みユーザー

退会済みユーザー

2021/01/16 13:42

すいません。すぐに直します。
kazuma-s

2021/01/16 13:45

重複がどうとかこうとかいう以前の問題です。 in.data1 だけを読み込んで、それを in.data として書き出すだけのプログラムが書けますか?
退会済みユーザー

退会済みユーザー

2021/01/16 13:47

それはできました。
kazuma-s

2021/01/20 08:00

なぜ質問を消すんですか? コメントとの整合性が取れません。 元に戻してください。 そして、コードについて注釈を追加してください。
guest

回答1

0

ベストアンサー

これでどうでしょうか?

C

1#include <stdio.h> 2#include <stdlib.h> // exit 3 4void read_data(const char *fname, int p[1024][4], double ep[1024][3]) 5{ 6 FILE *fp = fopen(fname, "r"); 7 if (!fp) { perror(fname); exit(1); } 8 double d; 9 fscanf(fp, "%d%d%d%d%lf", &p[0][0], &p[0][1], &p[0][2], &p[0][3], &d); 10 int i, j; 11 for (i = 1; i <= p[0][1]; i++) 12 for (j = 0; j < 4; j++) fscanf(fp, "%d", &p[i][j]); 13 for (i = 1; i <= p[0][0]; i++) 14 for (j = 0; j < 3; j++) fscanf(fp, "%lf", &ep[i][j]); 15 fclose(fp); 16} 17 18void write_data(const char *fname, int p[1024][4], double ec[1024][3]) 19{ 20 FILE *fp = fopen(fname, "w"); 21 if (!fp) { perror(fname); exit(1); } 22 fprintf(fp, "%8d%8d%8d%8d%16.3e\n", p[0][0], p[0][1], 0, 0, 1.0e+3); 23 int i, j; 24 for (i = 1; i <= p[0][1]; i++) { 25 fprintf(fp, "%8d%8d%8d%8d", p[i][0], p[i][1], p[i][2], p[i][3]); 26 if ((i & 1) == 0) fputc('\n',fp); 27 } 28 if ((i & 1) == 0) fputc('\n',fp); 29 for (int i = 1; i <= p[0][0]; i++) 30 fprintf(fp, "%24.13g%24.13g%24.13g\n", ec[i][0], ec[i][1], ec[i][2]); 31 fclose(fp); 32} 33 34int main(void) 35{ 36 int point1[1024][4]; 37 int point2[1024][4]; 38 double epoint1[1024][3]; 39 double epoint2[1024][3]; 40 int conv[1024]; 41 42 read_data("in.dat1", point1, epoint1); 43 read_data("in.dat2", point2, epoint2); 44 45 int np1 = point1[0][0], ne1 = point1[0][1]; 46 int np2 = point2[0][0], ne2 = point2[0][1]; 47 48 int i, j, k = np1; 49 for (i = 1; i <= np2; i++) { 50 for (j = 1; j <= np1; j++) 51 if (epoint1[j][0] == epoint2[i][0] && 52 epoint1[j][1] == epoint2[i][1] && 53 epoint1[j][2] == epoint2[i][2]) break; 54 if (j > np1) { // 重複しなかったので 55 conv[i] = ++k; // 新規節点番号を登録 56 for (j = 0; j < 3; j++) epoint1[k][j] = epoint2[i][j]; 57 } 58 else conv[i] = j; // 重複したので、登録済み節点番号 j を使う 59 } 60 for (i = 1; i <= ne2; i++) 61 for (j = 0; j < 4; j++) point1[ne1 + i][j] = conv[point2[i][j]]; 62 63 point1[0][0] = k; 64 point1[0][1] = ne1 + ne2; 65 write_data("in.dat", point1, epoint1); 66} 67

理解できたかどうかのコメントをお願いします。

投稿2021/01/16 18:28

編集2021/01/16 18:53
kazuma-s

総合スコア8224

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

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

退会済みユーザー

退会済みユーザー

2021/01/16 23:07

ご回答ありがとうございます。 とてもまとまっていてわかりやすいです。 ひとつ質問です。 for (i = 1; i <= ne2; i++) for (j = 0; j < 4; j++) point1[ne1 + i][j] = conv[point2[i][j]]; 最後のfor文は登録済み節点番号 j を探して、point1[ne1 + i][j]に代入ということでいいでしょうか。
kazuma-s

2021/01/17 02:36

j は節点番号ではありません。 一つの要素には 4 つの節点があるので、その 4つを参照するための添字です。 i は in.dat2 の中の要素番号です。 ne1 は in.dat1 の要素数です。 point1[ne1 + i] = で in.dat2 の要素を in.dat1 に追加しています。 conv は in.dat2 の節点番号を新しい節点番号へ変換するためのテーブルです。 in.dat2 の節点番号 i に対して、 同じ座標の接点が in.dat1 にあれば conv[i] はその in.dat1 の節点番号、 同じ座標の接点が in.dat1 になければ conv[i] は新規節点番号。
退会済みユーザー

退会済みユーザー

2021/01/18 07:38

理解できました。丁寧にありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問