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

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

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

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

Q&A

解決済

2回答

1896閲覧

c言語のバイナリファイルの読み込みについて

masamuneyuya

総合スコア12

C

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

0グッド

0クリップ

投稿2021/07/12 14:56

前提・実現したいこと

コマンドライン引数としてjpgファイルを指定して、そのバイナリファイルを読み込んで、新しいファイルとして書き出したい。

発生している問題

50個のjpegファイルが生成されるはずなのに、生成されない。

該当のソースコード

c

1#include <stdio.h> 2#include <stdlib.h> 3#include <stdint.h> 4#include <string.h> 5 6typedef uint8_t BYTE; 7char* file_name(int count); 8int count = 0; 9char filename[8]; 10 11int main(int argc, char *argv[]) 12{ 13 if (argc != 2) 14 { 15 printf("Usage: ./recover image\n"); 16 return 1; 17 } 18 FILE *file = fopen(argv[1],"r"); 19 if (!file) 20 { 21 printf("Could not open file.\n"); 22 return 1; 23 } 24 25 BYTE bytes[4]; 26 BYTE buffer[512]; 27 while (fread(&buffer, sizeof(BYTE), 1, file)) 28 { 29 fread(bytes, sizeof(BYTE), 4, file); 30 if (bytes[0] == 0xff && bytes[1] == 0xd8 && bytes[2] == 0xff && (bytes[3] & 0xf0) == 0xe0) 31 { 32 char* name = file_name(count); 33 FILE *destination = fopen(name, "w"); 34 if (!destination) 35 { 36 return 1; 37 } 38 do 39 { 40 fwrite(&buffer, 512, 1, destination); 41 } 42 while (!(bytes[0] == 0xff && bytes[1] == 0xd8 && bytes[2] == 0xff && (bytes[3] & 0xf0) == 0xe0)); 43 44 fclose(destination); 45 count++; 46 } 47 } 48 return 0; 49} 50 51char* file_name(int number) 52{ 53 char number2[sizeof(number)]; 54 sprintf(number2,"%d", number); 55 if (strlen(number2) == 1) 56 { 57 sprintf(filename,"00%s.jpg", number2); 58 return filename; 59 } 60 else 61 { 62 sprintf(filename,"0%d%d.jpg", (int)number2[0], (int)number2[1]); 63 return filename; 64 } 65} 66

試したこと

・最初のwhile文のfreadの第二引数の数を1にするといくつかファイルが生成されるが、50個には全然届かない。
・どこまで実行できているかprintf関数を使って調べたところ、最初のwhile文は通り抜けているが、その次のifで通り抜けるものがほぼない。

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

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

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

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

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

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

y_waiwai

2021/07/12 15:03

なにをしてる(つもりの)コードなのか詳しく説明しましょう
itagagaki

2021/07/12 15:05

そのコードでどうして50個できるはずなのか説明できますか?
jimbe

2021/07/12 15:10

> その次のifで通り抜けるものがほぼない 通り抜けるはずなのに無いということであれば、なぜ抜けないのかをお調べになるしかないでしょう。 bytes の中はどのような値になっているのかや、 fread で読み込む際のファイルポインタの位置が想定通りなのか等は printf で確認されたのでしょうか。
masamuneyuya

2021/07/12 15:14

cs50という講座の課題です。その課題にjpgファイルが50個できると記載されておりました。 その際の実行コードは./recover card.raw です。(コンパイル済み) https://cs50.jp/x/2021/week4/problem-set/recover/ まず最初の方は正しいコマンドライン引数がなかった場合、ファイルが正しくなかった場合は弾いています。 BYTE bytes[4]以降は配列を作成し、freadで読み取れた場合にはif文で16進数でjpegファイルかどうかを判定しています。その後新しいファイルの名前をfile_name関数で決定し、fopenで新規ファイルを作成しています。do-while文では次のjpegファイルが見つかるまで512ブロックを読み取り続けているつもりです。
jimbe

2021/07/12 15:34

> fread(bytes, sizeof(BYTE), 4, file); で jpeg の署名の 4 バイトを読む前に、 > while (fread(&buffer, sizeof(BYTE), 1, file)) の fread で 1バイト読んでしまっているのではないでしょうか。
jimbe

2021/07/12 19:10

file_name 関数は恐らく期待通りには動かないと思います。 (s)printf のフォーマットには指定桁数で右詰め"0"埋めする書き方がありますので、お調べになっては如何でしょうか。 > do-while文では次のjpegファイルが見つかるまで512ブロックを読み取り続けているつもり fwrite しかありませんが。
dodox86

2021/07/13 00:02

この質問を読む第三者への質問の背景の説明が足りない(その課題の文を読まないと分からない)です。その課題に含まれている、ダウンロード可能なデータファイル card.rawを実行ファイルrecoverで処理すると、50個のファイルができるはず、と説明されています。
guest

回答2

0

ベストアンサー

50個のjpegファイルが生成されるはず

だって、「そんなはずない」プログラムなのだから。あなたの期待は期待。プログラムの動作は動作。期待の通りになる「はず」と思いこんでいるとプログラムの間違いは見つかりません。
古人曰く「プログラムは思ったとおりには動かない。ソースコードに書いてあるとおりに動く」。

FILE *file = fopen(argv[1],"r");
jpegファイルを開きました。
while (fread(&buffer, sizeof(BYTE), 1, file))
1バイト目を読み込みました。jpegデータならきっと0xffがbufferに1byte読み込まれるのでしょう。freadは読み込んだバイト数1を返すので、whileループの中に入ります。
fread(bytes, sizeof(BYTE), 4, file);
jpegファイルの2~5バイト目をbytesに読み込みます。jpegファイルなら、'd8','ff','e0'とあとデータの最初の1byteですから、
if (bytes[0] == 0xff && bytes[1] == 0xd8 && bytes[2] == 0xff && (bytes[3] & 0xf0) == 0xe0)
このif文は必ず偽になりますね。
再びwhile文に戻って、
while (fread(&buffer, sizeof(BYTE), 1, file))
jpegファイルの6バイト目を読み込みます。まぁ、jpegならそんなに短くないでしょうから読み込めるでしょう。
fread(bytes, sizeof(BYTE), 4, file);
jpegファイルの7~10バイト目をbytesに読み込みます。データはなんでしょうね? ファイルによりますが、
if (bytes[0] == 0xff && bytes[1] == 0xd8 && bytes[2] == 0xff && (bytes[3] & 0xf0) == 0xe0)
このif文は多分偽になりますね。もしかして、偶然にそのパターンに一致することはあるかも知れません。

以下続く。

ちゃんと見てませんが、ほかもいろいろ怪しい気がします...というか間違っています。まぁ、そちらは順次頑張って解決してください。

投稿2021/07/13 00:01

thkana

総合スコア7703

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

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

0

while (fread(&buffer, sizeof(BYTE), 1, file))

1バイトしか読み込んでないですが、そんでいいんでしょうか


while (fread(&buffer, sizeof(BYTE), 1, file))

{ fread(bytes, sizeof(BYTE), 4, file);

1バイト読み捨てたあと4バイト読み込んでます。
つまりは5バイト読み込んでますがこれでいいんでしょうか。

投稿2021/07/12 14:59

編集2021/07/12 15:28
y_waiwai

総合スコア88042

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問