Visual C++ 6.0 にて

LPSTR pszTmp = (LPSTR ) new char [ 1];

strcpy(pszTmp,”A”);
delete[] pszTmp;

とすると
CheckBytes(pbData(pHead) + pHead->nDataSize, _bNoMansLandFill, nNoMansLandSize

でアサートとなります。

LPSTR pszTmp = (LPSTR ) new char [ 2];

とすると正常にdeleteが走りますが。
何故文字数+1とする必要があるのでしょうか?

回答の条件
  • URL必須
  • 1人2回まで
  • 登録:2005/03/18 13:41:44
  • 終了:--

回答(4件)

id:taknt No.1

きゃづみぃ回答回数13539ベストアンサー獲得回数11982005/03/18 13:44:17

C言語では 文字列は ヌルで終わる決まりになっています。

ヌルというのは 0 です。

なので1文字分、余計に宣言しないとダメなのです。

id:TONTON3

それは解りますが NULL を入れないとdelete できないのが何故なのか理解できないんです。

2005/03/18 13:57:54
id:EddyYamanaka No.2

EddyYamanaka回答回数385ベストアンサー獲得回数12005/03/18 13:58:20

ポイント20pt

http://www.hatena.ne.jp/1111120904

人力検索はてな - Visual C++ 6.0 にて LPSTR pszTmp = (LPSTR ) new char [ 1]; strcpy(pszTmp,”A”); delete[] pszTmp; とすると CheckBytes(pbData(pHead) + pHead->nDataSize, _bNoMans..

strcpy()にて確保したデータエリアを越えた場所にターミネータを書き込んだため、new/deleteで使用する管理エリアを破壊したのでしょう。

id:TONTON3

ただ単に

*pszTmp =’A’;

としても同じくアサートです。

どうしてなんだろ

としただけでもアサートになります。

この場合も +1 をすれば問題ないのですが

2005/03/18 14:04:59
id:EddyYamanaka No.3

EddyYamanaka回答回数385ベストアンサー獲得回数12005/03/18 14:12:18

『*pszTmp = ’A’;』を試してみましたが、こちらはエラーになりませんけど?

id:TONTON3

いや、なりますよー だめです。

VC6.0 がへぼいのかな

LPSTR pszTmp = (LPSTR ) new char [ 1];

*pszTmp = ’A’;

delete[] pszTmp;

ですよ?

2005/03/18 14:15:12
id:aki73ix No.4

aki73ix回答回数5224ベストアンサー獲得回数272005/03/18 15:14:40

ポイント50pt

strcpy(pszTmp,”A”)の場合は

”A¥000”の2バイトがpszTmpに上書きされるので、問題が発生します

memcpy(pszTmp,”A”,1)の場合は問題ないはずなので、普通は

LPSTR pszTmp = (LPSTR ) new char [ 1];

*pszTmp = ’A’;

delete[] pszTmp;

でもエラーになりませんね

理由は、変数領域には干渉しないからです

これでエラーが出る理由ですが、デバッガによっては LPSTRは文字列型変数なのでチェック時にNULLが含まれていないとASSERTを返すものがあるようです

だから・・・

strcpy(pszTmp,”¥000”);や

*pszTmp=”¥000”;

とした場合は発生しませんよね

でも、本来LPSTR は CHAR*と定義されてるのでメモリ領域の char と考えればエラーは起こらないような気も・・・

char *pszTmp=new char[1];

unsigned char *pszTmp=new unsigned char[1];

などと定義した場合は、また結果が変わってくるかもしれませんね

id:TONTON3

すいません、もう一回やってみたらエラーになりませんでした。

はい、aki73ixさんのおっしゃるとおりと思います。ありがとうございました。

2005/03/18 15:19:18
  • id:cx20
    参考情報

    一応、説明を書いたので貼っておきます。

    ----------------------------------------------------------------
    C/C++ の文字列は NULL 文字(’¥0’)で終わる決まりです。
    ”A” という文字列は、実際には [41][00](0x41 … ’A’, 0x00 … ’¥0’)
    という2バイトで表現されます。

    > 何故文字数+1とする必要があるのでしょうか?

    したがって、この2バイトをコピーするには、
    2バイト分のメモリを確保する必要があります。

    また、VC++ で delete 時にアサートする原因ですが、
    VC++ のデバッグ版では new したメモリ領域の前後に
    「NoMansLand (0xFD)」と呼ばれるバッファが4バイト書き込まれます。
    (初期化されていないメモリ領域には 0xCD が書き込まれます。)
    これは、ユーザーがメモリブロックの境界を上書きしていないかを
    検出するための仕組みです。

    以下は、メモリのイメージです。
    (メモリウィンドウは [表示] - [デバッグウィンドウ] - [メモリ] で表示できます。)

    <new したメモリ領域>
    00372F89 00 00 00 01 00 00 00 33 00 00 00 FD FD FD FD .......3.......
    00372F98 CD FD FD FD FD F0 AD BA 0D F0 AD BA 0D F0 AD ヘ....隲コ.隲コ.隲

    <strcpy した結果>
    00372F89 00 00 00 01 00 00 00 33 00 00 00 FD FD FD FD .......3.......
    00372F98 41 00 FD FD FD F0 AD BA 0D F0 AD BA 0D F0 AD A....隲コ.隲コ.隲

    このように、strcpy() は NULL 文字(’¥0’)を含めてコピーを行うため、
    1バイトしか確保されていないメモリ領域に、
    2バイト( 0x41 … ’A’, 0x00 … ’¥0’)を書き込むと、

    |[FD][FD][FD][FD]|[CD]|[FD][FD][FD][FD]|
              ↓
    |[FD][FD][FD][FD]|[41]|[00][FD][FD][FD]|

    というように、new したメモリ領域を超えて、コピー(メモリ領域の破壊)が行われます。

    このとき、デバッグウィンドウには、

    memory check error at 0x00372F99 = 0x00, should be 0xFD.

    と表示されているハズです。

    「0xFD でないといけないところが 0x00 になっていますよ」というエラーです。


    > LPSTR pszTmp = (LPSTR ) new char [1];
    > *pszTmp = ’A’;
    > delete[] pszTmp;

    であれば、エラーは検出されないハズです。
    (少なくとも、自分のところではエラーになりませんでした。)

    <new したメモリ領域>
    00372F89 00 00 00 01 00 00 00 33 00 00 00 FD FD FD FD .......3.......
    00372F98 CD FD FD FD FD F0 AD BA 0D F0 AD BA 0D F0 AD ヘ....隲コ.隲コ.隲

    <*pszTmp = ’A’ した結果>
    00372F89 00 00 00 01 00 00 00 33 00 00 00 FD FD FD FD .......3.......
    00372F98 41 FD FD FD FD F0 AD BA 0D F0 AD BA 0D F0 AD A....隲コ.隲コ.隲

    |[FD][FD][FD][FD]|[CD]|[FD][FD][FD][FD]|
              ↓
    |[FD][FD][FD][FD]|[41]|[FD][FD][FD][FD]|

    もう一度、メモリウィンドウを表示させて、動作を確認してみてください。
    ----------------------------------------------------------------

    <参考情報>
    ■ メモリ管理とデバッグ ヒープ
    http://www.microsoft.com/JAPAN/developer/library/vccore/_core_memory_management_and_the_debug_heap.htm
    ■ バッファ オーバーランを解消せよ!
    http://www.microsoft.com/japan/msdn/columns/secure/secure05202002.asp
  • id:taknt
    すべては

    私がかいたように 文字列の最後は ヌルという決まりが原因ですね。

    というのは理解してもらっているのかなぁ?

    strcpy(pszTmp,”A”);
    とすれば 文字列の領域が 1文字分(ヌル)で 終わっている状態に
    代入することになり、1バイト以上の領域として認識されてしまいます。

    ま、cx20さんが 詳しくかかれてますが、C言語は、メモリのことを配慮しないと暴走するプログラムを作り出してしまいますので、注意が必要です。
  • id:EddyYamanaka
    実際に試してみたのに

    *pszTmp = ’A’;
    がエラーにならないと説明したのは私なのにネ。
    ポイントが貰えなかったのは残念。(;_;)
  • id:TONTON3
    Re:すべては

    説明がたりませんでしたがその点はすでに確認済みの事項でしたので
    申し訳ありませんがポイントはなしとさせていただきました。
  • id:TONTON3
    Re:実際に試してみたのに

    やり直してみたらできてました。申し訳ない
    strcpyが生きていたためエラーになってました。

    かなり正解に近い事項でしたので20ポイントなのですが・・・
    より詳しい解説があったためより納得できたため
    このようなポイント配分とさせていただきました。

この質問への反応(ブックマークコメント)

トラックバック

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません