【掲示板ご利用上の注意】

 ※題名は具体的に!
 ※学校の課題の丸投げ禁止!
 ※ソースの添付は「HTML変換ツール」で字下げ!
 ※返信の引用は最小限に!
 ※環境(OSとコンパイラ)や症状は具体的に詳しく!
 ※返信付き投稿の削除は禁止!
 ※マルチポスト(多重投稿)は慎んで!

 詳しくはこちら


本当はこんなに大きく書きたくはないのですが、なかなか守っていただけなくて…。
 守ってくださいね。お願いします。(by管理人)

C言語ソース⇒HTML形式ツール掲示板2こちら


管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧

No.22320

動的メモリ割り当てについて
投稿者---zero(2005/07/31 15:15:20)


こんにちは。

早速ですが、ある関数内でmallocなどで動的にメモリを割り当てた場合、
この関数内でfreeを呼ばないかぎり、この関数を抜けても動的に確保されたメモリ領域はstatic変数のようにずっと内容が残っているのでしょうか?


この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:動的メモリ割り当てについて 22321 まきじ 2005/07/31 15:59:17
<子記事> Re:動的メモリ割り当てについて 22324 とおり 2005/07/31 17:34:44


No.22321

Re:動的メモリ割り当てについて
投稿者---まきじ(2005/07/31 15:59:17)


>この関数を抜けても動的に確保されたメモリ領域はstatic変数のようにずっと内容が残っているのでしょうか?

関数を抜けると、メモリ上のどこにあるか解らなくなります。


この投稿にコメントする

削除パスワード

No.22322

Re:動的メモリ割り当てについて
投稿者---zero(2005/07/31 17:09:30)


>関数を抜けると、メモリ上のどこにあるか解らなくなります。

返信ありがとうございます。
と言うことは、メモリ上には、確保された領域は開放されずに残っているということですね?

>関数を抜けると、メモリ上のどこにあるか解らなくなります。

mallocの返り値をstatic変数に代入した場合は別ですよね?


この投稿にコメントする

削除パスワード

No.22323

Re:動的メモリ割り当てについて
投稿者---まきじ(2005/07/31 17:32:27)


>>関数を抜けると、メモリ上のどこにあるか解らなくなります。

>と言うことは、メモリ上には、確保された領域は開放されずに残っているということですね?

例えば、main() 以外の関数で、malloc() により確保された領域を
main() で参照するには、ポインタを返す か ポインタへのポインタを
渡す必要があります。

>mallocの返り値をstatic変数に代入した場合は別ですよね?

実験してみましたが、static なポインタ変数に、malloc() するとなると、

static char *p = malloc(sizeof(char) * 10);

な風にする事になると思いますが、これはコンパイルエラーになります。

だから、

static char *p;
p = malloc(sizeof(char) * 10);

とすれば、コンパイルエラーになりませんが、
static にする意味がない様な気がします。

というか、static char *p って p が指してる所が static な気がします。
(const と同じ)static char 型へのポインタではないのでしょうか?

char 型への static ポインタにしようと思い、
char* static p とするとコンパイルエラーですし・・・

# 俗に、識者 と云われる方々、お願いします。


この投稿にコメントする

削除パスワード

No.22325

Re:動的メモリ割り当てについて
投稿者---とおり(2005/07/31 17:43:05)


識者ではないですが…

>実験してみましたが、static なポインタ変数に、malloc() するとなると、
>
>static char *p = malloc(sizeof(char) * 10);
>
>な風にする事になると思いますが、これはコンパイルエラーになります。

char*にcastしてないだけでは??
別に↑でまずいことは全くありませんが。
最初にpを初期化する際のみ、mallocが呼ばれるだけです。

>static char *p;
>p = malloc(sizeof(char) * 10);
>
>とすれば、コンパイルエラーになりませんが、

これは、ここを通る度にmallocが呼ばれるだけです。

>static にする意味がない様な気がします。

そんなことはありません。


この投稿にコメントする

削除パスワード

No.22326

Re:動的メモリ割り当てについて
投稿者---まきじ(2005/07/31 17:59:31)


>char*にcastしてないだけでは??

キャストして駄目でした。

>別に↑でまずいことは全くありませんが。
>最初にpを初期化する際のみ、mallocが呼ばれるだけです。

static 変数の初期化子は、定数じゃないと駄目なようです。

「error C2099: initializer is not a constant」となる


