char** の new と delete について – プログラミング – Home

通知
すべてクリア

[解決済] char** の new と delete について


佐藤
 佐藤
(@佐藤)
ゲスト
結合: 21年前
投稿: 19
Topic starter  

初めまして。
似たような項目はあったのでですが若干違うので質問させてください。

現在ポインタの勉強をしていて、可変の文字列のソートをやっています。
以下ソースです。

std::string str_line;
std::vector< char* > tmp;
unsigned int g_size;
char** g_container;

// ファイルから1行毎読み込む
while()
{
/* 中略 */

// 登録
char* ch = new char[ str_line.size() ];
strcpy( ch, str_line.c_str() );
tmp.push_back( ch );
}

g_size = static_cast< unsigned int >( tmp.size() );
g_container = new char* [ g_size ];

for( unsigned int i = 0; i < g_size; ++i )
g_container[ i ] = tmp[ i ];
tmp.clear();

// ここにソート関数が入る。swapの所のみ記載
char* tmp = g_container[j];
g_container[j] = g_container[i];
g_container[i] = tmp;

// 解放
for( unsigned int i = 0; i < g_size; ++i )
delete[] g_container[ i ]; // ここで落ちる
delete[] g_container;

丁度 delete[] のところで落ちてしまいます。
配列の確保・解放の仕方はこれであっているのでしょうか?

以上です。宜しくお願いします。

【環境】WinXP VC.net2003


引用未解決
トピックタグ
Blue
 Blue
(@Blue)
ゲスト
結合: 20年前
投稿: 1467
 

> char* ch = new char[ str_line.size() ];
'\0'を含むから、

char* ch = new char[ str_line.size() + 1 ];

では?


返信引用
佐藤
 佐藤
(@佐藤)
ゲスト
結合: 21年前
投稿: 19
Topic starter  

レスありがとうございます。

while の中を省略してしまったのがいけなかったです。
一応'\0'はつけております。

pos は現在の position 。size はファイルサイズです。

while( pos < size )
{
// 1行分をバッファに格納
str_line.clear();
while( ( pos < size ) && ( buf[pos] != '\r' ) && ( buf[pos] != '\n' ) )
{
char c[2] = { buf[pos], '\0' };
str_line.append( c );
++pos;
}
// CR-LFの処理
if( ( pos < size ) && ( buf[pos] == '\r' ) ) ++pos;
if( ( pos < size ) && ( buf[pos] == '\n' ) ) ++pos;

// 登録
char* ch = new char[ str_line.size() ];
strcpy( ch, str_line.c_str() );
tmp.push_back( ch );
}


返信引用
reshia
 reshia
(@reshia)
ゲスト
結合: 20年前
投稿: 117
 

こういうときは、
 new したときに得られた領域のアドレスと
 delete しようとしている領域のアドレスが
一致しているかを調べてみればいいと思います。

具体的には、次のようにprintfを入れます。

// 登録
char* ch = new char[ str_line.size() ];
printf(new : %p\n, ch); // ←追加

// 解放
for( unsigned int i = 0; i < g_size; ++i )
{
printf(del : %p\n, g_container); // ←追加
delete[] g_container[ i ];
}


返信引用
reshia
 reshia
(@reshia)
ゲスト
結合: 20年前
投稿: 117
 

↑間違えた。

間違い:
// 解放
for( unsigned int i = 0; i < g_size; ++i )
{
printf(del : %p\n, g_container); // ←追加
delete[] g_container[ i ];
}

修正:
// 解放
for( unsigned int i = 0; i < g_size; ++i )
{
printf(del : %p\n, g_container[i]); // ←追加
delete[] g_container[ i ];
}


返信引用
佐藤
 佐藤
(@佐藤)
ゲスト
結合: 21年前
投稿: 19
Topic starter  

あああ、Blue様勘違いしておりました。
確かに new char[ str_line.size() + 1 ] でした。

少し試してみます。


返信引用
K
 K
(@K)
ゲスト
結合: 23年前
投稿: 98
 

原因を絞るために、ソート部分をなくして
読み込み -> 解放で落ちないかチェックしてみては?

ポインタの勉強なら仕方ないですが、
パフォーマンスの問題でもない限り、
std::vector<std::string>
が確実だと思います。

ベタでnew, deleteは基本的に使いません。
バグ(の元)ですから。


返信引用
佐藤
 佐藤
(@佐藤)
ゲスト
結合: 21年前
投稿: 19
Topic starter  

reshia様、K様レスありがとうございます。

ソートを切ってポインタの表示をさせてみたのですが
ポインタは同じようでした。(ちなみに赤×メッセージです↓)

DAMAGE : after Normal block (#45) at 0x00370FF0.

>std::vector<std::string>が確実だと思います。

ごもっともです。最初は vector を使用してやっていたのですが
データ数増やしてみたら恐ろしく遅かったので、勉強を兼ねてポインタにした次第であ
ります。

少し試してみます。


返信引用
reshia
 reshia
(@reshia)
ゲスト
結合: 20年前
投稿: 117
 

> DAMAGE : after Normal block (#45) at 0x00370FF0.
これって、確保した領域外にアクセスしてから解放したときにでる・・
こんな↓コードで再現します。

int* arr = new int[10];
for (int i = 0; i <= 10; i++) {
arr[i] = i;
}
delete[] arr;
return 0;


返信引用
reshia
 reshia
(@reshia)
ゲスト
結合: 20年前
投稿: 117
 

>ソートを切ってポインタの表示をさせてみたのですが
>ポインタは同じようでした。(ちなみに赤×メッセージです↓)

ソートが原因だったとしたら、
ソートを切った状態でポインタを・・いやアドレスを表示しても意味がないですよ。


返信引用
佐藤
 佐藤
(@佐藤)
ゲスト
結合: 21年前
投稿: 19
Topic starter  

間違った所がありました。

Blue様のご指摘を受けて修正した箇所を
char* ch = new char[ str_line.size() + 1 ];
strcpy( ch, str_line.c_str() );
// ch[ str_line.size() + 1 ] = '\0'; // ←こうしてました。
ch[ str_line.size() ] = '\0';

修正してみたら落ちなくなりました。


返信引用
佐藤
 佐藤
(@佐藤)
ゲスト
結合: 21年前
投稿: 19
Topic starter  

入れ違いでした。

>> DAMAGE : after Normal block (#45) at 0x00370FF0.
>これって、確保した領域外にアクセスしてから解放したときにでる・・

なるほど!

つまり一番最初のコードの時も'\0'分確保してないにもかかわらず
strcpyで範囲外にアクセスしてたって事なんですかね。

その場で出ないで delete の時にエラーになるんですね。
勉強になりました。

とりあえず落ちなくなったので解決とさせて頂きます。

Blue様、reshia様、K様ご教示ありがとうございました。


返信引用

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました