- 締切済み
動的メモリの初期化方法について。
char *p = new char[SIZE]; 上記の方法で動的メモリを確保した場合 確保したメモリの初期化は、 memset(p, 0x00, SIZE); のほかに方法はありますでしょうか? 個人的にSIZEを指定してしまうのがキレイではないような気がしています。 memset(p, 0x00, sizeof(p)); では、sizeof(p)はchar* のサイズなので正しく初期化できず、 for (int i = 0; i < SIZE; i++){ memset(p[i], 0x00, sizeof(p[i])); } では、コンパイルエラーが出てしまいます。 (new char[SIZE]で確保した場合には、p[i]のように配列としてアクセスできないのでしょうか? 単にchar p[SIZE]の場合には、当然配列としてアクセスできるのに。。。) 一般的な初期化方法のほかにも何かコメントでも良いので経験あるかたいらっしゃいましたら教えてください。 宜しくお願いいたします。
- みんなの回答 (7)
- 専門家の回答
みんなの回答
- jacta
- ベストアンサー率26% (845/3158)
char *p = new char[SIZE]; で確保した領域を memset( p, 0, 何らかのサイズ ); としても危険はありません。 処理系にも依存しません。 これは配列の要素が汎整数型だからです。 非POD型の場合は危険ですし、POD型の場合でも、ポインタ型や浮動小数点型、またはそれらを含む集成体の場合も安全とはいえません。 型によって、安全であったり、そうでなかったりするので、よく分からないならmemsetは使わない方が無難です。 最低限std::fill_nを使うようにしましょう。 なお、もっとも安全なのは、そもそもnewを使うのはやめてstd::vectorにすることです。std::vectorを使えば、SIZEを持ちまわってどうこうという問題もなくなります。
- yphkz4063
- ベストアンサー率23% (34/144)
リクツを言えば、 char *p = new char[SIZE]; で確保した領域を memset( p, 0, 何らかのサイズ ); とするのは、こわいです。 処理系が変われば、どのような結果になるかわかりません。 率直に for( i = 0; i < SIZE; i++ ) p[ i ] = 0; なら、間違いありません。
お礼
>memset( p, 0, 何らかのサイズ ); >とするのは、こわいです。 確かにご指摘のとおり、 "何らかのサイズ"によっては 簡単にオーバーフローしますね。 ご指摘ありがとうございます。
- aris-wiz
- ベストアンサー率38% (96/252)
> 個人的にSIZEを指定してしまうのが > キレイではないような気がしています。 なぜですか? 確保したSIZE分クリアしなければならないのだから、 SIZEを渡すことはむしろ当然のことと思いますが? >memset(p[i], 0x00, sizeof(p[i])); 既に出ていますが、p[i]はポインタ型では有りません。 上記はchar1個に対してmemsetを呼び出す大変無駄なコードです。 こんなことをするくらいなら p[i] = 0;の方が遥かにましでしょう。 まずは、char p[SIZE];で宣言されたpと char* p;で宣言されたpの違いを理解してください。 前者の型は char[SIZE]型のpで、後者はchar*型のpです。 故に前者でのsizeof(p)はchar[SIZE]分のサイズなのに対し 後者のpではchar*分のサイズとなります。 C言語上では配列の先頭は暗黙の変換によりchar*となりますが、 関数呼び出しなどで渡された物を除き、宣言されたスコープの中では 宣言された型を保持します。 今回はC++なのかnewが使われていますが、 C言語であれば、確保した領域の0クリアが保障されている callocなどもあります。
お礼
>SIZEを渡すことはむしろ当然のことと思いますが? 初心者ながらsizeof(...)で指定できたほうがコード修正が楽になる場合もあると思い、何か方法があれば。。。という気持ちで質問させていただきました。 >前者の型は char[SIZE]型のpで、後者はchar*型のpです。 >故に前者でのsizeof(p)はchar[SIZE]分のサイズなのに対し >後者のpではchar*分のサイズとなります。 理解していたはずなのですが、この説明はすごくわかりやすいです! char[SIZE]型であると理解できれば当然のことですね。 根本的な考え方が間違っていたんですね。 ご指摘、有難うございます。
- D-Matsu
- ベストアンサー率45% (1080/2394)
> for (int i = 0; i < SIZE; i++){ > memset(p[i], 0x00, sizeof(p[i])); > } > では、コンパイルエラーが出てしまいます。 p[i]がポインタではないので第一引数でargument mismatchを起してるだけでしょう。 &p[i]でないと。
お礼
少し混乱してました。 ご指摘いただいたとおりの方法で問題ありませんでした(汗) 有難うございます。
- Lchan0211
- ベストアンサー率64% (239/371)
pがchar*型である限り、それが指している領域のサイズは コンパイラにはわからないので、初期化時にSIZEを再指定する しかないでしょう。 stdライブラリが使えないのであれば、 次のようにchar[SIZE]をクラス化してしまう 手もあると思います。 class char_array{ public: char_array() {memset(c,0,sizeof(c));} char c[SIZE]; }; char_array *p = new char_array();
お礼
よく分かりました! クラス化してしまいコードを簡略化してしまう方法ですね。 有難うございます。
- jacta
- ベストアンサー率26% (845/3158)
newを使って配列を直接割付けなければならない理由があるのでしょうか? 特別な理由がなければstd::vectorを使う方が得策です。 コンパイラが古いとか、Embedded C++だとか、フリースタンディング環境だとか、その他諸々の組込み向けの方言だとかであれば仕方ないでしょうが...
お礼
vector<char> p(SIZE);ですね。 初心者なので教えてほしいのですが、1つの文字列のための領域を確保するときにでも普通はあまりnewは利用しないのでしょうか? 明示的にdelete操作できるのがnewの良さかなと思っていたのですがそういったことは経験上なかったでしょうか?(回答を拝見するとなさそうですが。。。)
- koko_u_
- ベストアンサー率18% (459/2509)
>のほかに方法はありますでしょうか? std::fill_n()
お礼
ご回答ありがとうございます。 試してみます!
お礼
>memset( p, 0, 何らかのサイズ ); >としても危険はありません。 "何らかのサイズ"がSIZE以上の場合には 危険ではないでしょうか? >std::vectorを使えば、SIZEを持ちまわってどうこうという問題もなくなります。 vectorの場合は生成と同時に初期化されるということですね。