web-dev-qa-db-ja.com

Cプログラミング:別の関数内のmalloc()

malloc()別の関数の内部で助けが必要です

main()から関数にpointerおよびsizeを渡しているので、そのポインタにメモリを動的に割り当てたいmalloc()は、呼び出された関数の内部からですが、私が見るのは...割り当てられているメモリは、呼び出された関数内で宣言されたポインター用であり、main()内のポインター用ではありません。

ポインタを関数に渡し、呼び出された関数内から渡されたポインタにメモリを割り当てる方法


次のコードを作成しましたが、次のような出力が得られます。

ソース:

int main()
{
   unsigned char *input_image;
   unsigned int bmp_image_size = 262144;

   if(alloc_pixels(input_image, bmp_image_size)==NULL)
     printf("\nPoint2: Memory allocated: %d bytes",_msize(input_image));
   else
     printf("\nPoint3: Memory not allocated");     
   return 0;
}

signed char alloc_pixels(unsigned char *ptr, unsigned int size)
{
    signed char status = NO_ERROR;
    ptr = NULL;

    ptr = (unsigned char*)malloc(size);

    if(ptr== NULL)
    {
        status = ERROR;
        free(ptr);
        printf("\nERROR: Memory allocation did not complete successfully!");
    }

    printf("\nPoint1: Memory allocated: %d bytes",_msize(ptr));

    return status;
}

プログラム出力:

Point1: Memory allocated ptr: 262144 bytes
Point2: Memory allocated input_image: 0 bytes
59

関数へのパラメーターとして、ポインターへのポインターを渡す必要があります。

int main()
{
   unsigned char *input_image;
   unsigned int bmp_image_size = 262144;

   if(alloc_pixels(&input_image, bmp_image_size) == NO_ERROR)
     printf("\nPoint2: Memory allocated: %d bytes",_msize(input_image));
   else
     printf("\nPoint3: Memory not allocated");     
   return 0;
}

signed char alloc_pixels(unsigned char **ptr, unsigned int size) 
{ 
    signed char status = NO_ERROR; 
    *ptr = NULL; 

    *ptr = (unsigned char*)malloc(size); 

    if(*ptr== NULL) 
    {
        status = ERROR; 
        free(*ptr);      /* this line is completely redundant */
        printf("\nERROR: Memory allocation did not complete successfully!"); 
    } 

    printf("\nPoint1: Memory allocated: %d bytes",_msize(*ptr)); 

    return status; 
} 
71
Mark Ransom

関数にポインターを渡し、呼び出された関数内から渡されたポインターにメモリを割り当てるにはどうすればよいですか?

自問してみてください:intを返さなければならない関数を書かなければならなかったら、どうしますか?

直接返すか:

int foo(void)
{
    return 42;
}

または indirection のレベルを追加して、出力パラメーターを介して返します(つまり、int*の代わりにint):

void foo(int* out)
{
    assert(out != NULL);
    *out = 42;
}

そのため、ポインタ型(T*)、同じことです。ポインタ型を直接返すか、

T* foo(void)
{
    T* p = malloc(...);
    return p;
}

または、1レベルの間接参照を追加します。

void foo(T** out)
{
    assert(out != NULL);
    *out = malloc(...);
}
88
jamesdlin

関数でポインター自体を変更する場合は、ポインターへのポインターとして渡す必要があります。簡単な例を示します。

void allocate_memory(char **ptr, size_t size) {
    void *memory = malloc(size);
    if (memory == NULL) {
        // ...error handling (btw, there's no need to call free() on a null pointer. It doesn't do anything.)
    }

    *ptr = (char *)memory;
}

int main() {
   char *data;
   allocate_memory(&data, 16);
}
8
Matti Virkkunen

