🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

2回答

3451閲覧

fscanf_s();関数で文字が最初しか設定出来ない理由が知りたい。

退会済みユーザー

退会済みユーザー

総合スコア0

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2020/12/31 08:13

編集2020/12/31 09:45

提示コードですがコメント部のfscanf_s(); 関数部ですがなぜ最初の数字だけ設定された他の2番目、3番目の場合は数字が設定されないのでしょうか? 理由がわかりません。printf();でデバッグしていますがなぜかpos[1] pos[2]の場合だけ数字が設定されません。これはどうすればしょうか・上のコードのように普通にコードを組めばいいと思うのですがなぜでしょうか?

公式リファレンス: https://docs.microsoft.com/ja-jp/cpp/c-runtime-library/reference/fscanf-s-fscanf-s-l-fwscanf-s-fwscanf-s-l?view=msvc-160

参考サイト: http://www.opengl-tutorial.org/jp/beginners-tutorials/tutorial-7-model-loading/

イメージ説明

cpp

1 2//objファイルを読み込み 3bool Game::Load_obj(const char* file, std::vector<glm::vec3>& out_vertices, std::vector<glm::vec2>& out_uvs, std::vector<glm::vec3>& out_normals) 4{ 5 6 std::vector<unsigned int> vertexIndices; //頂点インデックス 7 std::vector<unsigned int> uvIndices; //UV座標インデックス 8 std::vector<unsigned int> normalIndices; //法線インデックス 9 10 11 12 std::vector<glm::vec3> temp_vertices; 13 std::vector<glm::vec2> temp_uvs; 14 std::vector<glm::vec3> temp_normals; 15 16 17 std::vector<int> index_pos; 18 std::vector<int> index_uv; 19 std::vector<int> index_norm; 20 21 FILE* fp = nullptr; 22 fopen_s(&fp, file, "r"); //読み込み専用でファイルを開く 23 24 /* 25 //.objファイルを表示 26 char str[256] = { 0 }; 27 if (fp != nullptr) { 28 while (fgets(str, 256, fp) != NULL) 29 { 30 printf("%s", str); 31 } 32 } 33 */ 34 35 int a = 0; 36 if (fp != NULL) 37 { 38 while (true) 39 { 40 char lineHeader[256] = { 0 }; 41 int res = fscanf_s(fp, "%s", lineHeader, (unsigned int)sizeof(lineHeader)); 42 43 if (res == EOF) 44 { 45 break; 46 } 47 else 48 { 49 /* ################ ファイル抽出 ################ */ 50 51 if (strcmp(lineHeader, "v") == 0) //頂点を抽出 52 { 53 glm::vec3 vertex; 54 fscanf_s(fp, "%f %f %f", &vertex.x, &vertex.y, &vertex.z); 55 temp_vertices.push_back(vertex); 56 } 57 else if (strcmp(lineHeader, "vt") == 0) //UV座標を抽出 58 { 59 glm::vec2 uv = glm::vec2(0, 0); 60 fscanf_s(fp, "%f %fn", &uv.x, &uv.y); 61 temp_uvs.push_back(uv); 62 } 63 else if (strcmp(lineHeader, "vn") == 0) //法線を抽出 64 { 65 glm::vec3 normalize = glm::vec3(0, 0, 0); 66 fscanf_s(fp, "%f %f %fn", &normalize.x, &normalize.y, &normalize.z); 67 temp_normals.push_back(normalize); 68 } 69 else if (strcmp(lineHeader, "f") == 0) 70 {////////////////////////////////////////////////////////// 71 int pos[3]; //座標 72 int uv[3]; //UV座標 73 int norm[3];//法線 74 fscanf_s(fp,"%d%d%d %d%d%d %d%d%d", 75 &pos[0], &uv[0], &norm[0], 76 &pos[1], &uv[1], &norm[1], 77 &pos[2], &uv[2], &norm[2] 78 ); 79///////////////////////////////////////////////////////////////////////// 80 printf("%d\n",pos[1]); 81 82 83 index_pos.push_back(pos[0]); 84 index_pos.push_back(pos[1]); 85 index_pos.push_back(pos[2]); 86 87 88 89 index_uv.push_back(uv[0]); 90 index_uv.push_back(uv[1]); 91 index_uv.push_back(uv[2]); 92 93 index_norm.push_back(norm[0]); 94 index_norm.push_back(norm[1]); 95 index_norm.push_back(norm[2]); 96 } 97 } 98 } 99 100 try { 101 102 for (int i = 0; i < index_pos.size(); i++) 103 { 104 printf("wwwwwwwwwww %d\n",(int)index_pos.at(i)); 105 } 106 107 108 109// for (int i = 0; i < index_pos.size(); i++) { 110 for (int i = 0; i < temp_vertices.size(); i++) { 111 112 glm::vec3 v = temp_vertices.at(index_pos.at(i)); 113 114 printf("%d\n",temp_vertices.size()); 115 out_vertices.push_back( v ); 116 } 117 118 119 } 120 catch (std::exception e) 121 { 122 printf("頂点 %s\n",e.what()); 123 } 124/* 125 try { 126 // UV座標 127 for (int i = 0; i < temp_uvs.size(); i++) 128 { 129 printf("%.2f , %.2f \n", temp_uvs.at(i).x, temp_uvs.at(i).y); 130 out_uvs.push_back(temp_uvs.at(i)); 131 } 132 } 133 catch (std::exception e) 134 { 135 printf("UV座標 %s\n", e.what()); 136 } 137 138 try { 139 // 法線座標 140 for (int i = 0; i < temp_normals.size(); i++) 141 { 142 printf("%.2f , %.2f , %.2f \n", temp_normals.at(i).x, temp_normals.at(i).y, temp_normals.at(i).z); 143 out_normals.push_back(temp_normals.at(i)); 144 } 145 } 146 catch (std::exception e) 147 { 148 printf("法線 %s\n", e.what()); 149 } 150 151 */ 152 153 154 return true; 155 } 156 else 157 { 158 printf("ファイルが読めませんでした。\n"); 159 return false; 160 } 161}

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

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

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

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

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

