2

今日、割り当てられたメモリへのポインターを返すことを実験するために、次のコードを書きました。プログラムは正常に動作しますが、いくつか質問があります。

  1. の戻り値にメモリを割り当てるには、rmchを使用しますrealloc。私は関数とそれが何をするのかを理解していますが、割り当てられたメモリのサイズを #c chars に変更することを理解して(char *)いる行のポイントが何であるかはよくわかりませんが、その部分は何をしますか?ret = (char *) realloc(ret, c * sizeof(char));realloc(ret, c * sizeof(char));(char *)

  2. retどこかを指す割り当てられたメモリは解放しませんretが、関数で呼び出されるポインタは解放しますmain。割り当てられたメモリに何が起こっていますか? 解放されていない場合、どうすれば解放できますか?

コード

#include <stdio.h>
#include <stdlib.h>
char* rmch(char *str, char ch)
{
    char *ret = NULL;
    int c = 0, i;

    for(i = 0; str[i] != '\0'; i++)
    {
        if(str[i] != ch)
        {
            c++;
            ret = (char *) realloc(ret, c * sizeof(char));
            ret[c - 1] = str[i];
        }
    }
    ret[c] = '\0';
    return ret;
}

int main(void)
{
    char *foo = rmch("f o o", ' ');

    printf("%s", foo);
    free(foo);
    return 0;
}
4

3 に答える 3

2

mainでFooを解放すると、rmchで再割り当てしたretが解放されます。

free()である理由は、rmchによって返されるポインタによって指定されたアドレスに移動します。

また、この投稿に「C」タグを付けているので、割り当ての戻り値をキャストしないでください。void *'s割り当て中に正しいバイトサイズが指定されていれば、自動的に、暗黙的に、格納されているものにプロモートされます。

余談ですが、割り当てられたメモリを、使用している/使用する予定のポインタに直接格納しないでください。返されたポインタがNULLで、まだ古いメモリを指している場合、メモリリークが発生する可能性があります。

これを行う方が良いです:

temp = realloc();
if( temp == NULL)
{
     printf("realloc failed to reallocated memory!");
     return NULL;
}
ret = temp;

そして、メインでもNULLリターンをチェックする必要があります。

于 2012-08-02T19:31:39.270 に答える
1

コードにはまだもう 1 つの問題があります。valgrind で実行すると、次のようになります。

toc@UnixServer:~$valgrind --leak-check=full --show-reachable=yes ./realloc_pb
==17077== Memcheck, a memory error detector
==17077== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==17077== Using Valgrind-3.6.1-Debian and LibVEX; rerun with -h for copyright info
==17077== Command: ./realloc_pb
==17077== 
==17077== Invalid write of size 1
==17077==    at 0x80484BF: rmch (realloc_pb.c:19)
==17077==    by 0x80484E3: main (realloc_pb.c:25)
==17077==  Address 0x41b709b is 0 bytes after a block of size 3 alloc'd
==17077==    at 0x402896C: realloc (vg_replace_malloc.c:525)
==17077==    by 0x804848A: rmch (realloc_pb.c:14)
==17077==    by 0x80484E3: main (realloc_pb.c:25)
==17077== 
==17077== Invalid read of size 1
==17077==    at 0x402903D: __GI_strlen (mc_replace_strmem.c:284)
==17077==    by 0x4098739: puts (ioputs.c:37)
==17077==    by 0x4050112: (below main) (libc-start.c:226)
==17077==  Address 0x41b709b is 0 bytes after a block of size 3 alloc'd
==17077==    at 0x402896C: realloc (vg_replace_malloc.c:525)
==17077==    by 0x804848A: rmch (realloc_pb.c:14)
==17077==    by 0x80484E3: main (realloc_pb.c:25)
==17077== 
foo
==17077== 
==17077== HEAP SUMMARY:
==17077==     in use at exit: 0 bytes in 0 blocks
==17077==   total heap usage: 3 allocs, 3 frees, 6 bytes allocated
==17077== 
==17077== All heap blocks were freed -- no leaks are possible
==17077== 
==17077== For counts of detected and suppressed errors, rerun with: -v
==17077== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 11 from 6)

null で終了する文字により多くのスペースを割り当てる必要があるため、これも変更します。

temp = (char *) realloc(ret, (c + 1) * sizeof(char)); // It's better to use temp pointer as suggested by ardent sonata

最後に、malloc または realloc 関数のキャストについて説明します。これは実際には必要ありません。正しいヘッダー (stdlib.h) を追加するのを忘れた場合にコンパイラに役立つため、コンパイラは警告を表示できます ( http://c-faq. com/malloc/mallocnocast.html )。

この助けを願っています。

よろしく。

于 2012-08-02T20:55:06.090 に答える
0

mallocまたはcalloc、指定したサイズのメモリを割り当てます。reallocすでに割り当てられているメモリのサイズを変更します。既存のヒープバッファを縮小または拡張できます。

たとえば、既存のヒープバッファをnバイトからバイトに拡張する場合は、のn+1ようにreallocを呼び出す必要があることを意味しますrealloc(existing_bufPtr, n+1)。ここで、OSは既存のバッファを1バイト増やす必要があるため、n+1からのバイトexisting_bufPtrが他の目的に割り当てられていないかどうかを確認します。その場合、既存のバッファのサイズをに拡張するn+1か、別の場所に新しいバッファを割り当て、既存のバッファから新しいバッファに値を移動します。そして、新しく割り当てられたバッファの開始アドレスを返します。

したがって、前のバッファを解放する必要がある場合は、返されるアドレスが渡されたものと同じであるかどうかを確認する必要があります。したがって、コードを次のように変更します

if(str[i] != ch)
{
   c++;
   ret_new = (char *) realloc(ret, c * sizeof(char));
   if (NULL == ret_new)     
   {
       return NULL;
   }
   else if (ret_new != ret)
   {
       free(ret);
       ret = ret_new;
   }

   ret[c - 1] = str[i];
}

を使用して既存のヒープバッファを縮小してもrealloc、新しいアドレスは返されません。ただし、展開すると新しいアドレスが返される場合があります。

reallocポインタ型をとして返します。void *ポインタの型に大文字小文字を区別する必要がありますchar *

メモリ割り当て関数(、、mallocまたはcallocreallocは、オペレーティングシステムにとって常にコストのかかる操作です。reallocしたがって、時間を呼び出す代わりに、をn使用してメモリを1回だけ割り当てるmalloc(sizeof(str))と、パフォーマンスが向上します。

于 2012-08-03T04:42:31.797 に答える