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

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

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

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

C++

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

Q&A

解決済

2回答

1809閲覧

バイナリーファイルのコピー

strike1217

総合スコア651

C

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

C++

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

0グッド

0クリップ

投稿2017/12/03 04:41

編集2017/12/03 04:47

バイナリーファイルをコピーするプログラムです。
以下は正常に動作したプログラムです。

C

1#include<stdio.h> 2 3#define BSIZE 1024 4 5int main(int argc, char* argv[]){ 6 int n; 7 FILE *src, *dst; 8 unsigned char buf[BSIZE]; 9 10 if(argc != 3){ 11 fprintf(stderr, "パラメータが不正です。\n"); 12 } else { 13 if((src = fopen(*++argv, "rb")) == NULL){ 14 fprintf(stderr, "ファイル%sをオープンできませんでした。\n", *argv); 15 return 1; 16 } else if((dst = fopen(*++argv, "wb")) == NULL){ 17 fprintf(stderr, "ファイル%sをオープンできませんでした。\n", *argv); 18 fclose(src); 19 return 1; 20 } else { 21 while((n = fread(buf, sizeof(unsigned char), BSIZE, src)) > 0){ 22 fprintf(stderr, "n = %d\n", n); 23 fwrite(buf, sizeof(unsigned char), n, dst); 24 } 25 fclose(src); 26 fclose(dst); 27 } 28 } 29 30 return 0; 31} 32

ところが、私が持っている本の中では、コピーを行っている部分が以下のようになっていました。

while((n = fread(buf, BSIZE, 1, src)) > 0){ fprintf(stderr, "n = %d\n", n); fwrite(buf, n, 1, dst); }

最初この通りに作ったのですが、うまく行かなかったので自分で作り変えました。

しかしよく考えると、疑問です。
下の方でも良いような気がします。
なぜ下のやり方ではうまく行かないのでしょうか??
fprintf はテスト用に入れてあります。

下のプログラムを実行すると n = 1と表示されて終わります。
つまりループが一回しか実行されていないことになります。

なんで一回で終わってしまうんでしょうか?
下のやり方ではできない理由を教えてください。

実行環境は Linux 64bit gcc です。
皆さんの環境では、どうなりますかね?
正常に動作しますか??

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

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

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

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

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

guest

回答2

0

freadの扱いが間違ってますね
要素数を返すため、読み取ったバイト数は 第2引数 * 戻り値 です

1が戻った場合はBSIZE1個分読んだよってことです


ちなみに、動かす方法

  • BSIZE を 1にする事で(偶然)動く
  • 多分本来コレを書くつもりだった

c

1 while((n = fread(buf, 1, BSIZE, src)) > 0){ 2 fprintf(stderr, "n = %d\n", n); 3 fwrite(buf, n, 1, dst); 4 }

投稿2017/12/03 05:57

asm

総合スコア15147

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

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

strike1217

2017/12/03 08:16

16進数は2桁で1Bですよね。 この関数、第二パラメータを1以外にする場面ってあるんでしょうか?
strike1217

2017/12/03 08:22 編集

バイナリは数字が連続しているので 第2パラメータに1024Bを入れると 1024B分取ってくるという意味ではないのですか? それだと、 fread(buf, 1, BSIZE, src); fread(buf, BSIZE, 1, src); 何が違うんですかね? 上は1Bを 1024個 下は1024Bを1個ですよね? 結局同じような気するんですが・・・
asm

2017/12/03 09:13

>16進数は2桁で1Bですよね 1バイトは8bitですから16進数2桁で表わせますが逆が常に正しいかというと …どれだけ相手が意地悪な人かで変わってきそうです ちなみに私なんぞは生粋の天邪鬼なので、"3F"(文字列)や、(int)0x3Fなどを考えてしまいます。 > この関数、第二パラメータを1以外にする場面ってあるんでしょうか? 構造体の配列等を扱うときにはちょっと楽できます 歴史的な経緯があるのかもしれませんが > 何が違うんですかね? その後のfwrite(buf, n, 1, dst);でfwrite(buf,1,1,dst);になって1byteしか書き出していません
strike1217

2017/12/03 12:28 編集

fwriteで1Bしか書き出していないのはわかるのですが・・・ ん? ちょっとまってください。 なんでループは一回で終わっているんですかね?
guest

0

ベストアンサー

fwrite(buf, n, 1, dst);が間違ってます。
n*BSIZE*1バイト書かないといけないので、下記のいずれかにする。

C

1fwrite(buf, n, BSIZE, dst); 2fwrite(buf, BSIZE, n, dst); 3fwrite(buf, n*BSIZE, 1, dst);

投稿2017/12/03 08:53

otn

総合スコア84423

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

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

strike1217

2017/12/03 12:29

freadの方は問題がないということでしょうか?
strike1217

2017/12/03 12:35

ああ・・・できました。 freadの方は2つとも問題ないようですね。 fwrite()の方に問題があったということですね。 while文の継続条件は、n > 0 ですが、なんでfwrite()修正するとちゃんとループするんでしょうか?? fwrite()は変数nに影響を与えていませんよね?? なんでループが1回で終了してしまうんでしょうか?
otn

2017/12/03 12:40

ファイルサイズがBSIZE以下だと、ほとんどの場合ループが1回で終わるでしょう。
strike1217

2017/12/03 12:41

確かに、その通りです。 しかし、試したのはELF実行ファイルで1024Bよりも大きいです。 なんででしょうかね・・・?
otn

2017/12/03 12:54

2048B以下だと、2回目のfreadでは0が返りますね。 実際には、1024B未満が読み込まれていますが。
strike1217

2017/12/03 13:00 編集

fread(buf, BSIZE, 1, src) fread(buf, sizeof(unsigned char),BSIZE,src); この2つは、結局は同じ。 fwrite() についても理解できました。 ループが謎すぎます。><
strike1217

2017/12/03 12:57

コピーしたファイルの大きさは、ls -lhで調べてみました。 8.7KBのようですね。
otn

2017/12/03 12:58

返り値が違いますね。返り値は、第二引数サイズの要素の個数なので、0以上第三引数以下です。
strike1217

2017/12/03 13:10 編集

返り値とはfread()の返り値のことですよね? あ、確かに、そうですね。 というより、再度異常のあるコードをコンパイルしたら、ループしました。 .....??? 再度コンパイルするとできるようになるという現象がよく起きるんですよね。 なんですかね・・・これ・・・ (この問題については、再度質問するかもしれません。gccのバグでしょうかね?) fwrite() はどの道間違っていましたね。 とりあえず、fread() と fwrite() が分かったので、ベストアンサーにさせてもらいます。
otn

2017/12/03 13:12

> 再度コンパイルするとできるようになるという現象がよく起きるんですよね。 > なんですかね それは気のせいで、コンパイルがミスっているでしょう。 1つ前のソースが動いていたとか。
strike1217

2017/12/03 14:24

おそらく、私のミスです。 ケアレスミスが多いので、どこかで勘違いを起こしているかもしれません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問