SHOMI

2020/12/31 09:56

読めない理由はepistemeさんの回答通りです(参考サイトのコードも書式はあってます)が、 fscanf_s(fp, "%f %fn", &uv.x, &uv.y); fscanf_s(fp, "%f %f %fn", &normalize.x, &normalize.y, &normalize.z); 書式文字列末尾の「n」は「\n」でしょう。 参考サイトも英語表示にするとそうなります。
guest

回答2

0

書式指定文字列の誤りでしょうね。
以下 sscanf_s で実験:

C

1#include <stdio.h> 2 3int main() { 4 const char* input = "1/2/3"; 5 int data[3]; 6 7 int result; 8 int i; 9 10 // ダメな場合 11 result = sscanf_s(input, "%d%d%d", &data[0], &data[1], &data[2]); 12 printf("# of input : %d \n", result); 13 for ( i = 0; i < result; ++i) { printf("data[%d] = %d\t", i, data[i]); } printf("\n\n"); 14 15 // イケてる場合 16 result = sscanf_s(input, "%d/%d/%d", &data[0], &data[1], &data[2]); 17 printf("# of input : %d \n", result); 18 for ( i = 0; i < result; ++i) { printf("data[%d] = %d\t", i, data[i]); } printf("\n\n"); 19 20 return 0; 21}

公式リファレンス曰く:

書式は左から右へ読み取られます。 書式指定以外の文字は、入力ストリーム内の一連の文字列に一致するものと想定されます。これらの文字は入力ストリーム内でスキャンされますが格納はされません。 入力ストリーム内の文字が書式指定に合わないと、scanf 関数は終了し、その文字は読み取られなかったものとして入力ストリームに残ります

つまり書式中に '/' を書いてないのでデータ中の '/'は読み飛ばされずに %d すなわち int に変換しようとする。ところが '/'はintに変換できずに scanfはそこで失敗とする。2つめ以降が読み取れない理由はコレ。

投稿2020/12/31 09:13

編集2020/12/31 09:25
episteme

総合スコア16612

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

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

退会済みユーザー

退会済みユーザー

2020/12/31 09:25 編集

