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

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

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

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

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

ポインタ

ポインタはアドレスを用いてメモリに格納された値を"参照する"変数です。

Q&A

5回答

468閲覧

C言語 free ポインタ

KKKM

総合スコア16

C

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

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

ポインタ

ポインタはアドレスを用いてメモリに格納された値を"参照する"変数です。

0グッド

0クリップ

投稿2020/06/17 12:35

ある数字未満の数字を重複なし,順番ランダムで
配列に代入するプログラムを作成しました。
いろいろ実験しながら作ったので無駄な部分は多いのですが、、、

shuffle関数にて動的に配列を作っています。
動的に配列を作った場合はfreeで解放してあげる必要があると
様々なサイトで書かれていたことを頭のすみに入れながらプログラムを作ったらたくさんの疑問が生まれました

質問1 arrayに動的に作った配列array2のアドレスを格納し,freeしてみました。
僕としては動的に作った配列はfreeしないといけない意識があり,shuffle関数内でfreeしたかったのですが戻り値として設定したかったこともありshuffle関数内でのfreeをあきらめて同じポインタを持つarrrayをfreeした次第です。
しかし,freeの前後でarrayのアドレスは変わっていませんでした。何故でしょうか。

質問2 printf("%p",array[1]);でarray[1]のアドレス,すなわちarray[0]+1がアドレス表示されると思ったのですが格納された値が出力されました。何故でしょうか。

質問3 shafful関数でarray2をfreeした状態で戻り値にarray2を指定するとarray[2]以降はarray2の同じ要素が格納されています。freeしたから確保したアドレスはなくなり,array2が保持していた情報はなくなりエラーになるとおもったのですが

質問4int N ,B からarrayのアドレスまで大きく異なります。これはなぜでしょうか。

#include <stdio.h>
#include<stdlib.h>
#include<time.h>
int* shuffle(int N);

int main(){
srand((int)time(NULL));
int N = 10;
int B = 11;
int *array = shuffle(N);

for(int i = 0; i < N;i++){
printf("N [%d] %d\n",i,array[i]);
}
printf("adress %p\n",array);
free(array);
printf("address %p\n",N);
printf("address %p\n",B);
printf("address %p\n",array);
}

