Как правильно написать функцию C, возвращающую массив символов? - PullRequest
16 голосов
/ 29 ноября 2011

Я довольно хорошо знаком с Java, но не совсем в C.

В Java, если у меня есть метод, который что-то делает и возвращает строку, он будет выглядеть так:

private String doSomething(...) {
    String s;
    // do something;
    return s;
}

Синтаксический эквивалент в C не будет работать и совершенно неверен:

char* doSomething(...) {
    char s[100];
    // do something;
    return s;
}

Конечно, я могу сделать:

char* doSomething(...) {
    char *s;
    s = malloc(100 * sizeof(char));
    // do something;
    return s;
}

, который бы работал (я думаю!), Но я редко вижу, чтобы коды делали это (это потому, что это излишне заполняет кучу?)

Чаще всего я вижу:

bool doSomething(char *s) {
    // do something that copies chars to s
    return true;
}

И вызывающие операторы будут:

char s[100];
doSomething(s);

Что если я не знаю размер массива char до тех пор, пока внутри самой функции? то есть я не смог бы объявить массив char вне функции и затем передать его.

Каким будет правильный способ справиться с таким сценарием?

Ответы [ 5 ]

19 голосов
/ 29 ноября 2011

Пусть вызывающий код отвечает за распределение памяти. Передача в буфер и длина буфера в примере 2:

bool doSomething(char *s, size_t buflen)
{ 
    // do something that copies chars to s up to max of buflen
    return true; 
} 

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

5 голосов
/ 29 ноября 2011

Пример случая статического размещения (вы должны думать о максимальном размере буфера во время компиляции)

buf[MAX_NO];
do(buf, MAX_NO);

_Bool do(char *s, size_t len) { 
// use len as boundary in your operations
}

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

char *s = NULL;
size_t final_len;
do(&s, &final_len);

_Bool do(char** s, size_t* final_len) {
    size_t len = discoverSize();
    char* buf = (char*) malloc(sizeof(char) * len);

    *s = buf; //save memory location
    *final_len = len; //save buffer size
    // use len as boundary in your operations

}

// do whatever
free(s); //remember to free the buffer for politeness
2 голосов
/ 29 ноября 2011

Если вы не можете знать правильный размер возвращаемой строки, используйте решение malloc.Конечно, вы должны free строку после того, как с ней покончено.

1 голос
/ 29 ноября 2011

Вы не можете вернуть массив в C.

Вы можете вернуть указатель , и вы должны изучить (читая хорошую книгу по программированию на C языке) разницу между массивами и указателями.

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

Вы также можете вернуть структуру, содержащую массив.

добавления

Если вы хотите иметь сборщик мусора в C, попробуйте Сборщик мусора Бема

0 голосов
/ 29 ноября 2011

Самый безопасный способ - это оставить ответственность за выделение вызывающей стороне, как говорят другие.

Но, если вам не нужен повторно вводимый код и простота Java, синтаксический рабочий эквивалент в C:

char* doSomething(...) {
    static char s[100];
    // do something;
    return s;
}
...