下に同様の質問があるのですが,やはり理解できません.
文字列配列をメンバにもつ構造体の,メモリを動的に確保をしたいのですが,うまくいきません.
具体的には以下のようです.
正しくはどのようにすればよいでしょうか.よろしくお願いします.
typedef struct {
char **boy;
char **girl;
} Name_class;
int init_name_class(Name_class name_class, int n_boy, int n_girl)
{
int i;
name_class.boy = (char**) malloc( n_boy * sizeof(char**) );
for(i=0; i<n_boy; i++)
name_class.boy[i] = (char*) malloc( 32 * sizeof(char*) );
name_class.girl = (char**) malloc( n_girl * sizeof(char**) );
for(i=0; i<n_girl; i++)
name_class.girl[i] = (char*) malloc( 32 * sizeof(char*) );
}
main(int argc, char *argv[])
{
int i, j, n_boy=3, n_girl=2;
Name_class name_class;
init_name_class(name_class, n_boy, n_girl);
name_class.boy[0] = "yukio";
name_class.boy[1] = "hideaki";
name_class.boy[2] = "mitsuru";
name_class.girl[0] = "youko";
name_class.girl[1] = "chiharu";
printf("%s, %s, %s, %s, %s\n", name_class.boy[0], name_class.boy[1], name_class.boy[2], name_class.girl[0], name_class.girl[1]);
}
No.3ベストアンサー
- 回答日時:
×name_class.boy = (char**) malloc( n_boy * sizeof(char**) );
○name_class.boy = (char**) malloc( n_boy * sizeof(char*) );
メンバboyは、char**のサイズの領域をn_boy個ではなく、char*のサイズの領域をn_boy個欲しい筈。
×name_class.boy[i] = (char*) malloc( 32 * sizeof(char*) );
○name_class.boy[i] = (char*) malloc( 32 * sizeof(char) );
boy配列の各要素は、char*サイズの領域が32個分ではなく、charサイズの領域が32個分、つまりは32文字分の領域が欲しい筈。
以下、girlメンバについても同様。
更に、
init_name_class(name_class, n_boy, n_girl);
で動的にメモリ確保したのに
name_class.boy[0] = "yukio";
name_class.boy[1] = "hideaki";
name_class.boy[2] = "mitsuru";
name_class.girl[0] = "youko";
name_class.girl[1] = "chiharu";
とやってしまうと、動的に確保したメモリのポインタは忘れ去られ、スタティックな文字列へのポインタが配列要素に上書き代入されます。
そして、動的に確保したメモリは取り残され、だれも開放すること無く残ります。これをメモリリークと言います。
多分、free関数で開放してないのは「開放しようとするとメモリエラーで例外が発生してアプリが飛ぶ」からでしょうけど、動的に確保したメモリのポインタを書き潰してるので、メモリエラーが出て当然です。
strncpy(name_class.boy[0],"yukio",31);
name_class.boy[0][31]='\0';
strncpy(name_class.boy[1],"hideaki",31);
name_class.boy[1][31]='\0';
strncpy(name_class.boy[2],"mitsuru",31);
name_class.boy[2][31]='\0';
strncpy(name_class.girl[0],"youko",31);
name_class.girl[0][31]='\0';
strncpy(name_class.girl[1],"chiharu",31);
name_class.girl[1][31]='\0';
のように、(1つに付き32バイト分確保した)メモリに31文字以内で文字列コピーしましょう。
strncpyは、コピー時に指定したバイト数を超えそうになると終端文字の\0を書き込まないので、念の為32文字目に\0を書いておくようにしましょう。
また、mainが終る前に、free関数で確保したメモリを開放しましょう。開放の順番間違いや開放し忘れは、メモリリークの原因になります。
以下の2つのプログラムの違いが判りますか?
main()
{
char *p;
p = "test";
printf("%s\n",p);
}
main()
{
char *p;
p = (char *)malloc(10 * sizeof(char));
strncpy(p,"test",9);
p[9]='\0';
printf("%s\n",p);
free(p);
}
以下の2つのプログラムは正しくありません。判りますか?(実行するとメモリエラーで例外終了します)
main()
{
char *p;
p = (char *)malloc(10 * sizeof(char));
p = "test";
printf("%s\n",p);
free(p);
}
main()
{
char *p;
strncpy(p,"test",9);
p[9]='\0';
printf("%s\n",p);
}
書いていただいたことをなんとなくですが,理解しました.
ポインタとそれがさす実体の関係,スタティックなメモリ領域とその他の(?)メモリ領域に配慮すること.メモリの管理や,文字列を扱う際の '\0' に対する配慮など,もりだくさんの内容に関して,理解するのに十分なご説明とプログラムの例示をいただいたという感想をもちました.
書いていただいたことを教科書にして,しっかり理解したいと思います.
見知らぬ方々の親切なご回答に,たいへん感謝の念をいだいております.
ありがとうございました.
No.4
- 回答日時:
Ano1.のものです。
手元のコンピュータでは取り合えるコンパイルできてセグメンテーションフォルトにもならなかったもので、失礼しました。落ち着いてよく読むと、Ano2,3のかたが指摘されておられるように、mallocに指定するサイズ計算が変ですね。
それと、
name_class.boy[0] = "yukio";
の件ですが。
まず、name_class.boy[0]の中身は 今後上書きで書き換える予定があるので、 "yukio"のバイト数にかかわらず32文字分確保する必要があるのでしょうか?それとも、"yukio"さえ入ればいいのでしょうか?
前者なら、ANo.3 の解答通りです。
後者なら,
for(i=0; i<n_girl; i++)
name_class.girl[i] = (char*) malloc( 32 * sizeof(char*) );
は、
for(i=0; i<n_girl; i++)
name_class.girl[i] = NULL;
でよくて、
name_class.boy[0] = "yukio";
は書き換える必要はありません。
なお、このプログラム例のように文字列リテラルなどではなく、ファイル等から読み込んだ文字列 s をセットするのなら、
name_class.boy[0] = strdup(s);
とするのが楽ちんです。もちろん、正確には、
if((name_class.boy[0] = strdup(s))==NULL) {
fprintf(stderr, "Memory Allocation Failed\n");
exit(1);
}
みたいな感じで、エラー処理が必要ですが。
ご回答ありがとうございます.
さらに新しい理解を得ることができました.
構造体に格納した名前は,書き換えるかどうかまだ決まっていないのですが,書き換えない場合,ご説明していただいたとおりでよいのだ,ということは全くの未知でありました.
また,文字列は,実際にはファイルから読み込むことを想定しております.strdup という関数は知りませんでしたし,エラー処理の仕方も,書いていただいたとおり,そのままありがたく使わせていただきたいと思います.
回答をいただいたみなさんのおかげで,ずいぶん理解のレベルが深まった気になってます.
どうも,ありがとうございました.
No.2
- 回答日時:
int init_name_class(Name_class name_class, int n_boy, int n_girl)
の部分、構造体は参照渡しではなく、値渡しなので、
void init_name_class(Name_class *name_class, int n_boy, int n_girl)
とします。
(値を返していないのでvoid で)
そのように変更したら
メンバーへのアクセスは
name_class->boy のようにします
呼び出す側は、
init_name_class(&name_class, n_boy, n_girl);
のようにします。
----------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char **boy;
char **girl;
} Name_class;
void init_name_class(Name_class *name_class, int n_boy, int n_girl)
{
int i;
name_class->boy = (char**) malloc( n_boy * sizeof(char**) );
for(i=0; i<n_boy; i++)
name_class->boy[i] = (char*) malloc( 32 * sizeof(char*) );
name_class->girl = (char**) malloc( n_girl * sizeof(char**) );
for(i=0; i<n_girl; i++)
name_class->girl[i] = (char*) malloc( 32 * sizeof(char*) );
}
main(int argc, char *argv[])
{
int i, j, n_boy=3, n_girl=2;
Name_class name_class;
init_name_class(&name_class, n_boy, n_girl);
name_class.boy[0] = "yukio";
name_class.boy[1] = "hideaki";
name_class.boy[2] = "mitsuru";
name_class.girl[0] = "youko";
name_class.girl[1] = "chiharu";
printf("%s, %s, %s, %s, %s\n", name_class.boy[0], name_class.boy[1], name_class.boy[2], name_class.girl[0], name_class.girl[1]);
}
お礼が遅れてすみません.しばらく考えておりました.
ようやく書いていただいたことが分かりました.
構造体の扱いだけでなく,ポインタに関する理解も足りないことがわかりました.
もう一度,教科書を読んでしっかり理解したいと思います.
ありがとうございました.
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# C++プログラミングコードにポリモーフィズムを取り入れ方を教えてください。 2 2023/06/09 11:17
- HTML・CSS CSSが効かずどのように指定すれば良いか分からないのでアドバイスお願い致します 2 2023/06/07 12:25
- JavaScript ①入力フォーム→②確認表示画面→③送信完了画面のコードを書いているのです、 入力フォームから受け取っ 2 2022/05/10 16:45
- HTML・CSS ボタンをクリックした時に、入力フォームのすぐ下部に、「入力欄が空白です」というテキストメッセージが表 1 2022/04/27 16:25
- HTML・CSS CSS のみのタブ切り替えについて 1 2023/01/11 16:47
- JavaScript sessionStorageを調べています。 1 2023/06/20 12:41
- JavaScript jqueryを使ったスムーススクロールのコードを書いたのですが、HTMLコード内にある、a butt 2 2022/04/14 10:59
- JavaScript clear機能を失わずにファイルアップロード機能を作成したい 3 2023/06/10 16:12
- Java java final 1 2022/06/10 22:49
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
このQ&Aを見た人はこんなQ&Aも見ています
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
Application.ScreenUpdating = ...
-
FindFirst を複数条件で検索
-
VBA他のブックから値のみ貼付す...
-
実行時エラー 3020の対策
-
ACCESS テキストボックスを隙...
-
コンボボックスのtag情報の取得...
-
[python] 文字列を変数名として...
-
MSXMLでの属性の存在確認法
-
講義でわからないのですが以下...
-
構造体の変数の値を、動的に取...
-
vbaでxmlからNodeListでデータ...
-
JSONで文字列が長い時
-
formで特定のinputを送信しない...
-
メモリをアドレスを直接指定し...
-
pythonで演算子を変数に代入す...
-
文字の横にプルダウンを表示さ...
-
セレクトメニューで2つの項目...
-
Python - Excel で Webからデー...
-
Perlで複数の値を返す良い方法...
-
<SELECT>タグの折り返し
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
Application.ScreenUpdating = ...
-
実行時エラー 3020の対策
-
FindFirst を複数条件で検索
-
「*:*」って何を意味するのでし...
-
ACCESS テキストボックスを隙...
-
パイソンプログラミング
-
VBAでPDFのコピーとリネームを...
-
パイソンのクラスのブログラム
-
【メモリ不足で落ちる(python)】
-
[python] 文字列を変数名として...
-
パイソンのクラスについて
-
vscode 文字化け
-
PythonのExperimentに関する質...
-
vbaでxmlからNodeListでデータ...
-
phpでボタンを押したときに変数...
-
UWSC:ポップアップウインドウ...
-
VBA他のブックから値のみ貼付す...
-
構造体の各データの表示につい...
-
コンボボックスのtag情報の取得...
-
VBAで特殊文字を出力したい
おすすめ情報