int* shuffle(int N){

int * array2 = (malloc)(sizeof(int)*N);

for(int i = 0; i < N ; i++){
int random = rand()%N;

if( i == 0){ array2[i] = random; printf("array[0] %d\n",random); } else{ int count = 0; for(int j = 0; j < i ; j ++){ //printf("random %d i %d\n",random,i); if( array2 [j] == random){ count = count + 1; i = i - 1; } else if( j == i - 1 && count == 0){ array2[i] = random; printf("array[%d] %d\n",i,array2[i]); } }

}

}
// free(array2);
//printf("address %p\n",array2);
return array2;
}

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

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

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

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

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

anndonut

2020/06/18 00:37

コードの部分は、コード貼り付け機能を使って貼り直していただけると見やすくなると思います。 ```C // コードの中身 ``` と記述します。
KKKM

2020/06/20 09:11

ありがとうございます。 そのような機能があるんですね,今後利用いたします。
hidezzz

2020/06/20 09:29 編集

質問文は後からでも「編集」ボタンを押して修正することが可能です。
guest

回答5

0

基本的な部分で理解が足りていません。

質問1 freeの前後でarrayのアドレスは変わっていませんでした。何故でしょうか。

arrayに入っているポインタ値の指すメモリブロックを開放しただけで、arrayという変数に何かを代入したわけじゃないので、変わりません。

質問2 printf("%p",array[1]);でarray[1]のアドレス,すなわちarray[0]+1がアドレス表示されると思ったのですが格納された値が出力されました。何故でしょうか。

アドレスを表示したいときは、アドレスを渡します。
printf("%p\n",&array[1]);

また、「array[1]のアドレス,すなわちarray[0]+1が」と言う理解も間違っています。
「array[1]のアドレス,すなわちarray+1が」なら、部分的には正しいです。

質問3 

質問1と同様。

質問4int N ,B からarrayのアドレスまで大きく異なります。これはなぜでしょうか

いずれのprintf結果もアドレスではないので、無意味な質問です。

投稿2020/06/17 13:14

otn

総合スコア85901

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

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

DreamTheater

2020/06/17 23:23

同感です。 メモリ管理云々以前に、ポインタ変数(というか変数全般)をもっと学習しましょう。
guest

0

freeの前後でarrayのアドレスは変わっていませんでした。

freeは引数のポインタを値渡しで受け取りますので、引数を書き換えることはできません。

質問2

array[1]のアドレスを渡したいときは、&array[1]のようにしてください。C言語は、printfの引数と実際に与えられる値の対応は取ってくれません。

freeしたから確保したアドレスはなくなり,array2が保持していた情報はなくなりエラーになるとおもったのですが

freeしたあとのポインタにアクセスした場合の動作は未定義です。消すのが面倒で残っていることもありえます(もちろん、アクセスした瞬間にクラッシュしても文句は言えません)。

int N ,B からarrayのアドレスまで大きく異なります。これはなぜでしょうか。

ローカル変数はスタック領域に取られますが、mallocはヒープから行います。メモリ領域が別物となっています。

投稿2020/06/17 13:13

maisumakun

総合スコア146018

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

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

0

mallocしたらfree, newしたらdeleteって思ってる人多いですけど、基本的に「トイレの戸を開けたら閉める」くらいのイメージでいいです。というと怒る人がいるので以下に詳細を述べます。

  • デスクトップPCのOSは堅牢なのでメモリを解放していない状態でプロセスを終了してもシステムに悪影響を与えない
  • デスクトップPCのアプリでmalloc, freeが問題になるのは、長時間動作し続けて、かつユーザ入力などが入って動作が複雑になる場合です。ワープロ、表計算ソフト、ブラウザなどがそれに該当するのですが、UNIXコマンドなどの単純な動作だけでプロセスが終了する場合はあえてfreeしない場合もあります。どうして問題になるかというとmallocの呼び出し回数が多い、もっというとmallocによる延べメモリ確保量が多いと開放されないメモリが増大しアプリがハングアップします(メモリリーク)。
  • 組込系OSでは確保したメモリを解放せずにプロセスを終了するとシステムに悪影響がでる場合があるそうです
  • デスクトップPCではファイルクローズ、DLLなどによる何らかのリソースを確保した後の解放のほうに気を配ったほうがいいです。ファイルクローズしないとデータが中途半端にしか書き込まれないことがあります。メモリではなくグラフィックスやサウンドなどの機能はOSの基幹機能ではないのでプロセス終了後に誤動作することはままあります。

要は、確保したリソースは解放しなければならないのです(解放してくださいと言われている場合は)。これはプログラミングの基本です。

どうやって動的メモリを扱えばいいのか

①動的メモリは基本的に呼び出し側で確保し、解放します。

C

1// ok 2void func1() { 3 char *s = malloc(101); 4 func2(s, 101); 5 free(s); 6}

C

1// ng 2void func1() { 3 char *s = malloc(101); 4 func2(s); 5} 6 7void func2(char *s) { 8 free(s); 9}

C

1// ng 2void func1() { 3 char *s = func2(); 4 free(s); 5} 6 7char *func2() { 8 char *s = malloc(101); 9 return s; 10}

②ライブラリ側で特殊なメモリ確保を行いたい場合は、メモリ確保とメモリ解放の関数を用意します。

malloc, freeの仕組みについて知りたい場合は「ヒープ」について学びましょう。

投稿2020/06/18 00:23

anndonut

総合スコア667

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

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

KKKM

2020/06/20 09:20

今までずっとメモリ アドレス,ポインタ,ヒープについて逃げてきましたが 腰を据えて勉強しなければですね。 サンプルまで記載いただきありがとうございます。
guest

0

質問1 freeの前後でarrayのアドレスは変わっていませんでした。何故でしょうか。

freeは、ヒープに確保された領域を解放(再利用できる状態に)しますが、自動的にarrayのアドレスを書き換えたりはしないから。freeした後のarrayの値を使わないこと(たとえば、NULLに設定しなおすなど)は、作成者に課せられた制約です。

質問2 printf("%p",array[1]);でarray[1]のアドレス,すなわちarray[0]+1がアドレス表示されると思ったのですが格納された値が出力されました。何故でしょうか。

array[X]*(array + X)と同じだからarray[0]のアドレスを求める式はarray(あるいはarray + 0)、array[1]のアドレスを求める式はarray + 1です。

質問3 shufful関数でarray2をfreeした状態で戻り値にarray2を指定すると(以下略)。

freeした後のarray2の値を利用してはいけません。解放されたヒープ領域は他の目的に使われる可能性があります。解放直後に値が残っているのは、「まだ他の目的で使われていなかったから」に過ぎません。なお、freeするとarray2のアドレスを自動的にundefined的な値に変更したり、array2[X]にアクセスするとエラーになるような親切さはC言語にはありません。

質問4int N ,B からarrayのアドレスまで大きく異なります。これはなぜでしょうか。

はじめに、NBはint型の変数なので、あなたがprintfで表示している値はポインターではありませんNBの値そのものです。「&N」や「&B」と書けば、おそらくあなたの欲しい情報が表示されます。これらの変数はスタックに確保されるので、表示されるアドレスはヒープに確保される領域を指すarrayの値とは大きく異なります。

投稿2020/06/17 13:22

Daregada

総合スコア11990

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

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

0

デバッグ環境を整えましょう。
Eclipseや、VisualStudioなど。
コードの任意の行で実行を止め、変数のナカミを参照できます。
また、1行づつ実行させ、コードの流れや変数のナカミの変化などをモニタできます。

そうすればあなたのその疑問のすべてが解決すると思いますよ

投稿2020/06/17 12:41

y_waiwai

総合スコア88042

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

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

maisumakun

2020/06/17 13:14

「文法的なもの」や「未定義動作に関わる箇所」、「メモリ配置」など、今回の質問内容はデバッガで追いかけて解決しないものばかりだという印象です。
KKKM

2020/06/20 09:16

デバック環境を整えて一から追っていくことが理解を助けてくれそうですね。 ありがとうございます
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問