ページ 11

メモリ確保(再)

Posted: 2013年1月31日(木) 00:44
by Cユーザー
こんばんわ、C言語の勉強を始めたものです。
以下の構造体でメモリ確保を行うには
SAMPLE *sample = (SAMPLE *) malloc(sizeof(SAMPLE));
と確保できるのはわかりました。
しかし例えば

SAMPLE *sample = (SAMPLE *) malloc(500);
と余分にメモリを確保した場合、メモリ的にどういう構造になるのでしょうか?

handle→4バイト
number→4バイト
str→4バイト

[handle(4バイト)] + [number(4バイト)] + [str(4バイト)] + [余分なゴミメモリ(488バイト)]

①こんな構造のメモリ領域ができあがると考えていますが、正しいでしょうか?

SAMPLE *sample = (SAMPLE *) malloc(500)とした後
sample->str = (char*)malloc(600);

とした場合、
②この場合、構造体メンバーの確保領域が、構造体の確保領域を超えているのですが、これはどういう状態になりますか?
エラーにはなりませんでした。

SAMPLE *sample = (SAMPLE *) malloc(500)とした後
sample->str = (char*)malloc(300);

とした場合、
③構造体のメモリ領域は以下のようになると考えています。正しいでしょうか?

[handle(4バイト)] + [number(4バイト)] + [str(300バイト)] + [余分なゴミメモリ(192バイト)]


①~③が質問です。
以上、よろしくお願いいたします。

コード:

struct SAMPLE
{
    HANDLE handle;
    int number;
    char *str;
}; 

Re: メモリ確保(再)

Posted: 2013年1月31日(木) 01:31
by h2so5
Cユーザー さんが書きました: SAMPLE *sample = (SAMPLE *) malloc(500);
と余分にメモリを確保した場合、メモリ的にどういう構造になるのでしょうか?

handle→4バイト
number→4バイト
str→4バイト

[handle(4バイト)] + [number(4バイト)] + [str(4バイト)] + [余分なゴミメモリ(488バイト)]

①こんな構造のメモリ領域ができあがると考えていますが、正しいでしょうか?
メモリアドレスが32bitの場合はそのようになります。
Cユーザー さんが書きました: SAMPLE *sample = (SAMPLE *) malloc(500)とした後
sample->str = (char*)malloc(600);

とした場合、
②この場合、構造体メンバーの確保領域が、構造体の確保領域を超えているのですが、これはどういう状態になりますか?
エラーにはなりませんでした。
構造体メンバーの確保領域は、構造体の確保領域を超えていません。
この場合もsampleは4byteです。
Cユーザー さんが書きました: SAMPLE *sample = (SAMPLE *) malloc(500)とした後
sample->str = (char*)malloc(300);

とした場合、
③構造体のメモリ領域は以下のようになると考えています。正しいでしょうか?

[handle(4バイト)] + [number(4バイト)] + [str(300バイト)] + [余分なゴミメモリ(192バイト)]
違います。

[handle(4バイト)] + [number(4バイト)] + [str(4バイト)] + [余分なゴミメモリ(488バイト)]

[(300バイト)]
の2つの領域が確保されます。この領域は連続しているとは限りません。
そして、strへ300byteの領域の先頭のアドレスが代入されます。

Re: メモリ確保(再)

Posted: 2013年1月31日(木) 01:40
by Cユーザー
ご返信ありがとうごさます。

なるほど、そういう仕組みなんですね。

もう1点質問させてください。逆に、
handle(4バイト)] + [number(4バイト)] + [str(300バイト)] + [余分なゴミメモリ(192バイト)]

となるような、確保領域の再設定?は可能でしょうか?
可能であれば方法をご教授いただきたいです。

Re: メモリ確保(再)

Posted: 2013年1月31日(木) 02:11
by h2so5
300byte連続してほしいなら

コード:

struct SAMPLE
{
    HANDLE handle;
    int number;
    char str[300];
};
でどうでしょうか?

Re: メモリ確保(再)

Posted: 2013年1月31日(木) 02:22
by Cユーザー
返信ありがとうございます。

その方法は1つの手ではあるのですが
後から構造体メンバの文字列のメモリを確保したいんです。

コード:

struct SAMPLE
{
    HANDLE handle;
    int number;
    char str[300];
};
だとあらかじめ決まった分しか確保できません。
其のため

コード:

struct SAMPLE
{
    HANDLE handle;
    int number;
    char *str;
};
としておいて、後からメモリを確保したいんですよね。
それでhandle(4バイト) + number(4バイト) + str(300バイト)

というような無駄なメモリもなくメモリを使いたい。実はこれが一番やりたいことです。