ポインターを渡す必要がありますby reference、ではなくby copy、関数_alloc_pixels_のパラメーターにはアンパサンド&ポインターのアドレスを返す-つまり、C話すのcall by reference.

 main()
 {
 unsigned char * input_image; 
 unsigned int bmp_image_size = 262144; 
 
 if(alloc_pixels(&input_image 、bmp_image_size)== NULL)
 printf( "\ nPoint2:割り当てられたメモリ:%dバイト"、_msize(input_image)); 
 else 
 printf( "\ nPoint3:メモリ割り当てられていません」); 
 
} 
 
 signed char alloc_pixels(unsigned char ** ptr、unsigned intサイズ)
 {
 signed char status = NO_ERROR; 
 * ptr = NULL; 
 
 * ptr =(unsigned char *)malloc(size); 
 
 if((* ptr )== NULL)
 {
 status = ERROR; 
/* free(ptr); 
 printf( "\ nERROR:メモリ割り当てが正常に完了しませんでした! "); */
} 
 
 printf( "\ nPoint1:割り当てられたメモリ:%dバイト"、_msize(* ptr)); 
 
 return状態;
}

_alloc_pixels_関数内のfree(ptr)と "ERROR:..."の2行をコメントアウトしています。メモリ割り当てが失敗した場合、freeポインタを使用する必要はありません。

Edit:OPが提供する msdn リンクを参照すると、コードサンプルは以前の回答と同じになります。..しかし... printf(...)main()呼び出しで、_%u_型の形式指定子を_size_t_に変更します。

 main()
 {
 unsigned char * input_image; 
 unsigned int bmp_image_size = 262144; 
 
 if(alloc_pixels(&input_image 、bmp_image_size)== NULL)
 printf( "\ nPoint2:割り当てられたメモリ:%uバイト"、_msize(input_image)); 
 else 
 printf( "\ nPoint3:メモリ割り当てられていません」); 
 
} 
4
t0mm13b

これは意味がありません:

if(alloc_pixels(input_image, bmp_image_size)==NULL) 

alloc_pixelssigned charERRORまたはNO_ERROR)を返し、それをNULL(ポインターに使用されることになっている)と比較します。

input_imageを変更する場合は、alloc_pixelsにポインターを渡す必要があります。 alloc_pixels署名は次のようになります。

signed char alloc_pixels(unsigned char **ptr, unsigned int size)

次のように呼び出します。

alloc_pixels(&input_image, bmp_image_size);

そして、メモリ割り当て

*ptr = malloc(size);
2
Bertrand Marron

あなたの初期コードでは、input_imageを関数alloc_pixelsに渡すときに、コンパイラはそのコピー(つまり、ptr)を作成し、値をスタックに保存していました。 mallocによって返された値をptrに割り当てます。関数がmainに戻り、スタックが巻き戻されると、この値は失われます。そのため、メモリはヒープ上に割り当てられたままですが、メモリの場所がinput_imageに格納(または割り当て)されなかったため、問題が発生しました。

わかりやすい関数alloc_pixelsのシグネチャを変更できます。追加の「ステータス」変数も必要ありません。

unsigned char *alloc_pixels(unsigned int size)
{
    unsigned char *ptr = NULL;
    ptr = (unsigned char *)malloc(size);
    if (ptr != NULL)
       printf("\nPoint1: Memory allocated: %d bytes",_msize(ptr));
    return ptr;
}

Mainで上記の関数を呼び出すことができます:

int main()
{
   unsigned char *input_image;
   unsigned int bmp_image_size = 262144;

   if((input_image = alloc_pixels(bmp_image_size))==NULL)
       printf("\nPoint3: Memory not allocated");    
   else
     printf("\nPoint2: Memory allocated: %d bytes",_msize(input_image)); 
   return 0;

}
1
juventus

パラメーターの割り当ては、値をaddressに設定した場合にのみ機能します。

この問題を解決する前に知っておくべき2つのポイントがあります。
1。 C関数:関数に渡したすべてのパラメーターは、関数のコピーになります。

つまり、関数で行ったすべての割り当ては、関数外の変数に影響を与えず、実際にはcopyで作業しています:

int i = 1;
fun(i);
printf("%d\n", i);
//no matter what kind of changes you've made to i in fun, i's value will be 1

したがって、関数のiを変更する場合は、Thingとそのコピーの違いを知る必要があります。

コピーはvalueをThingと共有しましたが、addressは共有しませんでした。

そして、それが唯一の違いです。

したがって、関数でiを変更する唯一の方法は、iのアドレスを使用することです。

たとえば、新しい関数fun_addrがあります。

void fun_addr(int *i) {
    *i = some_value;
}

このようにして、iの値を変更できます。

  1. malloc

Fun_addr関数の重要なポイントは、関数にアドレスを渡したことです。そして、そのアドレスに保存されている値を変更できます。

Mallocは何をしますか?

mallocは新しいメモリ空間を割り当て、そのアドレスを指すポインタを返します

この指示を見てください:

int *array = (int*) malloc(sizeof(int) * SIZE);

あなたがしていることは、配列の値をmallocによって返されたアドレスと等しくすることです。

見る?これは同じ質問であり、関数に渡されるパラメーターに値を永続的に割り当てます。この時点で、値はaddressです。

次に、アドレス(mallocによって返される)をアドレスに割り当てます(古いアドレスを格納します)。

したがって、コードは次のようになります。

void fun_addr_addr(int **p) {
    *p = (int*) malloc(sizeof(int) * SIZE);
}

これは動作します。

1
VELVETDETH

私がこの関数で持っていた同様の問題を解決するためのポインターソリューションへのポインターを取得できる唯一の方法

    BOOL OpenBitmap2 ( LPCTSTR pszFileName, char** pszBMPFile)  

一時的なポインタを割り当てて住所を保存することにより

    char* BMPFile;
    { BMPFile = (char*)GlobalAlloc(GPTR, dwFileSize + 1);   // allocate storage using GlobalAlloc + 1 for null term string

その後、再割り当て

    {* pszBMPFile = BMPFile; return (0);} // Error = False

GlobalAllocで「* pszBMPFile」を直接使用してもうまくいかなかった理由についてのコメントをいただければ幸いです。私は自分の質問に答えました。コードの他の行でpszBMPFileを使用して「*」を実行するのを忘れていました。すべての貢献者からの良いレッスン。どうもありがとう。

1
PeterS