Возвращение массива символов из функции в c - PullRequest
1 голос
/ 03 февраля 2011

Могу ли я вернуть массив, который создается динамически (с помощью malloc) внутри функции, обратно ее вызывающей стороне?

Я знаю, что возвращать статически размещенный массив неправильно, потому что стек раскручивается при возврате функции, а переменная больше не действительна, но как насчет динамически размещаемой переменной?

Ответы [ 4 ]

5 голосов
/ 03 февраля 2011

Возврат всего, что выделено с помощью malloc, - это нормально, если кто-то, кто использует вашу функцию, позаботится о free (), когда все будет сделано. malloc размещается в куче, которая по сути глобальна в вашей программе.

3 голосов
/ 03 февраля 2011

Как уже отмечали другие, вы можете фактически вернуть указатель на символ.Однако другой распространенный метод - вызывающая сторона передает указатель для метода для заполнения вместе с параметром длины.Это делает так, что функция, ответственная за выделение памяти, будет той же самой функцией, ответственной за освобождение памяти, которая может сделать утечки памяти легче видимыми.Это то, что делают такие функции, как snprintf и strncpy.

/* 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); 
}

Это может привести к некоторым издержкам, хотя, если вы не знаете, какой большой буфер вам понадобится, и вам нужно вызватьфункция дважды, но часто вызывающая сторона имеет хорошее представление о том, насколько большим должен быть буфер.Также требуется немного больше логики, чтобы гарантировать, что функция не переполняет данный буфер.Но он по-прежнему несет ответственность за освобождение памяти за счет того, что выделяет память, а также за возможность передачи локальной памяти стека.

Пример, возвращающий char*:

/* 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); 
}
0 голосов
/ 03 февраля 2011

Вы, конечно, можете вернуть массив, выделенный с помощью malloc, но вы должны убедиться, что вызывающая функция в конечном итоге освободит массив с free;если вы не освободите массив malloc, память останется «используемой» до завершения программы.

0 голосов
/ 03 февраля 2011

Да, вы можете.Просто malloc() массив внутри вашей функции и возврат указателя.

НО, вызывающий должен понимать, что в какой-то момент его нужно освободить, иначе у вас будет утечка памяти.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...