« 反逆を編集したかった(BlogPet) | トップページ | ソーシャルブックマーク管理ツール bookey 0.55c版 ― 「del.icio.us」関連、同期処理回りの修正を実施 »
2008.05.31
Re: Cのかきかた
外で晩飯を食べているときに、Twitter で、以下の発言を見かけました。
C書ける人教えてください:) http://generation1986.g.hatena.ne.jp/yaotti/20080530/1212157373
Twitter / やおっち: C書ける人教えてください:) http://gener...
これは、おもしろそう。帰ったら反応しよう。ってことで、この記事を書いています。
とりあえず動くんだけど妥当な書き方なのかわからんので貼ってみる。
「ここ変な書き方してるよ!!」とか突っ込み入れてもらえると嬉しいです。(略)
Cのかきかた - yaottiの日記 - ハチロク世代K&R 3-2
改行文字やタブ文字を\nや\tという文字そのものに変えてコピーする関数escape(s, t)を書け
すでに多くの人が反応しているようですが、私も反応してみます。
とりあえず、自分で書いてみたコードを貼り付けておきます。
/*
* K&R 3-2
* 改行文字やタブ文字を\nや\tという文字そのものに変えてコピーする関数
* escape(s, t)を書け
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *
escape(char *dst, const char *src)
{
char *s = dst;
while ( *src ) {
if ( *src == '\n' ) {
*dst++ = '\\';
*dst++ = 'n';
}
else if ( *src == '\t' ) {
*dst++ = '\\';
*dst++ = 't';
}
else
*dst++ = *src;
src++;
}
*dst = '\0';
return ( s );
}
int
test(const char *targetString)
{
char *result = NULL;
size_t sz;
int ret = 0;
sz = strlen(targetString) * 2 + 1;
result = (char *)malloc( sz );
if ( result ) {
memset( result, 0, sz );
escape( result, targetString );
printf( "<<%s>> -> <<%s>>\n", targetString, result );
ret++;
free( result );
}
return ( ret );
}
int
main( int argc, char *argv[] )
{
const char *testString1 = "1234\t567890\nabcdefg";
const char *testString2 = "1234\t\t\t\n567890\n\t\tabcd\nefg\t";
int ret = 0;
ret += test( testString1 );
ret += test( testString2 );
return ( ret );
}
char *escape(char *dst, const char *src) が本体(今回、作成する関数)で、その後ろに書いてあるのが、テスト用のコードです。テスト用のコードとセットで用意しておいて、あとで、テスト用のコードを削除するか、コメントアウトするか、#if 0 ~ #endif で囲ったりして、リリースすることになります。
で、yaottiさんのコードを見てみる。私の書いた escape() とソース(コピー元)、ディスティネーション(コピー先)が逆になってるし、リターン値の方も違ってるけど、それはいいとして。
気になるのは main() の
while((s[i++] = getchar()) != EOF)
;
if(!escape(s, t))
printf("the length of first arg is too long!!\n");
for (i = 0; t[i] != EOF; ++i)
printf("%c",t[i]);
最初の EOF はいいとして、2つ目の EOF、何でこんなところで出てくるのかな? 文字列の終端は通常は '\0' です。EOF がたまたま 0 である処理系もあるけど、-1 とか、0 じゃない処理系もあります。このままだと、メモリ参照エラーで落ちてしまうかも。
あと、escape() の引数は int [] よりも char * の方がいいかも。コピー元は const で修飾しておいた方が安心。 const をつけておくと、何気にコピー元を破壊するコードを書いてしまってもコンパイル時にエラーになるので、バグを見つけやすくなります(といっても、コンパイラでもチェックできないような破壊の仕方をするコードを書いちゃうと、チェックできないですけどね)。
とりあえず、こんな感じかな。あとは他の人がすでに書いてるし。
追記
格納する変数はintではなくcharで。
書き直し - yaottiの日記 - ハチロク世代
K&Rは今のとこ全部intで処理してるな…なんでだろ。
これは getchar() のリターン値が int なのと関係があります。今は、int といえば、32ビットか64ビットであることが多いですが、むかしは16ビットだったり、8ビットだったりした環境もあるんですよ(int が16ビットな環境は今でもあります)。int は char よりビット数が多いか、最悪でも同じビット数であることが保証されるので、int を使っておけば、汎用的かも、ってことですね。こわがりすぎ。
追記 2
今時は,バッファオーバーフロー,つまり文字列のあらかじめ意図した範囲を越えて書き換えてしまうような関数は危険とみなされる.こんなご時世では,いくらK&Rの課題とはいっても,実際にやるんだったら,せめてコピー先の文字列の最大長を与えてやらないといけないような課題にすべきだろうと思う.
Cでバッファオーバーフローを起こさせないためのちょっとした工夫 - jj1bdx: life beyond Japan
ここまでやるなら strlcpy() を紹介しておくべきだ,という意見があったので,関数の名前だけ書いておく.この関数はOpenBSDに始まり多くの環境で使えるが,すべての環境で実装されているわけではない.
Cでバッファオーバーフローを起こさせないためのちょっとした工夫 - jj1bdx: life beyond Japan
ちなみに、Visual C++ (8以降) では、strcpy_s() のような _s 付きの関数が対応します。Visual C++ 6 用に書いたコードを Visual C++ 8 (Visual Studio 2005)でコンパイルしようとすると C4996 の警告(warning)が出ることがありますが、この警告が出た場合は、_s 付きの関数を使って書き直すか、バッファオーバーフロー対策を自前で行なうか、する必要があります。printf 系の関数にも _s 付きの関数が用意されています。 (関連: 「Visual Studio 2005 Beta2 の評価中 - warning C4996 の件」)
投稿者: tsupo 2008.05.31 午前 03:15
| 固定リンク
|
|
| ![]()
|
|
アマゾンわくわく探検隊
トラックバック
この記事のトラックバックURL:
この記事へのトラックバック一覧です: Re: Cのかきかた:



