2011-02-03 15 views
1

関数内で動的に(mallocを使用して)作成された配列を呼び出し元に戻すことはできますか?cの関数から文字配列を返す

静的に割り当てられた配列を返すことは間違っていることは知っています。なぜなら、関数が返って変数が有効ではなくなってもスタックは巻き戻されるからです。

+0

、またはあなたが念頭に置いていたことが、より複雑なものがありました:

例は、単にchar*を返しますか? – Swiss

+3

静的割り当て!=自動割り当て。ローカル変数には自動保存期間があります。 Static storage durationは、プログラムが実行されている時間全体にわたってオブジェクトが存在することを意味します(これらのオブジェクトは、ファイルスコープで宣言されるか、関数内で 'static'を使用して宣言されます)。 –

+0

いいえ、それは私がやりたいことです – theReverseFlick

答えて

5

mallocで割り当てられたものを返すのは問題ありません。あなたの関数を使う人は誰でも関数が終了したらfree()を処理します。 mallocは、プログラム内で本質的にグローバルなヒープ上に割り当てます。

+0

結局のところ、それはちょうど 'malloc()'自体の働きです。 – caf

+0

私が 'malloc'を使って割り当てたものを解放しないと、プログラムが終了すると、メモリ自体が解放されます。 – theReverseFlick

+0

@ShyamLovesToCode:はい、あなたのOS(またはそれに密接に関連するもの)が壊れていない限り、それは解放されます。あなたが手で使っているものを解放するのは、もっときれいです。 –

0

はいできます。ちょうどmalloc()あなたの関数内の配列とポインタを返します。

ただし、発信者はある時点で解放する必要があることを理解する必要があります。そうしないと、メモリリークが発生します。

0

mallocで割り当てられた配列を返すことはできますが、関数の呼び出し元は最終的にfreeで配列を解放する必要があります。 malloc配列を解放しないと、プログラムが終了するまでメモリは「使用中」のままです。

3

他にも触れたように、実際にはcharポインタを返すことができます。 しかし、もう1つの一般的な方法は、呼び出し元がメソッドのポインタを渡してlengthパラメータを指定する方法です。これにより、メモリの割り当てを担当する関数もメモリの解放を担当する関数と同じになり、メモリリークを見やすくすることができます。これは、snprintfstrncpyのような機能です。

/* Performs a reverse strcpy. Returns number of bytes written if dst is 
* large enough, or the negative number of bytes that would have been 
* written if dst is too small too hold the copy. */ 
int rev_strcpy(char *dst, const char *src, unsigned int dst_len) { 
    unsigned int src_len = strlen(src); /* assumes src is in fact NULL-terminated */ 
    int i,j; 

    if (src_len+1 > dst_len) { 
     return -(src_len+1); /* +1 for terminating NULL */ 
    } 

    i = 0; 
    j = src_len-1; 
    while (i < src_len) { 
     dst[i] = src[j]; 
     ++i; 
     ++j; 
    } 
    dst[src_len] = '\0'; 

    return src_len; 
} 

void random_function() { 
    unsigned int buf_len; 
    char *buf; 
    int len; 
    const char *str = "abcdefg"; 

    buf_len = 4; 
    buf = malloc(buf_len * sizeof(char)); 
    if (!buf) { 
     /* fail hard, log, whatever you want */ 
     return; 
    } 

    /* ...whatever randomness this function needs to do */ 

    len = rev_strcpy(buf, str, buf_len); 
    if (len < 0) { 
     /* realloc buf to be large enough and try again */ 
     free(buf); 
     buf_len = -len; 
     buf = malloc(buf_len * sizeof(buf)); 
     if (!buf) { 
      /* fail hard, log, whatever you want */ 
      return; 
     } 
     len = rev_strcpy(buf, str, sizeof(buf)); 
    } 

    /* ... the rest of the randomness this function needs to do */ 

    /* random_function has allocated the memory, random_function frees the memory */ 
    free(buf); 
} 

あなたが必要と二度関数を呼び出す必要がありますどのように大きなバッファを知りませんが、多くの場合、呼び出し側がどのように大きなバッファのニーズに良いアイデアを持っている場合が、これにはいくつかのオーバーヘッドにつながることができますすることが。また、関数が指定されたバッファーをオーバーランしないようにするには少しだけ論理が必要です。しかし、メモリを割り当てている間はメモリを解放し、オプションはローカルスタックメモリを渡すことができます。あなたは、ポインタを返すことができ

/* Performs a reverse strcpy. Returns char buffer holding reverse copy of 
* src, or NULL if memory could not be allocated. Caller is responsible 
* to free memory. */ 
char* rev_strcpy(const char *src) { 
    unsigned int src_len = strlen(src); /* assumes src is in fact NULL-terminated */ 
    char *dst; 
    int i,j; 

    dst = malloc((src_len+1) * sizeof(char)); 
    if (!dst) { 
     return NULL; 
    } 

    i = 0; 
    j = src_len-1; 
    while (i < src_len) { 
     dst[i] = src[j]; 
     ++i; 
     ++j; 
    } 
    dst[src_len] = '\0'; 

    return dst; 
} 

void random_function() { 
    char *buf; 
    const char *str = "abcdefg"; 

    /* ...whatever randomness this function needs to do */ 

    buf = rev_strcpy(str);   
    if (!buf) { 
     /* fail hard, log, whatever you want */ 
     return; 
    } 

    /* ... the rest of the randomness this function needs to do */ 

    /* random_function frees the memory that was allocated by rev_strcpy */ 
    free(buf); 
} 
関連する問題