memset()は欠点があるみたいな話を聞いたことがあったので、「あーじゃ要らない機能なんだー。。」
くらいに思っていた。
今回、TopCoder editorialに投稿された解答がmemset()、memcpy()を使っていたので改めて勉強しなおした。
これは、なかなか使えそう。。。
まずは、memset()について見てみよう。
ここで問題!あなたは普段、配列を初期化する時どうしていますか?
ちなみに、宣言時にすべての要素を0に初期化する場合は、これでOKです。(disp()は確認用に標準出力へ出力するためのコードです。以下同様。)
#define forf(i, n) for(int i=0; i<(int)(n); i++)
#define disp(x) cout << #x << " : " << x << endl
using namespace std;
int main () {
int x[10] = {0};
forf(i, 10)
disp(x[i]);
return 0;
}
これは、まだ楽ですね。
じゃあ、宣言した後で、初期化するときは?
int main () {
int x[10];
forf(i, 10)
x[i] = 0;
forf(i, 10)
disp(x[i]);
return 0;
}
上記のようにやってる人。。。ちょっと面倒臭くないですか?
これを解決してくれるのがmemset()です。
int main () {
int x[10];
memset(x, 0, sizeof(x));
forf(i, 10)
disp(x[i]);
return 0;
}
さてさて、では0ではなく1に初期化するときは?
int main () {
int x[10];
memset(x, 1, sizeof(x));
forf(i, 10)
disp(x[i]);
return 0;
}
と思いきや、これを実行すると、16843009に初期化されてしまいます。ちょっと考えてみて気付きました。
16843009 = 1 + 2^{8} + 2^{16} + 3^{24}
なるほど、配列の要素を初期化するのではなく、メモリを1byte単位で初期化してるのね。。。うちのマシーンは、intが32bit(= 4 byte)なので、0x01010101に初期化されていたということです。
なるほど。。。
つなりこのmemset()という関数は、変数のサイズが1byteであるcharに使うってのが最も基本的な関数なようですね。。そうか!この要件を担保するためにcharのサイズは環境依存なしの1byteなのか!!(個人的な予想。。)
っと、ちょっと話が脱線しましたかね。
ではmemset()のさらに便利な使い方を。。2次元配列の初期化2重ループでやってませんか?そうです。これでイケちゃいます!!
int main () {
int x[10][10];
memset(x, 0, sizeof(x));
forf(i, 10)
forf(j, 10)
disp(x[i][j]);
return 0;
}
これでmemset()の便利さは分かりましたね!
さて、次はmemcpy()。細かい事はここまで読んでくれた人なら、多分分かってくれるはず。
memcpy()を使えば、以下のようにして2次元配列のコピーが可能です!
int main () {
int x[3][3];
int y[3][3] = {{1,2,3}, {4,5,6}, {7,8,9}};
memcpy(x, y, sizeof(y));
forf(i, 3)
forf(j, 3)
disp(x[i][j]);
return 0;
}
ちなみにmemcpy()の第3引数では、コピー元から何バイト分だけコピー先へコピーするかを指定します。
さー、ここまで来て、memset()、memcpy()はどうやらかなり出来るヤツらしいということが判明しました。では、これらの関数の欠点って何??
ちょっとネットで調べましたが、よさそうなページは見つけられませんでした。
自分なりに考えてみましたが、この問題点は、先に説明した1で初期化するつもりが0x01010101で初期化されるってことに関係してる気がします。
私が言いたいのは、intのサイズが32bitのマシンで意図的に配列の要素が0x01010101に初期化されるようなコードを書いた時に、これを16bitのマシンに移植すると、0x0101に初期化されることになる。
これが問題なのではないかな~~。と。。
自分ひとりで開発するなら問題ないけど、複数チームで複数環境で開発なんてやってるときに、この辺りを理解せずにむやみやたらにmemset()を使ってたら危険だぞ!ってことですね。
他に何か欠点をご存知の方いらっしゃいましたら、是非是非コメント頂ければ。。
0 件のコメント:
コメントを投稿