LoginSignup
0
0

More than 1 year has passed since last update.

【C】初めてのC言語(14. ヒープの利用)

Posted at

はじめに

※今回の内容は、スッキリわかるC言語入門 第2版のp.384~p.389となります。

学習環境

  • 今回はpaiza.ioのC言語のエディタを使いました。

配列の限界

  • 以下のコードではtest()で作った配列arrayを戻り値としてmain()に渡そうとしています。
  • ところが関数test()の終了時点で、配列arrayとして確保されていたメモリが開放されてしまいます。
    • 配列arrayは、ここではメモリのスタック領域に作られます。
  • 結果的に、main()内でこの配列を操作しようとするとコンパイルエラーが発生してしまいます。
Main.c
#include <stdio.h>

int* test() {
	int array[3];
	return array;	// 配列arrayの先頭アドレスが返される。
}  // 関数終了に伴い、メモリ上で配列arrayが確保した領域が解除される。

int main(void) {
	int* a = test();
	a[0] = 5;  // 確保されていないメモリにアクセスしてしまう。
	return 0;
}
コンパイルエラーのメッセージ
Main.c:1:9: warning: treating Unicode character as whitespace [-Wunicode-whitespace]
#include <stdio.h>
        ^~
Main.c:5:9: warning: address of stack memory associated with local variable 'array' returned [-Wreturn-stack-address]
        return array;   // 配列arrayの先頭アドレスが返される。
               ^~~~~
2 warnings generated.

ヒープの利用

  • 上記のように、スタック領域に確保したメモリは関数の終了とともに解放されてしまいますが、malloc()calloc()でヒープ領域を確保すれば、関数が終了した後もメモリが解放されることはありません。
  • そのため、ヒープ領域を利用した時は必ず確保した領域を、free()で明示的に解放する必要があります。
    • メモリを正しく解放しないと、メモリを食いつぶしていくメモリーリークの原因となります。

malloc関数

  • ヒープ領域に連続したメモリを確保する場合に使われる関数です。
    • 引数として確保したいサイズ(バイト数)を入れるだけで、ヒープ領域にメモリを確保できます。
  • 確保したメモリ領域は、利用しなくなった所でfree()を呼び出して明示的に解放します。
Main.c
#include <stdio.h>
#include <stdlib.h>

int* test(void) {
    // ヒープに12バイト(※int型配列の3要素分)を確保する。
    int* array = (int*)malloc(sizeof(int) * 3);
    
    array[0] = 2;
    array[1] = 4;
    array[2] = 6;
    return array;   // arrayの先頭アドレスが返される。
}   // 関数が終了しても、ヒープに確保したメモリは解放されない。

int main(void) {
    int* a = test();
    
    if (a==NULL) {
        printf("ヒープ確保に失敗しました。");
    } else {
        // ヒープに確保されているメモリにアクセスする。
        for (int i=0; i<3; i++) {
            printf("%d番目の要素は%dです。\n", (i+1), a[i]);
        }
        
        free(a);  // ヒープ領域を解放する。
    }
    
    return 0;
}
実行結果
1番目の要素は2です。
2番目の要素は4です。
3番目の要素は6です。

calloc関数

  • ヒープ領域に連続したメモリを確保する場合に使われる関数ですが、mallocと違って「メモリを確保した直後に内容を0で埋める」という特徴があります。
  • またmalloc()とは違い、第1引数が「要素数」、第2引数が「各要素の長さ(バイト数)」となります。
  • 確保したメモリ領域は、利用しなくなった所でfree()を呼び出して明示的に解放します。
Main.c
#include <stdio.h>
#include <stdlib.h>

int* test(void) {
    // ヒープにint型の3要素分(※12バイト)をのメモリを確保する。
    int* array = (int*)calloc(3, sizeof(int));
    
    array[1] = 4;
    return array;   // arrayの先頭アドレスが返される。
}   // 関数が終了しても、ヒープに確保したメモリは解放されない。

int main(void) {
    int* a = test();
    
    if (a==NULL) {
        printf("ヒープ確保に失敗しました。");
    } else {
        // ヒープに確保されているメモリにアクセスする。
        for (int i=0; i<3; i++) {
            printf("%d番目の要素は%dです。\n", (i+1), a[i]);
        }
        
        free(a);  // ヒープ領域を解放する。
    }
    
    return 0;
}
実行結果
1番目の要素は0です。
2番目の要素は4です。
3番目の要素は0です。

参考URL

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0