Как отметил Брайан, самая идиоматическая вещь, которую нужно сделать в C, это передать буфер, поэтому вы должны сделать:
int give_me_a_string(char* buffer, int buffersize)
{
const char* result = "Hello world!";
int requiredbufferlen = strlen(result)+1;
if ( (buffer==0) || (buffersize<requiredbufferlen) ){
errno = EINVAL;
return -1;
}
strncpy(buffer,"Hello world!",buffersize);
buffer[buffersize-1]='\0';
return 0;
}
int main(int argc, char* argv[])
{
int buffersize = 256;
char* buffer = (char*) malloc(buffersize);
if ( buffer == 0 ){
printf("Out of memory!\n");
return 1;
}
if ( give_me_a_string(buffer,buffersize) < 0 ){
printf("Oh my god, there's an error!\n");
free(buffer);
return 1;
}else{
printf("%s\n",buffer);
}
free(buffer);
return 0;
}
Теперь, если вам абсолютно не нужно передавать в буфер, тогдаВы можете написать:
char* give_me_a_string(void)
{
const char* str="Hello world!";
int buffersize = strlen(str)+1;
char* result=(char*) malloc(buffersize);
if ( result == 0 ){
return 0;
}
strncpy(result,str,buffersize);
result[buffersize-1]='\0';
return result;
}
Однако, если вы используете вышеизложенное, вы должны запомнить free()
результат.Тем не менее, я настоятельно рекомендую вам использовать первый подход;когда функция возвращает объект указателя, неясно, кто является владельцем (то есть кто отвечает за освобождение строки).Требуя, чтобы вызывающая сторона передала в буфер, вы делаете это владение явным (то есть вызывающая сторона владеет буфером и должна сама освободить его).
Существует одно последнее решение, которое вы можете использовать.Если вы возвращаете постоянную строку, то это приемлемо;однако, если вам нужно вычислить строку, это сделает ее не входящей, и поэтому я настоятельно рекомендую не делать это.На самом деле, я бы настоятельно рекомендовал против этого решения, даже если вы возвращали постоянную строку, потому что тогда API не может адаптироваться к случаю, когда вам нужно вычислить строку.Этот метод заключается в использовании общей глобальной переменной, которая содержит результат, поэтому он будет выглядеть следующим образом:
// declaration
char* give_me_a_string(void);
// implementation
char* global_string = "Hello world!";
char* give_me_a_string(void)
{
return global_string;
}
Это последнее решение не требует освобождения, поскольку сама функция является владельцем.Если бы вы делали это с вычисляемой строкой, она бы выглядела следующим образом:
// declaration
char* give_me_a_string(void);
// implementation
char* global_string = 0;
static void deallocate_global_string()
{
free(global_string);
global_string=0;
}
char* give_me_a_string(void)
{
if ( global_string == 0){
// allocate global_string
// ...
// initialize global_string
// ...
// ensure it is eventually freed
atexit(&deallocate_global_string);
}
return global_string;
}
Как должно быть очевидно, если вы сделаете это, это не реентерабельный (он не будет работать с несколькими потоками), итак что это действительно, действительно ужасная идея.Если вы обожглись, позвольте мне сказать, что я вас предупреждал.