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

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

ただいまの
回答率

91.35%

  • C

    2524questions

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

  • C++

    2410questions

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

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

解決済

回答 2

投稿 2017/12/03 13:41 ・編集 2017/12/03 13:47

  • 評価
  • クリップ 0
  • VIEW 140

strike1217

score 479

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

#include<stdio.h>

#define BSIZE 1024

int main(int argc, char* argv[]){
    int n;
    FILE *src, *dst;
    unsigned char buf[BSIZE];

    if(argc != 3){
        fprintf(stderr, "パラメータが不正です。\n");
    } else {
        if((src = fopen(*++argv, "rb")) == NULL){
            fprintf(stderr, "ファイル%sをオープンできませんでした。\n", *argv);
            return 1;
        } else if((dst = fopen(*++argv, "wb")) == NULL){
            fprintf(stderr, "ファイル%sをオープンできませんでした。\n", *argv);
            fclose(src);
            return 1;
        } else {
            while((n = fread(buf, sizeof(unsigned char), BSIZE, src)) > 0){
                fprintf(stderr, "n = %d\n", n);
                fwrite(buf, sizeof(unsigned char), n, dst);
            }
            fclose(src);
            fclose(dst);
        }
    }

    return 0;
}

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

 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 です。
皆さんの環境では、どうなりますかね?
正常に動作しますか??

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

+2

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

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


ちなみに、動かす方法

  • BSIZE を 1にする事で(偶然)動く
  • 多分本来コレを書くつもりだった
 while((n = fread(buf, 1, BSIZE, src)) > 0){
                fprintf(stderr, "n = %d\n", n);
                fwrite(buf, n, 1, dst);
            }

投稿 2017/12/03 14:57

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/12/03 17:16

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

    キャンセル

  • 2017/12/03 17:22 編集

    バイナリは数字が連続しているので 第2パラメータに1024Bを入れると 1024B分取ってくるという意味ではないのですか?

    それだと、
    fread(buf, 1, BSIZE, src);
    fread(buf, BSIZE, 1, src);

    何が違うんですかね?
    上は1Bを 1024個
    下は1024Bを1個ですよね?

    結局同じような気するんですが・・・

    キャンセル

  • 2017/12/03 18:13

    >16進数は2桁で1Bですよね
    1バイトは8bitですから16進数2桁で表わせますが逆が常に正しいかというと
    …どれだけ相手が意地悪な人かで変わってきそうです
    ちなみに私なんぞは生粋の天邪鬼なので、"3F"(文字列)や、(int)0x3Fなどを考えてしまいます。

    > この関数、第二パラメータを1以外にする場面ってあるんでしょうか?
    構造体の配列等を扱うときにはちょっと楽できます
    歴史的な経緯があるのかもしれませんが

    > 何が違うんですかね?
    その後のfwrite(buf, n, 1, dst);でfwrite(buf,1,1,dst);になって1byteしか書き出していません

    キャンセル

  • 2017/12/03 21:28 編集

    fwriteで1Bしか書き出していないのはわかるのですが・・・

    ん?
    ちょっとまってください。
    なんでループは一回で終わっているんですかね?

    キャンセル

checkベストアンサー

+1

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

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

投稿 2017/12/03 17:53

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/12/03 21:29

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

    キャンセル

  • 2017/12/03 21:35

    ああ・・・できました。
    freadの方は2つとも問題ないようですね。

    fwrite()の方に問題があったということですね。

    while文の継続条件は、n > 0 ですが、なんでfwrite()修正するとちゃんとループするんでしょうか??

    fwrite()は変数nに影響を与えていませんよね??
    なんでループが1回で終了してしまうんでしょうか?

    キャンセル

  • 2017/12/03 21:40

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

    キャンセル

  • 2017/12/03 21:41

    確かに、その通りです。
    しかし、試したのはELF実行ファイルで1024Bよりも大きいです。

    なんででしょうかね・・・?

    キャンセル

  • 2017/12/03 21:54

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

    キャンセル

  • 2017/12/03 22:00 編集

    fread(buf, BSIZE, 1, src)
    fread(buf, sizeof(unsigned char),BSIZE,src);

    この2つは、結局は同じ。
    fwrite() についても理解できました。

    ループが謎すぎます。><

    キャンセル

  • 2017/12/03 21:57

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

    キャンセル

  • 2017/12/03 21:58

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

    キャンセル

  • 2017/12/03 22:10 編集

    返り値とはfread()の返り値のことですよね?
    あ、確かに、そうですね。

    というより、再度異常のあるコードをコンパイルしたら、ループしました。

    .....??? 再度コンパイルするとできるようになるという現象がよく起きるんですよね。
    なんですかね・・・これ・・・
    (この問題については、再度質問するかもしれません。gccのバグでしょうかね?)

    fwrite() はどの道間違っていましたね。
    とりあえず、fread() と fwrite() が分かったので、ベストアンサーにさせてもらいます。

    キャンセル

  • 2017/12/03 22:12

    > 再度コンパイルするとできるようになるという現象がよく起きるんですよね。
    > なんですかね

    それは気のせいで、コンパイルがミスっているでしょう。
    1つ前のソースが動いていたとか。

    キャンセル

  • 2017/12/03 23:24

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

    キャンセル

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

ただいまの回答率

91.35%

関連した質問

同じタグがついた質問を見る

  • C

    2524questions

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

  • C++

    2410questions

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