読者です 読者をやめる 読者になる 読者になる

ソフトウェアエンジニア現役続行

雑多なことを綴ります

繰り返し処理には要注意

C言語

プログラミングでメシが食えるか!?―成功するプログラマーの技術と仕事術という本を読みました。軽いタッチの本でスラスラと読める本です。


その中で、読んでいてギクっとしたのが、繰り返し処理に関する記述です。


以下がダメな実装例です。

for (i=0; i


※pppタグは無視してください。はてなダイアリーのバグのようです。

なぜこれがダメかと言うと、for文のループの間、毎回strlen(3)が呼ばれてしまうからです。strlen(3)は文字列の先頭から1文字ずつ終端文字を探していきます。もし文字列strにとても大きな文字列が入っていたら、ものすごいオーバーヘッドが発生してしまいます。


僕もどこかで上記のような実装をしてきたんじゃなかと不安になって、思わず今まで会社で書いたソースコードをstrlenをキーにして探索しました。幸い上記のようなstrlenの使い方はしていませんでしたが、もしかしたら別の関数で同じようなことをやってしまっているかも知れません。。。


正しくは、以下のようにします。

len = strlen (str);
for (i=0; i


※pppタグは無視してください。はてなダイアリーのバグのようです。

プログラミングでメシが食えるか!?―成功するプログラマーの技術と仕事術では他にも、繰り返すごとに処理が遅くなるダメな例を紹介していました。

char getbuf[80], buf[4096];
while (1) {
  if (fgets (getbuf, sizeof (getbuf), stdin) == NULL)
    break;
  strcat (buf, getbuf);
}


strcat(3)も、strlen(3)と同様に、文字列の先頭から終端文字を探していきます。この例では、文字列bufの先頭から終端文字を探し、そこに文字列getbufを連結させます。なので、繰り返すごとに文字列bufが大きくなり、strcat(3)に時間がかかってしまいます。


正しくは以下のようにします。

char getbuf[80], buf[4096];
char *ptr = buf;
while (1) {
  if (fgets (getbuf, sizeof (getbuf), stdin) == NULL)
    break;
  strcpy (ptr, getbuf);
  ptr += strlen (getbuf);
}