Como não posso retornar uma variável local, qual é a melhor maneira de retornar uma string de uma function C ou C ++?

Como seguimento desta pergunta :

Pelo que vi, isso deve funcionar como esperado:

void greet(){ char c[] = "Hello"; greetWith(c); return; } 

mas isso causará um comportamento indefinido:

 char *greet(){ char c[] = "Hello"; return c; } 

Se estou certo, qual é a melhor maneira de corrigir a segunda function de saudação? Em um ambiente incorporado? Em um desktop?

Você está absolutamente correto. Seu array c no segundo exemplo está sendo alocado na pilha e, assim, a memory será reutilizada imediatamente após. Em particular, se você tivesse código como

  printf("%s\n",greet()); 

você obteria resultados estranhos, porque a chamada para o printf teria reutilizado algum espaço da sua matriz.

A solução é alocar a memory em outro lugar. Para expample:

 char c[] = "Hello"; char * greet() { return c; } 

Podia funcionar. Outra opção seria alocar estaticamente no escopo:

 char * greet() { static char c[] = "Hello"; return c; } 

porque a memory estática é alocada separadamente da pilha no espaço de dados.

Sua terceira escolha é alocá-lo no heap via malloc:

 char * greet() { char * c = (char *) malloc(strlen("Hello")+1); /* +1 for the null */ strcpy(c, "Hello"); return c; } 

mas agora você precisa se certificar de que a memory seja liberada de alguma forma, ou então você tem um memory leaks.

Atualizar

Uma dessas coisas que parece mais confusa do que eu esperava é exatamente o que é um “memory leaks”. Um vazamento ocorre quando você aloca memory dinamicamente, mas perde o endereço para que não seja liberado. Nenhum desses exemplos necessariamente tem um vazamento, mas apenas o terceiro potencialmente tem um vazamento, porque é o único que aloca memory dinamicamente. Então, assumindo a terceira implementação, você poderia escrever este código:

 { /* stuff happens */ printf("%s\n", greet()); } 

Isso tem um vazamento; o ponteiro para a memory malloc é retornado, o printf usa e depois é perdido; você não pode mais libertá-lo. Por outro lado,

 { char * cp ; /* stuff happens */ cp = greet(); printf("%s\n", cp); free(cp); } 

não vaza, porque o ponteiro é salvo em uma variável automática cp tempo suficiente para chamar free() . Agora, mesmo que o cp desapareça assim que a execução passa, ele termina a chave, já que o free foi chamado, a memory é recuperada e não vazou.

Se você estiver usando C ++, então você pode querer considerar o uso de std::string para retornar seqüências de caracteres da sua segunda function:

 std::string greet() { char c[] = "Hello"; return std::string(c); // note the use of the constructor call is redundant here } 

Ou, em um único ambiente encadeado, você pode fazer:

 char *greet() { static char c[] = "Hello"; return c; } 

A static aqui aloca espaço na área de memory global, que nunca desaparece. Este método static é cheio de perigos, no entanto.

Depende se o ambiente incorporado tem um heap ou não, se assim for, você deve malloc da seguinte forma:

 char* greet() { char* ret = malloc(6 * sizeof(char)); // technically " * sizeof(char)" isn't needed since it is 1 by definition strcpy(ret,"hello"); return ret; } 

Note que você deve chamar mais tarde free () para limpar. Se você não tiver access à alocação dinâmica, precisará torná-la global ou variável na pilha, mas aumentar ainda mais a pilha de chamadas.

Se você precisa fazer isso em C ++, usar std::string como sugerido por Greg Hewgill é definitivamente a estratégia mais simples e sustentável.

Se você estiver usando C, você pode considerar retornar um ponteiro para o espaço que foi alocado dinamicamente com malloc() como sugerido por Jesse Pepper; mas outra maneira que pode evitar a alocação dinâmica é ter greet() pegar um parâmetro char * e escrever sua saída lá:

 void greet(char *buf, int size) { char c[] = "Hello"; if (strlen(c) + 1 > size) { printf("Buffer size too small!"); exit(1); } strcpy(buf, c); } 

O parâmetro size está lá por segurança, para ajudar a evitar saturações de buffer. Se você soubesse exatamente quanto tempo a corda seria, não seria necessário.

Você pode usar um destes:

 char const* getIt() { return "hello"; } char * getIt() { static char thing[] = "hello"; return thing; } char * getIt() { char str[] = "hello"; char * thing = new char[sizeof str]; std::strcpy(thing, str); return thing; } shared_array getIt() { char str[] = "hello"; shared_array thing(new char[sizeof str]); std::strcpy(thing.get(), str); return thing; } 

O primeiro requer que você não escreva na string retornada, mas também é o mais simples que você pode obter. O último usa shared_array que automaticamente pode limpar a memory se a referência à memory for perdida (a última shared_array para ela sai do escopo). O último e o último último devem ser usados ​​se você precisar de uma nova string toda vez que chamar a function.

Retornar a memory malloc de uma function como sugerido por várias outras respostas é apenas pedir um memory leaks. O chamador teria que conhecê-lo e então chamar de graça. Se acontecer de eles chamarem delete, os resultados serão indefinidos (embora provavelmente estejam bem).

Seria melhor forçar o chamador a fornecer a memory para você e depois copiar sua string para ela. Desta forma, o chamador está ciente de que ele precisa limpar.

Pelo que eu li, a opção mais segura é fazer com que o responsável pela chamada aloque memory para manter a string. Você também deve verificar se o buffer é grande o suficiente para conter sua string:

 char *greet(char *buf, int size) { char *str = "Hello!" if (strlen(str) + 1 > size) { // Remember the terminal null! return NULL; } strcpy(buf, str); return buf; } void do_greet() { char buf[SIZE]; if (greet(buf, SIZE) == NULL) { printf("Stupid C"); } else {} // Greeted! } 

Uma tonelada de trabalho para uma tarefa simples … mas há C para você 🙂 Oops! Acho que fui espancado por random_hacker …

Alocar o array de caracteres no heap?

Se você pode usar malloc ou não depende do que você entende por “ambiente incorporado”.