この投稿にコメントする

削除パスワード

No.22335

Re:動的メモリ割り当てについて
投稿者---とおり(2005/07/31 19:46:50)


>static 変数の初期化子は、定数じゃないと駄目なようです。
>
>「error C2099: initializer is not a constant」となる

うちのVC6では、static変数の初期化子が定数以外(関数callとかも)でも、
何も問題ありませんでした。
(関数callした場合、初期化時に一度だけ呼ばれる)

と思ったら、CとC++の違いの模様。Cは駄目、C++はOK。
識者による仕様の解説求む…


この投稿にコメントする

削除パスワード

No.22342

Re:動的メモリ割り当てについて
投稿者---まきじ(2005/07/31 23:55:49)


>と思ったら、CとC++の違いの模様。Cは駄目、C++はOK。

C の方は、X3010 の 6.7.8 に
「静的記憶期間をもつオブジェクトの初期化子の中のすべての式は定数式又は文字列リテラルでなければならない」
と記載されていました。


この投稿にコメントする

削除パスワード

No.22343

Re:動的メモリ割り当てについて
投稿者---まきじ(2005/07/31 23:59:23)


定数式 について、同じく X3010 の 6.6 に
「代入、増分、減分、関数呼び出し又はコンマ演算子を含んではならない」
とありました。


この投稿にコメントする

削除パスワード

No.22339

Re:動的メモリ割り当てについて
投稿者---まきじ(2005/07/31 23:43:20)


>というか、static char *p って p が指してる所が static な気がします。
>(const と同じ)static char 型へのポインタではないのでしょうか?
>char 型への static ポインタにしようと思い、
>char* static p とするとコンパイルエラーですし・・・

この発言はなかったことに・・・

