質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

メモリリーク

メモリリークは、プログラムファイルがメモリの解放に失敗した時に起こります。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

5回答

1093閲覧

動的メモリ管理について

takuyaKK

総合スコア37

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

メモリリーク

メモリリークは、プログラムファイルがメモリの解放に失敗した時に起こります。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2021/07/09 03:22

編集2021/07/09 04:27

c言語のメモリ管理についての質問です。
以下のような関数をmain関数から呼び出して、内部でcallocを使って変数aにメモリを割り当てた場合、この関数からリターンした後もaというローカル変数の値はプログラムの実行終了までメモリ上に存在し続けることが保障されるという認識であってますでしょうか?

ご回答よろしくお願いいたします。

c

1 void a() { 2 int *a = calloc(1, sizeof(int)); 3 *a = 12; 4 return ture; 5 }

以下追記

例えばTokenという構造体があったとして、new_tokenという関数の中でこのようにtokという変数のメンバに値を代入したとします。

この時このnew_tokenという関数からreturnした後も、プログラムが終了するまで、この代入した値はメモリ上から失われないという認識は正しいでしょうか?

c

1struct Token { 2 Token *next; 3 int val; 4 char *str; 5 }; 6 7Token *new_token(Token *cur, char *str) { 8 Token *tok = calloc(1, sizeof(Token)); 9 tok->str = str; 10  tok->next = NULL; 11 cur->next = tok; 12 return tok;

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答5

0

C

1Token *tok = calloc(1, sizeof(Token));

callocは,
あなたが要求したサイズ( sizeof(Token)[byte]の塊を 1個並べることができるだけのサイズ)の領域をメモリ上のどこかに割り当てて(さらにその領域をゼロ埋めして),その位置を戻り値として返す.
freeを用いて解放するまで,あなたはこの領域を正当に使用することができる.

……というだけ.

なので,
その領域を以降も使うためには(freeを用いるためにも),その領域の場所(callocが返してきた値)をどこかに覚えておく必要がある.

そのためにあなたがやるべきことは,
【領域の場所覚えておくための「どこか」の生存期間 >= この領域を使用する期間】
となるように頑張ること.

  • 質問文の最初コードでは,この「どこか」が関数内のローカル変数だったので,すぐに寿命が尽きてしまっている.

これではその領域を以降に使ったり解放するための手立てがなくなっている.

  • 追記された後者側のコードでは関数呼び出し側がこのあたりをうまいことやるべき,ということになる.

投稿2021/07/09 06:25

fana

総合スコア11675

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

takuyaKK

2021/07/09 07:18

ありがとうございます!理解できました!
guest

0

前半の関数aについては、回答が付いているとおりで、間違っています。
メモリの実態と、そこへのポインターの混同があるのでは?

後半の追記部分は、代入先はプログラム終了もしくは、free等で解放するまで残るというのは合っていますが、「tokという変数のメンバに値を代入したとします。」は間違いで、tokという変数にメンバーは無くて、tokという変数の指す先の構造体のメンバーに値を代入しています。
構造体と構造体を指すポインターの混同があるのでは?。

関数new_tokenの返り値のポインターをどこかに保存しておけば、そのポインター経由で、構造体にアクセスできますし、ポインターの値を失ってしまえば、その構造体はメモリ上に存在はするがアクセスできないことになります。

投稿2021/07/09 05:33

otn

総合スコア84712

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

takuyaKK

2021/07/09 06:05

cは普段使ってないで適切な用語表現を使えず申し訳ありません????‍♂️知りたいことが理解できました!ありがとうございます!
guest

0

ベストアンサー

以下のような関数をmain関数から呼び出して、内部でcallocを使って変数aにメモリを割り当てた場合、この関数からリターンした後もaというローカル変数の値はプログラムの実行終了までメモリ上に存在し続けることが保障されるという認識であってますでしょうか?

保証はされません。あくまで「結果的に」あるだけです。

保証はされるようです。

// ですが、あれを保証すると言うのかな……(まあ、確かに保証はしていますが……)

まず、普通の変数や定数はスタック領域に確保されます。

ですが、C言語でいうmalloc/free, C++でいうnew/delete でやる動的確保については、
ヒープ領域に確保されます。

スタック領域では一気に確保するので、大きいサイズは不可能です。

ヒープ領域では動的に確保するので大きいサイズでもOKです。
(メモリが許せば)

ただし、ヒープ領域にセットされたものはC言語でいう free関数, C++でいうdelete で破棄しないと、
破棄されません。

例えばTokenという構造体があったとして、new_tokenという関数の中でこのようにtokという変数のメンバに値を代入したとします。

用語がめちゃくちゃ。

C

1Token *tok;

はあくまでToken構造体のオブジェクトでしかないです。(近いニュアンスとしては『変数』か。厳密には違うけど)

ご指摘を受けて、よくよく考えると「ポインタ」なので、『Token構造体の(実体に対する)ポインタ』ですね。

メンバっていうのは Token構造体の中にある int val とかです。

この時このnew_tokenという関数からreturnした後も、プログラムが終了するまで、この代入した値はメモリ上から失われないという認識は正しいでしょうか

上で述べた通り、「明示的に破棄するまでは存在する」という意味では正しいです。

ですが、保証はされていません。

結果的に存在しているだけです。

ただし、質問にある、一番上のコードでは「他の関数からはアクセスできない」状態で居座っています。


[追記1]

リスト構造や木構造のように、「次へのポインタ」とかを持っている場合はそこから辿ればいいので、
使えます。

ポインタはあくまで「アドレス」です。

メモリ上のどこに配置されているかのアドレスであって、実体ではないので、
そのアドレスを辿っていけば使えるのです。


※ 他に低評価になりそうな理由があれば、挙げてほしいです。(後学のためにも)

投稿2021/07/09 05:19

編集2021/07/09 08:16
BeatStar

総合スコア4958

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

BeatStar

2021/07/09 05:47

できれば低評価の理由も書いてほしいのですが…… (後学のために)
takuyaKK

2021/07/09 06:07

なるほど、詳しくありがとうございました! 低評価は僕が押したのではないので分かりません...
K_3578

2021/07/09 06:10

> BeatStarさん 低評価をしたのは私ではないですが、低評価したユーザーへは回答へのコメントでは通知が来ないので 回答を編集してその旨を書いては如何でしょうか。 回答を編集した場合はコメントしたユーザーと低評価したユーザーに通知が行きますので。
Harahira

2021/07/09 06:20

たとえ、そこにアクセスする手段が無くなっても、malloc等で確保されたメモリは、明示的に破棄するまでは存在することは保証されてます。結果的に存在しているだけではありません
fana

2021/07/09 06:35

> Token *tok; > はあくまでToken構造体のオブジェクトでしかないです。 ここ,これだと「tok がToken型オブジェクトだ」という意味になっちゃうのでは.
neconekocat

2021/07/09 06:48

あんまり揚げ足とるようなことをしても仕方ない気はしますが・・・
fana

2021/07/09 06:58

単純な誤記だと思うので「ここ,変になってますよ」って伝えているだけですよ. (低評価してその理由を書いているという話ではないです) 場所が > 用語が… という話のところなので,直した方がいいんじゃないかな,と.
takuyaKK

2021/07/09 07:23

正しくは「tokはTokenという構造体が格納されているメモリの場所を表す変数」ですよね?
fana

2021/07/09 07:48

うん. しかし,今回の場合って,そこに「Token型のオブジェクトが格納されている」と言うのかなぁ? メモリ領域を「そこにToken型が存在していると思って」使っている,という感じ…? うーん,でも,その領域を Token型 として扱う以上はやはり「Token型のものが格納されている」でいいのかな. (一人で混乱中)
takuyaKK

2021/07/09 07:52

ありがとうございます!
BeatStar

2021/07/09 08:11 編集

K_3578さん そうですね。次からは本文に追記しますね。(一応、今回も書きますが) Harahiraさん あれって…保証されているってことでいいでしょうか fanaさん あー、確かに…… 修正しますね。
ppaul

2021/07/10 03:06

「後学のため」 です。 BeatStarさんの説明は、Cの言語仕様と、個別のCコンパイラの実装方法と、mallocなどのライブラリの仕様と、オブジェクトのフォーマットと、リンカの仕様が区別できていないように見えます。 Cの言語仕様的には、変数などは記憶域期間と可視かどうかという性質で判断すべきです。 それらが各コンパイラによってどのように実装されるかはコンパイラ次第です。私の知っている範囲でも、最適化レベルを上げた場合のgccやClangでは、静的でない局所変数や仮引数をスタックに置かないことは良くあります。 当然のことですが、静的な局所変数をスタックに置くコンパイラはありません。 なお私は評価はしない主義ですので低評価はつけていません。
BeatStar

2021/07/10 03:14

ppaulさん ありがとうございます。 別に低評価自体は問題ないですが、『どこが悪いのかな?』という疑問だけです。 > Cの言語仕様と、個別のCコンパイラの実装方法と、mallocなどのライブラリの仕様と、オブジェクトのフォーマットと、リンカの仕様が区別できていないように見えます (あ、そっちか……) 確かにそうですね…… もうちょっと調べてから修正します
guest

0

malloc/calloc/realloc された領域は free されぬ限り居座り続けます。
なのでこんなコード書いちゃダメ。呼び出されるたびにメモリをぢわぢわ食い潰します。

aというローカル変数の値はプログラムの実行終了までメモリ上に存在し続けることが保障されるという認識であってますでしょうか?

マチガイ。callocで確保された領域は居座ります。
が、その領域を指すaは関数から抜けたとたんに消えてなくなります。
結果確保された領域がどこだかわかんなくなるので開放できなくなります。

投稿2021/07/09 03:27

編集2021/07/09 03:46
episteme

総合スコア16614

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

takuyaKK

2021/07/09 04:29

質問に追記したのですが、構造体にnextという次の構造体を表すポインタを格納しておけば、確保された領域が分かるので、tree上に構造体を組み立てていくことができるという認識であってますでしょうか?
episteme

2021/07/09 06:09

関数内の tok は消えてなくなりますが、その値は呼び出し元に投げ返してますから、 呼び出し元がちゃんと管理し適宜開放してあげればよろしいですな。
takuyaKK

2021/07/09 08:24

ありがとうございます!理解できました!
guest

0

aというローカル変数の値はプログラムの実行終了までメモリ上に存在し続けることが保障されるという認識であってますでしょうか?

合っていません。aというポインタ変数はこの関数が終われば寿命を迎えます。

*aで指すメモリは、解放する(あるいはプログラムが終了する)まで保持されます。

投稿2021/07/09 03:25

maisumakun

総合スコア145201

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

takuyaKK

2021/07/09 04:29

質問に追記したのですが、構造体にnextという次の構造体を表すポインタを格納しておけば、確保された領域が分かるので、tree上に構造体を組み立てていくことができるという認識であってますでしょうか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問