C функция, возвращающая строку - PullRequest
1 голос
/ 02 апреля 2020

Я попытался создать функцию toString в C, например, так:

struct esploratore {
    char nome[20];
    char cognome[20];
    int nascita;
    int morte;
};

char *esploratoreToString(esploratore e) {
    char *s = (char*) malloc(50 * sizeof(char));
    snprintf(s, 50,
             "%s %s %d %d",
             e.nome, e.cognome, e.nascita, e.morte);
    return s;
}

и использовать ее в main следующим образом:

printf("%s", esploratoreToString(e));

it работает, но проблема в том, будет ли когда-нибудь освобождена память, назначенная mallo c?

это единственное решение?

char *s = esploratoreToString(e);
...
printf("%s\n\n", s);
free(s);

Ответы [ 4 ]

2 голосов
/ 02 апреля 2020

В вашем исходном коде память не будет освобождена. Это утечка памяти.

Для правильного вызова этой функции вам нужно будет сделать

char *s = esploratoreToString(e);
printf("%s", s);
free(s);

На самом деле нет никакого способа обойти это, если у вас будет esploratoreToString сделать распределение. Динамически размещенные объекты в C никогда не освобождаются. (C ++ - это другая история ...)

(Конечно, esploratoreToString должен проверить, что malloc успешно, прежде чем продолжить ...)

0 голосов
/ 04 апреля 2020

Существует альтернатива, в которой вы предоставляете буфер:

char *esploratoreToString(esploratore *e, char *buf, int bufsz) {
    snprintf(buf, bufsz,
             "%s %s %d %d",
             e.nome, e.cognome, e.nascita, e.morte);
    return buf;
}

...

int main()
{
    char buf[100];
    esploratore exp = {...};

    printf("%s\n", esploratoreToString(&exp, buf, sizeof buf);
}

Таким образом, вы можете выделить его динамически или как автоматически выделенный буфер стека c.

Другой альтернативой является чтобы вернуть указатель на статически выделенный буфер, как в:

char *esploratoreToString(esploratore *e) {
    static char buf[50];
    snprintf(buf, bufsz,
             "%s %s %d %d",
             e.nome, e.cognome, e.nascita, e.morte);
    return buf;
}

Но проблема в том, что он не реентерабелен, а также если вам нужно вызвать его дважды при одном и том же вызове printf(3)main) второй вызов перезапишет буфер, и вы получите странное поведение из-за того, что перезаписываете один результат другим и печатаете дважды одно и то же.

0 голосов
/ 02 апреля 2020

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

0 голосов
/ 02 апреля 2020

Да. Это общая идиома в C: вызываемый выделяет память, а передает владение вызывающей стороне. Это означает, что вызывающая сторона теперь отвечает за освобождение выделенного блока.

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