「ふつりな」第6章の練習問題(1)・続
『ふつうのLinuxプログラミング』に入門して、練習問題を解いています。
前回(http://d.hatena.ne.jp/torazuka/20110706/c)解けなかった問題の続き。
問題
タブ文字('\t')を「\t」、改行を「'$'+改行」として出力するcatコマンドを書きなさい。
前回、タブ文字だけまず何とかしようとしたけれど、惜しいところまでキタので、改行も追加。
解答
しかし、まだ正しく動きません。
#include <stdio.h> #include <stdlib.h> #include <string.h> static void do_cat(const char *path); static char *rep_str(char *str, const char *before, const char *after); static void die(const char *s); int main(int argc, char *argv[]) { int i; if(argc < 2){ fprintf(stderr, "%s: file name not given.\n", argv[0]); exit(1); } for(i = 1; i < argc; i++){ do_cat(argv[i]); } return 0; } static void do_cat(const char *path) { FILE *f; char before_t[] = "\t"; char after_t[] = "\\t"; char before_n[] = "\n"; char after_n[] = "$\n"; char buff[256]; f = fopen(path, "r"); if(!f){ die(path); } for(;;){ buff[0] = '\0'; if((fgets(buff, sizeof(buff), f)) == NULL){ break; } rep_str(buff, before_t, after_t); rep_str(buff, before_n, after_n); fprintf(stdout, "%s", buff); } } static char *rep_str(char *str, const char *before, const char *after) { int i; char *result = str; int str_len = strlen(str); int before_len = strlen(before); result[0] = '\0'; for(i = 0; i < str_len; i++){ if(0 == strncmp(&str[i], before, before_len)){ strcat(result, after); i += before_len - 1; } else { strncat(result, &str[i], 1); } } return result; } static void die(const char *s) { perror(s); exit(1); }
実行すると、各行の1文字目が欠けてしまう。
オロロン、オロロン、、、。
わからないこと
なぜ1文字目が欠けるのか。
- do_cat関数の中で、fgets関数を使って読み込んだ時点では、欠けていない
- rep_str関数の中で、strcat(strncat)関数を使って文字列を繋いだ時点で、戻り値が欠けている
最初は、次の初期化方法が間違っているのかと考えました。
result[0] = '\0';
「\0」という1つの要素を持つ文字列配列に対して、2つ目(result[1])の位置から値が繋がれてしまうから、ダメなのか??
しかし、1文字目が欠けることとは無関係な気がする…。そもそも、これは「欠ける」というより、正確には「検索対象文字列の1文字目が繋がれていない」という状態なのでは…。
それに、初期化しないと、do_catでprintf関数で出力したときに、2行ずつ表示されてしまう。オーノー・・・
もうちょっと考えます。
改善したこと
- fgetcで1文字ずつ読み込むのをやめ、fgetsで1行ずつ読み込むことにした
- 戻り値がintからcharになり、変換で悩む必要がなくなった
- 文字列置換については、サンプルを探して参考にした
- C言語入門 13.基本アルゴリズム http://c-production.com/contents/c/sec13.html
- 文字列が一致すれば変換後の文字列を、一致しなければ評価中の文字を、戻り値用の文字列に繋ぐ
- (…という概要は理解しているけれども、中で使ってる関数を正しく理解してないのでは。だから欠けるのでは)