多次元配列のメモリ解放についてです。
以下のような方法で多次元配列を確保した場合に、
---
char** ppMain;
ppMain = new char*[3];
for (int i = 0; i < 3; i++){
ppMain[i] = new char[20];
}
---
メモリ解放する場合、
---
for (int i = 0; i < 3; i++){
delete [] ppMain[i];
ppMain[i] = NULL;
}
delete [] ppMain;
ppMain = NULL;
---
で良いでしょうか?
おそらく、new/deleteの回数が同じであれば問題ないと思うのですが。
少し混乱してしまって、
delete [] ppMain[i]; によって
new char*[3]で確保したところも解放されており
delete [] ppMain; が必要なく危険な領域まで解放しようとしているということはないでしょうか?
ご専門、お詳しいかたコメント宜しくお願いします。
A 回答 (5件)
- 最新から表示
- 回答順に表示
No.5
- 回答日時:
> それを考えると以下の方法であっても、
> 例外が送出される場合があるのではないでしょうか?
> char (*pMain)[20] = new char[3][20];
例外が送出される可能性はあります。
しかし、上の場合では、メモリの割り付けに成功するか、例外が送出されてメモリがまったく割り付けられないかのどちらかですので、中途半端な割付けが行われてメモリリークすることがありません。
この回答への補足
ご回答ありがとうございます。
"中途半端な割付け"の意味をいろいろ調べていて、
連絡遅れてしまいました。
調べても全く違いが分からなかったのですが、
(1)の場合の中途半端な割付けというところをもし良ければ
少しコメントいただけないでしょうか?
■(1)
for (int i = 0; i < 3; i++){
ppMain[i] = new char[20];
}
■(2)
char (*pMain)[20] = new char[3][20];
jactaさんの回答では、
(2)の場合は、割付けに失敗すればNULLが返って来るので問題ない。
(1)の場合には割付けに失敗してもNULLが返ってこない(適当なアドレスが返ってきてしまうので例外チェックも必須)ということだと思いますが、
その違いは何でしょうか?
(1)と(2)の違いというと1次元配列、2次元配列の違いしか私には分からないのですが、
その違いでメモリ割り当て方法が大きく変わってくるのでしょうか?
No.4
- 回答日時:
> (1)の場所で例外が送出?
> というのはどういうことでしょうか?
メモリの割付けに失敗した場合、newはstd::bad_alloc例外を送出します。
その場合、既に割付け済みのメモリブロックは解放の機会を失いますので、メモリリークにつながります。
これの回避は面倒ですが...
char** ppMain;
ppMain = new char*[3];
std::fill_n(ppMain, 3, 0);
try{
for (int i = 0; i < 3; i++){
ppMain[i] = new char[20];
}
}
catch (std::bad_alloc&){
for (int i = 0; i < 3; i++){
delete[] ppMain[i];
}
delete[] ppMain;
}
のようにする必要があります。
これが面倒であれば、
char (*pMain)[20] = new char[3][20];
とすれば、簡単になります。
ただし、ポインタ配列ではないのでサイズは固定です。
更に簡単にするには、
std::vector<std::vector<char> > vMain(3, std::vector<char>(20, '\0'));
とでもすればよいでしょう。
これなら可変サイズにも対応できますし、明示的な解放が不要になります。
ご回答ありがとうございます。
new / deleteというものをよく知らず、
用語をググりながら内容理解しました。
メモリ不足なり、何らかの理由でメモリアロケートに失敗し、
例外が起こる可能性があり、チェックが必要ということですね。
それを考えると以下の方法であっても、
例外が送出される場合があるのではないでしょうか?
char (*pMain)[20] = new char[3][20];
着目点が間違っていますでしょうか?
No.3
- 回答日時:
結論としては、お示しのコードで問題ありません。
以下、ちょっと細かく解説します。
まず、「new char*[3];」は「多次元配列」ではなく「ポインタの配列」を確保していることに気をつけてください。
両者はメモリ上のデータ配置が全く異なります。
前者はある空間に char が3×20並んでいることになりますが、後者はアドレス値が三つ並んでいるにすぎません。
そして「new char[20];」の繰り返しで得られるポインタ群は連続している空間を指しているとは限らず、ましてや「new char*[3];」とは全く関係のない場所である可能性もありえます。
そう考えると、「delete [] ppMain[i];」の時点では各「new char[20];」で確保した部分を開放しており、「delete [] ppMain;」では「new char*[3];」で確保したところを開放していることが理解しやすいと思います。
ご回答ありがとうございます。
多次元配列だと、こんな感じのことですね。
char hairetu[][][];
失礼しました。
ポインタの配列のみを解放しているという感じが不安でした。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# c言語配列の結合についてです。 なぜうまくいかないのでしょうか。 #include <stdio.h 4 2022/05/30 22:42
- C言語・C++・C# ポインタの型変換、どうやるんでしたっけ? 2 2022/03/28 11:00
- C言語・C++・C# C++プログラミングコードにポリモーフィズムを取り入れ方を教えてください。 2 2023/06/09 11:17
- C言語・C++・C# C言語初心者 構造体 課題について 2 2023/03/10 19:48
- C言語・C++・C# c言語 プログラムのエラー 1 2023/02/11 20:31
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
- Java javaでのプログラム(配列)について質問です. 2 2022/10/14 22:27
- Java java 入力 3 4 3 出力 ABC DEFG HIJ このようなプログラムの書き方を教えてくだ 2 2022/07/15 14:18
- C言語・C++・C# このプログラミング誰か教えてくれませんか 1 2022/06/02 15:27
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
char*を初期化したいのですが
-
C言語のintとcharの違いってな...
-
C言語にて構造体のメンバがNULL...
-
'\\0'とはなんですか?
-
fstream型オブジェクトを関数の...
-
エクセルのMID関数は、C言語では?
-
c言語でポインタ変数を用いた配...
-
ポインタのポインタの使い方
-
wsprintf( ポインタ , "%d" , "...
-
36進数
-
C言語の文字リテラル中の16進文...
-
strcat関数を自作したいです
-
文字列str内の全ての数字を...
-
動的メモリの初期化方法について。
-
小数点入りの文字列をfloat型に...
-
char 文字列型 の表現範囲が-12...
-
const char* s1とただのchar s1...
-
CStringからchar*への型変換に...
-
char型にint型の数値を代入する。
-
文字列の途中から途中までを抽出
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
char*を初期化したいのですが
-
CStringからchar*への型変換に...
-
C言語にて構造体のメンバがNULL...
-
C言語のintとcharの違いってな...
-
小数点入りの文字列をfloat型に...
-
new charとnew char[N]の違いは?
-
const char* s1とただのchar s1...
-
DWORDとcharの変換
-
strcat関数を自作したいです
-
C++17で、unsigned char * 配列...
-
文字列内の数字削除
-
エクセルのMID関数は、C言語では?
-
char 文字列型 の表現範囲が-12...
-
char型にint型の数値を代入する。
-
C言語を用いた環境変数の作成/...
-
動的メモリの初期化方法について。
-
fstream型オブジェクトを関数の...
-
C言語のプログラムについてです
-
文字列の途中から途中までを抽出
-
C言語:小文字を大文字に変換す...
おすすめ情報