sscanf_s(lineHeader, "%d%d%d %d%d%d %d%d%d %d%d%d", //fscanf_s(fp,"%d%d%d %d%d%d %d%d%d", &pos[0],&uv[0], &norm[0], &pos[1], &uv[1], &norm[1], &pos[2], &uv[2], &norm[2], &pos[3], &uv[3], &norm[3]); としましたがすべての値が未初期化です。どうすればいいのでしょうか?ちゃんと考えましたがわかりません。
episteme

2020/12/31 09:29 編集

考えてない...てか読んでない。 書式:"%d/%d/%d"にしろ と答えたつもりだが?
退会済みユーザー

退会済みユーザー

2020/12/31 09:32 編集

sscanf_s(lineHeader, "%d/%d/%d %d/%d/%d %d/%d/%d %d/%d/%d", &pos[0],&uv[0],&norm[0], &pos[1], &uv[1], &norm[1], &pos[2], &uv[2], &norm[2], &pos[3], &uv[3], &norm[3]); として/を入れましたが未初期化です。どうすればいいのでしょうか?
episteme

2020/12/31 09:34

lineHeaderにはどんな文字列が入ってるか、printf("[%s]\n", lineHeader) かなにかで確認した?
SHOMI

2020/12/31 09:37 編集

lineHeaderが"f"だからでしょう
episteme

2020/12/31 09:36

400を超える質問してるんだ、そろそろ初心者を卒業してはいかが?
退会済みユーザー

退会済みユーザー

2020/12/31 09:37

確認したところ[ f ] としか文字列が入っていません。なぜでしょうか?上のコードではどれも正常に値が入っているため意外な結果です。どうすればいいのでしょうか?
episteme

2020/12/31 09:41 編集

↑そりゃそうだ。 int res = fscanf_s(fp, "%s", lineHeader, (unsigned int)sizeof(lineHeader)); コレで取り込めるのは最初の1単語だけだから。 それにあなたが読みたいのは ファイル(fp)からだろ? lineHeaderからじゃないよね?
SHOMI

2020/12/31 09:40

fscanf_s(fp,~ // ファイルから読み取り を sscanf_s(lineHeader, ~ //int res = fscanf_s(fp, "%s", lineHeader, (unsigned int)sizeof(lineHeader));で読み取ったもの に書き換えたからでしょ
episteme

2020/12/31 09:44

...だからナニ?
退会済みユーザー

退会済みユーザー

2020/12/31 09:45

すいませんでした。
episteme

2020/12/31 09:49

なんで謝るのかわからん。 こちらのサイトのコードを引用したものです...うん、それで? と訊いてます。
退会済みユーザー

退会済みユーザー

2020/12/31 09:52

それが自体がおかしいのでしょうか?自分はそのサイトを引用してコードを書いたのですが?
episteme

2020/12/31 09:55

それはわからんよ、一字一句完全丸コピしたんじゃないんでしょ?
SHOMI

2020/12/31 09:57

そのサイトのコードは合っていますよ。 int matches = fscanf(file, "%d/%d/%d %d/%d/%d %d/%d/%d\n", &vertexIndex[0], &uvIndex[0], &normalIndex[0], &vertexIndex[1], &uvIndex[1], &normalIndex[1], &vertexIndex[2], &uvIndex[2], &normalIndex[2] );
episteme

2020/12/31 09:58

ともかく、当初の「fscanf_s();関数で文字が最初しか設定出来ない理由が知りたい。」は解決したんよね?
退会済みユーザー

退会済みユーザー

2020/12/31 10:00

自己解決しました。
episteme

2020/12/31 10:09

「文字が最初しか設定出来ない理由」は何だったん?
退会済みユーザー

退会済みユーザー

2020/12/31 10:35

わかりませんがfgets();関数を使う方法で自己解決しました。 1行読み込む必要がるところ1文字しか読み込まれていませんでした。
SHOMI

2020/12/31 10:45 編集

fscanf_s(fp, "%d%d%d %d%d%d %d%d%d", &pos[0], &uv[0], &norm[0], &pos[1], &uv[1], &norm[1], &pos[2], &uv[2], &norm[2] ); の書式文字列を直せばいいだけでは?4組読み取るなら引数も追加で。
退会済みユーザー

退会済みユーザー

2020/12/31 10:47

いや上手くいかないのでfgets();にしました。
episteme

2020/12/31 10:53

ちっとも解決してねぇ...
SHOMI

2021/01/02 15:42 編集

fgets()&sscanf_s()にして動くなら、あなたが実際に書いたfscanf_s()版のコードが間違えているとしか思えません。 というか、コメント(2020/12/31 18:22,2020/12/31 18:29)であなたはfscanf_s(fp,~)ではなくsscanf_s(lineHeader, ~)にしてうまく行かないと書いていますが、ちゃんと fscanf_s(fp,"%d/%d/%d %d/%d/%d %d/%d/%d %d/%d/%d", &pos[0],&uv[0],&norm[0], &pos[1], &uv[1], &norm[1], &pos[2], &uv[2], &norm[2], &pos[3], &uv[3], &norm[3]); に戻して確認したのですか?
guest

0

ベストアンサー

以下のコードにより自己解決しました。
fgets();関数によりファイルの1行を取得してそれをsscanf_s();関数に渡すことによりファイルの中身を読み取れました。

cpp

1char str[256] = { 0 }; 2fgets(str, 256, fp); 3sscanf_s(str, "%d/%d/%d %d/%d/%d %d/%d/%d %d/%d/%d", 4&pos[0],&uv[0],&norm[0], 5&pos[1], &uv[1], &norm[1], 6&pos[2], &uv[2], &norm[2], 7&pos[3], &uv[3], &norm[3]);

投稿2020/12/31 10:00

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

episteme

2020/12/31 10:03

自己解決か?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問