何か方法はないでしょうか
以上、よろしくお願いいたします。

Re: メモリ確保(再)

Posted: 2013年1月31日(木) 02:49
by h2so5
文字列のサイズを可変にしたいだけなら領域が連続している必要もないので、普通に

コード:

SAMPLE *sample = (SAMPLE *) malloc(sizeof(SAMPLE));
sample->str = (char*)malloc(300);
で良いと思います。

Re: メモリ確保(再)

Posted: 2013年1月31日(木) 08:30
by Cユーザー(携帯)
ご返信ありがとうございます。

また疑問が1つできました。

前のレスで300の領域の先頭アドレスが代入されるとありました。
その場合、構造体のメモリ確保時のstrのメモリは無駄メモリになる感じでしょうか?

Re: メモリ確保(再)

Posted: 2013年1月31日(木) 08:33
by box
Cユーザー さんが書きました: その場合、構造体のメモリ確保時のstrのメモリは無駄メモリになる感じでしょうか?
300バイト確保した分がどこにあるか、というアドレス値を保持するために必須です。

Re: メモリ確保(再)

Posted: 2013年1月31日(木) 10:34
by Cユーザー(携帯)
なるほど。

ご教授ありがとうございました

Re: メモリ確保(再)

Posted: 2013年1月31日(木) 10:35
by Cユーザー(携帯)
すいません

解決チェック押し忘れです

Re: メモリ確保(再)

Posted: 2013年1月31日(木) 16:48
by ISLe
Cユーザー さんが書きました:というような無駄なメモリもなくメモリを使いたい。実はこれが一番やりたいことです。
構造体の最後のメンバを要素数1の配列にします。
#処理系によっては要素数0が使えます。

コード:

struct SAMPLE
{
	HANDLE handle;
	int number;
	char str[1];
};
必要な配列の要素数分を余分にメモリ確保します。

コード:

struct SAMPLE *sample = (struct SAMPLE *)malloc(sizeof(struct SAMPLE)+300-1);
こうするとsample->strは要素数が300あるかのように使えます。

Re: メモリ確保(再)

Posted: 2013年1月31日(木) 17:21
by YuO
ISLe さんが書きました:構造体の最後のメンバを要素数1の配列にします。
#処理系によっては要素数0が使えます。
標準C的には,要素数を記述しない,ですね。
# ISO/IEC 9899:1999 6.7.2.1 Structure and union specifiers ¶16
ISLe さんが書きました:

コード:

struct SAMPLE
{
	HANDLE handle;
	int number;
	char str[1];
};
標準Cが使えるならば,

コード:

struct SAMPLE
{
	HANDLE handle;
	int number;
	char str[];
};
とするとよいでしょう。
この場合,1を引く作業は不要です。
ただ,標準Cではあるものの標準C++ではない (標準C++の標準CとのCompatibility欄にすら書いていない) のが問題点ですが。
# 配列まわりはCとC++で非互換が……。

Re: メモリ確保(再)

Posted: 2013年2月02日(土) 11:03
by へにっくす
ISLe さんが書きました:
Cユーザー さんが書きました:というような無駄なメモリもなくメモリを使いたい。実はこれが一番やりたいことです。
構造体の最後のメンバを要素数1の配列にします。
#処理系によっては要素数0が使えます。

コード:

struct SAMPLE
{
	HANDLE handle;
	int number;
	char str[1];
};
必要な配列の要素数分を余分にメモリ確保します。

コード:

struct SAMPLE *sample = (struct SAMPLE *)malloc(sizeof(struct SAMPLE)+300-1);
こうするとsample->strは要素数が300あるかのように使えます。
これってWin32APIの構造体でよく見かけますね。
SDKのIncludeヘッダで、"[1]"で検索すると結構ヒットする。
これを使用する場合、たいていはどれだけの長さがあるかも構造体のメンバに入れてます。
例:winnt.hの一部

コード:

typedef struct _JOBOBJECT_BASIC_PROCESS_ID_LIST {
    DWORD NumberOfAssignedProcesses;
    DWORD NumberOfProcessIdsInList;
    ULONG_PTR ProcessIdList[1];
} JOBOBJECT_BASIC_PROCESS_ID_LIST, *PJOBOBJECT_BASIC_PROCESS_ID_LIST;

typedef struct _FILE_NOTIFY_INFORMATION {
    DWORD NextEntryOffset;
    DWORD Action;
    DWORD FileNameLength;
    WCHAR FileName[1];
} FILE_NOTIFY_INFORMATION, *PFILE_NOTIFY_INFORMATION;
まあWindows SDKでは常套手段ってことで参考になれば。
スレ汚しすみません。