45章 コマンドライン引数を受け取る

http://www.geocities.jp/ky_webid/c/045.html

とうとうこの話まできました。

これでようやくコマンドラインからの起動時に引数を指定できるプログラムを作れそうです。

問題1

コマンドライン引数によって指定されたテキストファイルの内容を、画面に表示させるプログラムを作って下さい。

ファイルの読み込みはfopenですね。やってみます。

int main (int argc, char *argv[]) {
    char *file;
    char str[81];
    FILE *fp;
    
    if ( argc == 1 ) {
        puts("ファイル名を指定してください");
        return 1;
    }
    
    file = argv[1];
    
    fp = fopen(file,"r");
    if ( fp == NULL ) {
        puts("file open error");
        return 1;
    }
    
    while(1){
        fgets(str,sizeof(str),fp);
        if ( feof(fp) ) break;
        
        printf("%s",str);
    }
    
    fclose(fp);
    return 0;
}
$ main
ファイル名を指定してください

$ main main.c
(main.cの内容が出力される)

$ main hoge.txt
file open error

argvの0番目の要素にはプログラムのファイル名が入ってるので1番目の要素を参照しないといけないので注意が必要です。

答え合わせ

fgetcを使って一文字ずつ読み込んでますね。

いつも思うのですが、fgetcとfgetsではどちらの方が良く使うんでしょうか?解答例を見てるといつもfgetcを使ってるように思えます。

一気に読み込むよりも一つずつ読み込んだ方が効率が良いんでしょうか?ちょっとその辺調べてみる必要がありますね。

問題2

1つ目のコマンドライン引数で指定されたファイルを、2つ目のコマンドライン引数で指定された名前のファイルにコピーするプログラムを作って下さい。

問題1の拡張版ですね。やってみますね。

int main (int argc, char *argv[]) {
    char *file, *out;
    char str[81];
    FILE *fp,*fp2;
    
    if ( argc != 3 ) {
        puts("ファイル名を二つ指定してください");
        return 1;
    }
    
    file = argv[1];
    out  = argv[2];
    
    fp = fopen(file,"r");
    if ( fp == NULL ) {
        printf("%s open error",file);
        return 1;
    }
    
    fp2 = fopen(out,"w");
    if ( fp2 == NULL ) {
        printf("%s open error",out);
        fclose(fp);
        return 1;
    }
    
    while(1){
        fgets(str,sizeof(str),fp);
        if ( feof(fp) ) break;
        
        fputs(str,fp2);
    }
    
    fclose(fp);
    fclose(fp2);
    return 0;
}

できました。うまくコピーされました。

答え合わせ

やはりfgetc、fputcを使って処理してますね。問題そのものは正解でした。

ひとつ気になった部分があるのですが、解答例では二つ目のファイルオープンに失敗した場合、一つ目のファイルポインタを閉じていませんね。これってまずいような気がするのですが、大丈夫でしょうか。

問題3

コマンドライン引数で渡された数値を、全て加算した結果を画面に表示させるプログラムを作って下さい。コマンドライン引数の個数は幾つか決められていません。

面白そうです。

int main (int argc, char *argv[]){
    int total = 0;
    
    argv++; // ファイル名は使わないので一つ進める
    
    while(--argc){
        total += atoi(*argv);
        argv++;
    }
    
    printf("合計は %d です\n",total);
    return 0;
}
$ main
合計は 0 です

$ main 10
合計は 10 です

$ main 10 30
合計は 40 です

$ main 10 30 44
合計は 84 です

できました。

コマンドラインから引数を渡せるっていうのは何だか楽しいですね。

色々やりたいことが実現できそうで凄く面白いです。もっと色んな処理を書きたいですね。

答え合わせ

解答例ではwhileではなくてforでやっていました。これは実装方法としてどちらでもいいのかなという気はします。