static は記憶クラス指定子で、const は型修飾子
同じ様に考えるのは論外ですね・・・(^^;


この投稿にコメントする

削除パスワード

No.22324

Re:動的メモリ割り当てについて
投稿者---とおり(2005/07/31 17:34:44)


>早速ですが、ある関数内でmallocなどで動的にメモリを割り当てた場合、
>この関数内でfreeを呼ばないかぎり、この関数を抜けても動的に確保されたメモリ領域はstatic変数のようにずっと内容が残っているのでしょうか?

freeを呼ばない限り、その領域はプロセスが終了するまで残ります。
まきじさんが言っているのは、変数なり何なりで、そのポインタを保持しない限り
確保領域がどこかわからない(ポインタがないので、アクセス(解放も)できなくなる)
ということです。

そのポインタがstatic変数であるか、global変数であるか、クラスのメンバ変数であるか
といった話は、そのポインタ変数の寿命(引いては、確保領域を把握していられる期間)を
決める話で、確保した領域そのものが存在するかとは無関係です。


この投稿にコメントする

削除パスワード

No.22327

Re:動的メモリ割り当てについて
投稿者---zero(2005/07/31 18:19:36)


皆様返信ありがとうございます。
現在サーバのソケットから一行受信する関数を作っていて上記のような悩みがでてきました。

main()関数内で char *buf;と宣言し、socRecvOneLine(soc, &buf);と呼びだします。

int socRecvOneLine(int soc, char **ret_buf) {
        char *tmpbuf;
        int len, str_len, pos;
        char *cp;

        *ret_buf = NULL;
        /* 初期メモリとして1024byte確保 */
        tmpbuf = (char *)calloc(1, sizeof(char));
        if (tmpbuf == NULL) {
                perror("calloc");
                return -1;
        }

        pos = 0;
        while (1) {
                len = recv(soc, tmpbuf+pos, 1, 0);
                if (len <= 0) {
                        perror("recv");
                        free(tmpbuf);
                        return -1;
                }
                if ( (cp = strstr(tmpbuf, "\r\n")) != NULL) {
                        *cp = '\0';
                        break;
                }

                while (len--) pos++;

                tmpbuf = (char *)realloc(tmpbuf, 1);
                if (tmpbuf == NULL) {
                        perror("realloc");
                        free(tmpbuf);
                        return -1;
                }
        }
        str_len = strlen(tmpbuf);
        *ret_buf = tmpbuf;

        return str_len;
}
          


上記の関数のままだと、毎回この関数を呼ぶたびに開放されてない領域が増えていくと思いますが、、、。
なにかいい方法はないでしょうか。


この投稿にコメントする

削除パスワード

No.22328

Re:動的メモリ割り当てについて
投稿者---zero(2005/07/31 18:28:03)


すいません、上記のソースは間違っていたので以下にもう一度貼り直します。

int socRecvOneLine(int soc, char **ret_buf) {
        char *tmpbuf;
        int len, str_len, pos;
        char *cp;

        *ret_buf = NULL;
        /* 初期メモリとして1024byte確保 */
        tmpbuf = (char *)calloc(1024, sizeof(char));
        if (tmpbuf == NULL) {
                perror("calloc");
                return -1;
        }

        pos = 0;
        while (1) {
                len = recv(soc, tmpbuf+pos, 1024, 0);
                if (len <= 0) {
                        perror("recv");
                        free(tmpbuf);
                        return -1;
                }
                if ( (cp = strstr(tmpbuf, "\r\n")) != NULL) {
                        *cp = '\0';
                        break;
                }

                while (len--) pos++;

                tmpbuf = (char *)realloc(tmpbuf, 1024);
                if (tmpbuf == NULL) {
                        perror("realloc");
                        free(tmpbuf);
                        return -1;
                }
        }
        str_len = strlen(tmpbuf);
        *ret_buf = tmpbuf;

        return str_len;
}




この投稿にコメントする

削除パスワード

No.22329

Re:動的メモリ割り当てについて
投稿者---まきじ(2005/07/31 19:23:42)


>関数を呼ぶたびに開放されてない領域が増えていくと思いますが、、、。

tmpbuf の事でしょうか?

*retbuf = tmpbuf; としているので、tmpbuf を解放すると
main() で retbuf で確保した領域にアクセスしても
データの保持は保障されないと思います。
データが消えてる可能性もあると思います。
よって、free() する必要があるポインタ変数はないと思います。
するなら、retbuf を使わなくなった時点で、free() をすれば
良いと思います。

>tmpbuf = (char *)calloc(1024, sizeof(char));

**rebuf で受け取ってるでしたら、
retbuf = (char*)calloc(1024,sizeof(char));
では駄目なんでしょうか?


この投稿にコメントする

削除パスワード

No.22332

Re:動的メモリ割り当てについて
投稿者---zero(2005/07/31 19:35:19)


socRecvOneLine()関数内でtmpbufが確保した領域をmain関数内で宣言したbufが指し、socRecvOneLine()関数を抜けてmain関数に戻ってきた時点で、動的に確保した領域を指しているポインタはbufだけになります。
そして次にmain関数内でまたsocRecvOneLine()関数を呼ぶと、bufは再び別に動的に確保された領域を指すようになっていしまい、前に動的に確保された領域を指すポインタが失われてしまうので、そのメモリを開放できなくなってしまうのではないでしょうか?
これが積もり積もるとメモリリークを引き起こさないか心配なのですが、、。


この投稿にコメントする

削除パスワード

No.22333

Re:動的メモリ割り当てについて
投稿者---まきじ(2005/07/31 19:39:45)


>そして次にmain関数内でまたsocRecvOneLine()関数を呼ぶと、bufは再び別に動的に確保された領域を指すようになっていしまい、前に動的に確保された領域を指すポインタが失われてしまう

socRecvOneLine() を呼び出す前に if(retbuf != NULL) free(retbuf) とか
すればどうでしょうか?


この投稿にコメントする

削除パスワード

No.22334

Re:動的メモリ割り当てについて
投稿者---まきじ(2005/07/31 19:41:37)


>これが積もり積もるとメモリリークを引き起こさないか心配なのです

最近は、メモリも大容量なのでメモリリークを起こす事も、
滅多にないと思います。


この投稿にコメントする

削除パスワード

No.22336

Re:動的メモリ割り当てについて
投稿者---とおり(2005/07/31 19:48:24)


>最近は、メモリも大容量なのでメモリリークを起こす事も、
>滅多にないと思います。

細かいことですみませんが、大容量なのとメモリリークを起こす起こさないは
全く無関係です。
メモリリークは起きます。
が、それが実際にシステムに影響を及ぼすかとかが、搭載メモリ量の影響を受けるだけ。
大容量でも、長時間繰り返せば影響出るでしょうし。


この投稿にコメントする

削除パスワード

No.22331

Re:動的メモリ割り当てについて
投稿者---Hermit(2005/07/31 19:34:33)


recv()が何か良く知らないのでなんともいえませんが、
        tmpbuf = (char *)calloc(1024, sizeof(char));
        if (tmpbuf == NULL) {
                perror("calloc");
                return -1;
        }

を、
static char tmpbuf;
tmpbuf = realloc(tmpbuf,1024);
とすれば、最初呼び出すときtmpbufがNULLなので、
mallocと同じ動作になるはずですが。

もひとつ・・・これ
                tmpbuf = (char *)realloc(tmpbuf, 1024);
                if (tmpbuf == NULL) {
                        perror("realloc");
                        free(tmpbuf); /* ここ */
                        return -1;
                }

これ、必ず free(NULL); ですが・・



この投稿にコメントする

削除パスワード

No.22337

Re:動的メモリ割り当てについて
投稿者---Hermit(2005/07/31 20:23:58)


>static char tmpbuf;
失礼、
static char *tmpbuf;
でした。
わかりやすいように、
static char *tmpbuf = NULL;
と指定してもいいけど。


この投稿にコメントする

削除パスワード

No.22344

Re:動的メモリ割り当てについて
投稿者---かずま(2005/08/01 07:17:14)


メモリの確保と解放をすべて socRecvOneLine() の中で行いたいのなら、
main() で最初に char *buf = NULL; と宣言し、socRecvOneLIne() の中で、

    free(*ret_buf);
    *ret_buf = NULL;
    tmpbuf = malloc(1024);
    ...
    *ret_buf = tmpbuf;
    return str_len;

とすればよいでしょう。

また、元のプログラムにはおかしなところがいくつかあります。

>         tmpbuf = (char *)calloc(1024, sizeof(char));

C なら、(char *) のキャストは不要。あっても間違いではありませんが。
sizeof(char) は 1 なので、1 と書いてもよい。
calloc() を使っていますが、バッファのゼロクリアは本当に必要ですか?

>                 len = recv(soc, tmpbuf+pos, 1024, 0);

pos が 0 でないとき、受信できる領域は 1024バイト未満のはずなのに
1024バイト受信しようとしていますよ。


>                 if ( (cp = strstr(tmpbuf, "\r\n")) != NULL) {

strstr() を使うために、calloc() のゼロクリアを使っているようですが、
もし、最初の recv で 1024バイト受信してしまったら、'\0' がないので、
strstr() が利用できません。


>                 while (len--) pos++;

これは、pos += len; len = 0; と等価です。


>                 tmpbuf = (char *)realloc(tmpbuf, 1024);

tmpbuf は 1024 バイトなのに、同じサイズで realloc() するのは無意味です。

>                 if (tmpbuf == NULL) {
>                         perror("realloc");
>                         free(tmpbuf);

tmpbuf が NULL のとき、free(tmpbuf) は free(NULL) で無意味です。



この投稿にコメントする

削除パスワード

No.22345

Re:動的メモリ割り当てについて
投稿者---かずま(2005/08/01 07:31:53)


#include <stdlib.h>
#include <string.h>

int socRecvOneLine(int soc, char **ret_buf)
{
    char *tmpbuf, *cp;
    int len, pos;

    free(*ret_buf);
    *ret_buf = NULL;
    tmpbuf = malloc(1024);
    if (tmpbuf == NULL) {
        perror("socRecvOneLine: malloc");
        return -1;
    }

    pos = 0;
    while (1) {
        len = recv(soc, tmpbuf + pos, 1024, 0);
        if (len <= 0) {
            perror("socRecvOneLine: recv");
            free(tmpbuf);
            return -1;
        }
        cp = memchr(tmpbuf + pos, '\r', len);
        if (cp != NULL) {
            *cp = '\0';
            break;
        }
        pos += len;
        cp = realloc(tmpbuf, pos + 1024);
        if (cp == NULL) {
            perror("socRecvOneLine: realloc");
            free(tmpbuf);
            return -1;
        }
        tmpbuf = cp;
    }
    *ret_buf = tmpbuf;
    return cp - tmpbuf;
}



この投稿にコメントする

削除パスワード

No.22349

Re:動的メモリ割り当てについて
投稿者---zero(2005/08/01 10:38:23)


かずま様、ご丁寧な返信ありがとうございます。

ご指摘いただいた個所は確かに色々とおかしいですね。

また示していただいたソースを十分勉強したいと思います。

ありがとうございました。


この投稿にコメントする

削除パスワード

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