C言語関係掲示板

過去ログ

No.977 malloc()等で確保した領域のサイズを後から調べる方法

[戻る] [ホームページ]
No.12689

malloc()等で確保した領域のサイズを後から調べる方法
投稿者---はしもと(2004/02/12 16:06:34)


お世話になります。

たとえば、以下のように領域確保したとして

char * damy ;
damy = (char*)malloc(5);

このときdamyに割り当てられた領域のサイズは5ですよね?

で、あとから、damyを使って領域のサイズを知る方法ってあるのでしょうか?
sizeof(damy)だとポインタのサイズ4が帰って来てしまうし。

ご存知の方教えていただけないでしょうか?
よろしくお願いします。

No.12713

Re:malloc()等で確保した領域のサイズを後から調べる方法
投稿者---RAPT(2004/02/13 02:27:03)


ありません。自前でサイズを覚えておくしかありません。
C++等なら、クラスで逃がすって、手段もありますが。

参考までに、C言語でクラスによる隠蔽を真似た簡単なサンプルソースを
掲載します。

※Windows2000/VC++6(Console)で動作確認済み


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

typedef struct{
  size_t size;  /* 確保した領域の個数 */
  size_t typesize;  /* 扱う型のサイズ */
  char *psz;  /* 実際に確保する領域へのポインタ */
} my_type;

void my_free(my_type *pT){
  if (pT->psz){
    free(pT->psz);
    pT->psz = NULL;
  }
  pT->size = 0;
  pT->typesize = 0;
}

void my_alloc(my_type *pT, size_t typesize, size_t n){
  my_free(pT);  /* 既存のメモリ割り当てがあれば、ここで開放 */
  pT->psz = (char *)malloc(typesize * (1+n));
  if (pT->psz == NULL){
    return;
  }
  memset(pT->psz, 0, typesize * (1+n)); /* 0で初期化 */
  pT->typesize = typesize;
  pT->size = n;
}

int main(){
  my_type a = {0}; /* ここで初期化しないとエラーになる */

  /* char型の例 */
  my_alloc(&a, sizeof(char), 10);
  if(a.size == 0){
    /* メモリの確保に失敗 */
    return 1;
  }
  strncpy(a.psz, "0123456789abcdef", a.size);
  printf("%s\n", a.psz);

  /* int型の例 */
  my_alloc(&a, sizeof(int), 1);
  if(a.size == 0){
    /* メモリの確保に失敗 */
    return 1;
  }
  *(int*)a.psz = 1054;  /* pszは、(char*)型なので、まず(int*)型にキャストしてから使用する */
  printf("%d\n", *(int*)a.psz);

  /* 最後にメモリを開放する */
  my_free(&a);

  return 0;
}


No.12735

Re:malloc()等で確保した領域のサイズを後から調べる方法
投稿者---はしもと(2004/02/13 15:20:50)


> ありません。自前でサイズを覚えておくしかありません。
> C++等なら、クラスで逃がすって、手段もありますが。
>
> 参考までに、C言語でクラスによる隠蔽を真似た簡単なサンプルソースを
> 掲載します。

回答ありがとうございます。
挙げていただいた例だと、
アロケートサイズ取得関数 getAllocSize()みたいなのを作って、
変数にアクセスするようにすれば、擬似的に実現できるわけですね。

Cって、ありそうな”あると便利”な機能ってほとんど存在しないですね。
面倒な言語だなあ…

No.12795

Re:malloc()等で確保した領域のサイズを後から調べる方法
投稿者---NykR(2004/02/17 03:10:20)


>Cって、ありそうな”あると便利”な機能ってほとんど存在しないですね。
>面倒な言語だなあ…

確保された領域は、別の領域と重なったりしないし、freeで解放するときも確保した領域分をちゃんと解放します。
mallocの戻り値を表示させてみても(私の環境では、ですが)アドレスは確保した順番に、(大体)確保したサイズ分だけ大きくなっていってるし。
だから、サイズに関するデータはどこかにあるはずです。
けれども、それを取得する方法は用意されていません。

でも、大抵直前のアドレスあたりに入ってたりして・・・、

というわけで擬似的にそういうものを作るのは可能です。

#include <stdlib.h>

/*
 * MyAllocで確保した領域は連結リストで管理する.
 */
typedef struct AllocListItem_tag {
    size_t     *alloc;
    struct AllocListItem_tag *next;
} AllocListItem;

static AllocListItem   *st_head;

/*
 * 配列の登録
 * 登録に成功したら1を, 失敗したら0を返す. 
 */
static int st_add(void *allocArray)
{
    AllocListItem      *newItem = malloc( sizeof(AllocListItem) );
    if (newItem == NULL) {
        return 0;
    }
    newItem->alloc = allocArray;
    newItem->next = st_head;
    st_head = newItem;

    return 1;
}

/* malloc */
void *MyAlloc(size_t size)
{
    size_t     *allocData = malloc( sizeof(size_t) + size );

    if (!allocData) {
        return NULL;
    }

    if ( !st_add(allocData + 1) ) {
        free(allocData);
        return NULL;
    }

    allocData[0] = size;

    return allocData + 1;
}

/* sizeof */
size_t GetSize(const void *allocArray)
{
     AllocListItem     *p;

    for (p = st_head; p != NULL; p = p->next) {
        if (p->alloc == allocArray) {
            return p->alloc[-1];
        }
    }
    return 0;
}

/* free */
void MyFree(void *allocArray)
{
    AllocListItem      *p, *prev = NULL;

    for (p = st_head; p != NULL; p = p->next) {
        if (p->alloc == allocArray) {
            free(p->alloc - 1);

            if (p == st_head) {
                st_head = p->next;
            } else {
                prev->next = p->next;
            }
            free(p);

            return;
        }
        prev = p;
    }
    free(allocArray);
}