これまでのあらすじ
前々回の日記: Joel on Software を紙で読んでいた。その中の「ゲリラ的雇用面接のすすめ」にて出されていた試験例題「C言語の文字列をその場で逆にする」に挑戦した。
前回の日記:文字列長が INT 型の最大値に依存しなくなった。
今回の記事はその改善。
C 言語で文字列を逆にする
strrev.c
// 文字列を逆にする
// どうせなら string.h なしで
#include <stdio.h>
// 文字列を逆順にする
void strrev(char s[]){
char temp = '\0';
char *first = s;
char *last = s;
// 長さ0の文字列なら操作せず返す
if(*first == '\0'){ return; }
// 文字列の最後の文字のポインタを取得する
while( *(last+1) != '\0'){ last++; }
// 外側から逆にする
while(first < last){
temp = *first;
*first = *last;
*last = temp;
// 一つずつ範囲を小さくする
first++;
last--;
}
return;
}
// a.out の後に続く文字列を操作する
int main(int argc, char* argv[]){
char *s = argv[1];
// 引数が足りないなら比較しない
if(argc <= 1){ return 0; }
// 操作前
printf("Input: %s\n", s);
// 文字列を逆にする
strrev(s);
// 操作後
printf("Output: %s\n", s);
return 0;
}
実行結果はこちら
$ ./a.out a
Input: a
Output: a
$ ./a.out ab
Input: ab
Output: ba
$ ./a.out abc
Input: abc
Output: cba
$ ./a.out abcd
Input: abcd
Output: dcba
$ ./a.out what_a_wonderfull_world!
Input: what_a_wonderfull_world!
Output: !dlrow_llufrednow_a_tahw
前回からの改善点
ポインタ演算の比較を改善した。
完全一致を条件にするのではなく、大小を比較するようにした。
ポインタでもアドレスの大小を比較することはできる。同じ配列のどこかを指しているポインタ同士なら、その場所が配列上での前か後ろかで比較する。
(先頭からのオフセット値を比較している?)
とても基本的な改善。そもそも最初からこのように書いておけば、最初のバージョンのデバッグに30分近く取られることはなかった。
しかも当時、ぼんやりと、面倒くさいし == でいいや、とか考えていた気がする。
バグは油断したところにすかさず潜り込んでくる。
そんなことを感じました。おわり。
追記2014/07/12:
ループ途中の break 文を消した。動作は変わらず。
これもポインタでの大小比較ができるようになった恩恵。