Linux講座にようこそ。このページは「C言語プログラミング入門 - 第14章.ライブラリ関数 - メモリ操作ライブラリ」です。

C言語プログラミング入門

14. ライブラリ関数(27/36) - メモリ操作ライブラリ(2/2)

14.40 メモリ操作関数

14.40.1 malloc関数

malloc関数は指定した大きさのメモリ領域を確保して、その先頭アドレスを返り値として返します。返り値の型名はvoid型ですので、このままでは使えません。通常、型変換(キャスト)演算子で型変換して使用します。(具体的には例題をご覧ください)

【表14-6-2】 malloc関数
形式#include <stdlib.h>
void *malloc(size_t size);
返り値確保したメモリ領域の先頭アドレスを返します。エラーの場合はNULLを返します。
引数
size_t size
確保するメモリ領域の大きさをバイト単位で指定します。

14.40.2 calloc関数

calloc関数はmalloc関数と同じく、指定した大きさのメモリ領域を確保して、その先頭アドレスを返り値として返します。malloc関数との相違は確保した領域を0(全ビット0)でクリアする事です。

【表14-6-3】 calloc関数
形式#include <stdlib.h>
void *calloc(size_t nmemb, size_t size);
返り値確保したメモリ領域の先頭アドレスを返します。エラーの場合はNULLを返します。
引数
size_t nmemb
要素の大きさをバイト単位で指定します。
size_t size
要素の数を指定します。確保する領域の大きさは「要素の大きさ×要素の数」になります。

14.40.3 realloc関数

realloc関数はcalloc関数やmalloc関数で確保したメモリ領域の大きさを変更して、その先頭アドレスを返り値として返します。領域を大きくした場合は元の内容はそのまま残っています。なお、領域が別の場所に移動する場合もありますので注意してください。(第1引数のptrの値と戻り値は一致するとは限りません)

【表14-6-4】 realloc関数
形式#include <stdlib.h>
void *realloc(void *ptr, size_t size);
返り値変更後のメモリ領域の先頭アドレスを返します。エラーの場合はNULLを返します。なお、エラーの場合は指定した領域は元のままです。
引数
void *ptr
変更するメモリ領域の先頭アドレスを指定します。
size_t size
変更後のメモリ領域の大きさをバイト単位で指定します。

14.40.4 free関数

free関数はcalloc関数やmalloc関数で確保したメモリ領域を開放します。

【表14-6-5】 free関数
形式#include <stdlib.h>
void free(void *ptr);
返り値ありません。
引数
void *ptr
開放するメモリ領域の先頭アドレスを指定します。

14.40.5 例題

実行時引数で指定したファイルの中のタブ文字を半角スペースに置換した結果を表示します。ファイルの内容はmalloc関数で確保したメモリ領域に格納しますが、領域が一杯になった場合はrealloc関数で拡張します。領域の最初の大きさは100バイトで、一杯になった場合は100バイトずつ拡張します。

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #define EXPAND_SIZE    100
  5. #define LINE_MAX       1024
  6.  
  7. int main(int argc, char **argv)
  8. {
  9.     FILE    *fp;
  10.     int     buff_max = EXPAND_SIZE;    /* データ格納領域の大きさ */
  11.     int     buff_used = 0;             /* データ格納領域の使用量 */
  12.     char    *p_buff_top;               /* データ格納領域の先頭 */
  13.     char    line[LINE_MAX];
  14.     char    *p_line;
  15.     int     line_len;
  16.  
  17.     if(argc != 2)
  18.     {
  19.         printf("実行時引数が不当です。\n");
  20.         return 1;
  21.     }
  22.  
  23.     if((fp = fopen(*(argv + 1), "r")) == NULL)
  24.     {
  25.         printf("%sがオープンできません。\n", *(argv + 1));
  26.         return 1;
  27.     }
  28.  
  29.     /* データ格納領域を確保 */
  30.     if((p_buff_top = (char *)malloc(buff_max)) == NULL)
  31.     {
  32.         printf("データ格納領域が確保できません。\n");
  33.         return 1;
  34.     }
  35.  
  36.     while(fgets(line, LINE_MAX, fp) != NULL)
  37.     {
  38.         p_line = line;
  39.         while((p_line = strchr(p_line, '\t')) != NULL)
  40.         {
  41.             /* タブ文字をスペースに置換 */
  42.             *p_line = ' ';
  43.             ++p_line;
  44.         }
  45.  
  46.         line_len = strlen(line);
  47.         /* 入力データがデータ格納領域に収まるかをチェック */
  48.         if((buff_used + line_len + 1) > buff_max)
  49.         {
  50.             /* データ格納領域を拡張 */
  51.             buff_max += EXPAND_SIZE;
  52.             if((p_buff_top = (char *)realloc(p_buff_top, buff_max)) == NULL)
  53.             {
  54.                 printf("データ格納領域が拡張できません。\n");
  55.                 return 1;
  56.             }
  57.         }
  58.  
  59.         /* スペースに置換後の入力データをデータ格納領域にコピー */
  60.         memcpy(p_buff_top + buff_used, line, line_len);
  61.         buff_used += line_len;
  62.         *(p_buff_top + buff_used) = '\0';
  63.     }
  64.  
  65.     fclose(fp);
  66.  
  67.     /* タブ文字をスペースに置換した結果を表示 */
  68.     printf("%s", p_buff_top);
  69.  
  70.     /* データ格納領域を開放 */
  71.     free(p_buff_top);
  72.  
  73.     return 0;
  74. }
$ wc ./DATA/ex14_2_5.dat
  8  19 102 ./DATA/ex14_2_5.dat ← ex14_2_5.datの容量は102バイトです
$ cat ./DATA/ex14_2_5.dat
main()
{
        short   bango   =       12;
        int     nenrei;
        float   taijyu  =       65.5;
        double  sintyo;
        char    ketueki =       'A';
}
$
$ cat -t ex14_2_5.dat ← -tはタブ文字を見えるように(^I)表示するオプションです
main()
{
^Ishort^Ibango^I=^I12;
^Iint^Inenrei;
^Ifloat^Itaijyu^I=^I65.5;
^Idouble^Isintyo;
^Ichar^Iketueki^I=^I'A';
}
$
$ ./ex14_6_1.prg ./DATA/ex14_2_5.dat
main()
{
 short bango = 12;
 int nenrei;
 float taijyu = 65.5;
 double sintyo;
 char ketueki = 'A';
}
$
3行目
メモリ操作関数を使いますのでstdlib.hを取り込みます。
30行目
入力データを格納する100バイトの領域をmalloc関数で確保します。確保した領域のアドレスはvoid型ですので、ここでは明示的に型変換演算子でchar型のポインタに変換しています。ただし、代入先のp_buff_top変数はchar型のポインタとして宣言していますので、直接代入しても自動的に型変換して代入します。
52行目
入力データを格納する領域をrealloc関数で100バイト拡張します。malloc関数で確保した時と同様に、明示的にchar型のポインタに変換しています。