Estou tentando retornar uma string C de uma função, mas não está funcionando. Aqui está meu código.
char myFunction()
{
return "My String";
}
Em main
que estou chamando-o assim:
int main()
{
printf("%s", myFunction());
}
Eu também tentei algumas outras formas para myFunction
, mas não estão funcionando. Por exemplo:
char myFunction()
{
char array[] = "my string";
return array;
}
Nota: Não tenho permissão para usar ponteiros!
Um pequeno histórico sobre este problema:
Existe uma função que é descobrir em que mês estamos. Por exemplo, se for 1, ele retornará janeiro, etc.
Então, quando ele vai imprimir, é fazê-lo como este: printf("Month: %s",calculateMonth(month));
. Agora o problema é como retornar essa string da calculateMonth
função.
return 0
está implícito por padrão apenas em C99 (e C ++), mas não em C90.Respostas:
Sua assinatura de função precisa ser:
Fundo:
É tão fundamental para C e C ++, mas pouca discussão deveria ser necessária.
Em C (e C ++ para esse assunto), uma string é apenas um array de bytes terminado com um byte zero - portanto, o termo "string-zero" é usado para representar este tipo particular de string. Existem outros tipos de strings, mas em C (e C ++), esse sabor é inerentemente entendido pela própria linguagem. Outras linguagens (Java, Pascal, etc.) usam diferentes metodologias para entender "minha string".
Se você já usou a API do Windows (que está em C ++), verá parâmetros de função com bastante regularidade, como: "LPCSTR lpszName". A parte 'sz' representa esta noção de 'string-zero': uma matriz de bytes com um terminador nulo (/ zero).
Esclarecimento:
Por causa desta 'introdução', uso as palavras 'bytes' e 'caracteres' alternadamente, porque é mais fácil de aprender desta forma. Esteja ciente de que existem outros métodos (caracteres largos e sistemas de caracteres multibyte ( mbcs )) que são usados para lidar com caracteres internacionais. UTF-8 é um exemplo de mbcs. Por causa da introdução, eu silenciosamente 'pulo' tudo isso.
Memória:
Isso significa que uma string como "minha string" na verdade usa 9 + 1 (= 10!) Bytes. É importante saber quando você finalmente conseguirá alocar strings dinamicamente.
Então, sem esse 'zero terminador', você não tem uma string. Você tem uma matriz de caracteres (também chamada de buffer) circulando na memória.
Longevidade dos dados:
O uso da função desta forma:
... geralmente levará você a exceções aleatórias não tratadas / falhas de segmento e semelhantes, especialmente 'no futuro'.
Resumindo, embora minha resposta esteja correta - 9 em cada 10 vezes, você terminará com um programa que trava se o usar dessa forma, especialmente se você achar que é uma 'boa prática' fazê-lo dessa forma. Resumindo: geralmente não é.
Por exemplo, imagine em algum momento no futuro, a string agora precisa ser manipulada de alguma forma. Geralmente, um codificador irá 'seguir o caminho mais fácil' e (tentar) escrever código como este:
Ou seja, seu programa travará porque o compilador (pode / não) liberou a memória usada
szBuffer
no momentoprintf()
em que o inmain()
é chamado. (Seu compilador também deve avisá-lo sobre esses problemas com antecedência.)Existem duas maneiras de retornar strings que não vomitam tão prontamente.
std::string
) para lidar com a longevidade dos dados (o que requer a alteração do valor de retorno da função), ouObserve que é impossível usar strings sem usar ponteiros em C. Como mostrei, eles são sinônimos. Mesmo em C ++ com classes de modelo, sempre há buffers (ou seja, ponteiros) sendo usados em segundo plano.
Então, para melhor responder a (questão agora modificada). (Com certeza há uma variedade de "outras respostas" que podem ser fornecidas.)
Respostas mais seguras:
Exemplo 1, usando strings alocadas estaticamente:
O que o 'estático' faz aqui (muitos programadores não gostam desse tipo de 'alocação') é que as strings são colocadas no segmento de dados do programa. Ou seja, está alocado permanentemente.
Se você mudar para C ++, usará estratégias semelhantes:
... mas provavelmente é mais fácil usar classes auxiliares, como, por exemplo
std::string
, se você estiver escrevendo o código para seu próprio uso (e não parte de uma biblioteca para ser compartilhada com outras pessoas).Exemplo 2, usando buffers definidos pelo chamador:
Esta é a maneira mais 'infalível' de passar as cordas. Os dados retornados não estão sujeitos à manipulação pela parte chamadora. Ou seja, o exemplo 1 pode facilmente ser abusado por uma parte chamadora e expô-lo a falhas de aplicativo. Dessa forma, é muito mais seguro (embora use mais linhas de código):
Existem muitas razões pelas quais o segundo método é melhor, especialmente se você estiver escrevendo uma biblioteca para ser usada por outros (você não precisa se prender a um esquema específico de alocação / desalocação, terceiros não podem quebrar seu código, e você não precisa se vincular a uma biblioteca de gerenciamento de memória específica), mas como todo código, você decide o que mais gosta. Por esse motivo, a maioria das pessoas opta pelo exemplo 1 até que tenham sido queimados tantas vezes que se recusam a escrever mais dessa forma;)
Aviso Legal:
Eu me aposentei há vários anos e meu C está um pouco enferrujado agora. Este código de demonstração deve ser compilado corretamente com C (embora seja OK para qualquer compilador C ++).
fonte
char *
, pois os literais de string em C são do tipochar[]
. Eles, entretanto, não devem ser modificados de forma alguma, portanto, o retornoconst char*
é preferível (consulte securecoding.cert.org/confluence/x/mwAV ). O retornochar *
pode ser necessário se a string for usada em uma função de biblioteca legada ou externa que (infelizmente) espera umchar*
como argumento, mesmo que seja apenas lido dele. C ++, por outro lado, tem literais de string doconst char[]
tipo (e, desde C ++ 11, você também pode terstd::string
literais).fraught with problems
na seção "Longevidade dos dados" é perfeitamente válido. Literais de string têm tempos de vida estáticos em C / C ++. Veja o link que Giorgi menciona acima.A string AC é definida como um ponteiro para uma matriz de caracteres.
Se você não pode ter ponteiros, por definição não pode ter strings.
fonte
void foo( char array[], int length)
. Obviamente,array
é um ponteiro por baixo do capô, mas não é "explicitamente" um ponteiro e, portanto, pode ser mais intuitivo para alguém que está aprendendo matrizes, mas que ainda não aprendeu ponteiros.Observe esta nova função:
Eu defini "array" como estático. Do contrário, quando a função termina, a variável (e o ponteiro que você está retornando) sai do escopo. Uma vez que essa memória é alocada na pilha, ela será corrompida. A desvantagem dessa implementação é que o código não é reentrante e não é thread-safe.
Outra alternativa seria usar malloc para alocar a string no heap e, em seguida, liberá-la nos locais corretos de seu código. Este código será reentrante e thread-safe.
Conforme observado no comentário, esta é uma prática muito ruim, já que um invasor pode então injetar código em seu aplicativo (ele precisa abrir o código usando GDB, fazer um ponto de interrupção e modificar o valor de uma variável retornada para estourar e a diversão acaba de começar).
É muito mais recomendado deixar o chamador lidar com as alocações de memória. Veja este novo exemplo:
Observe que o único conteúdo que pode ser modificado é aquele do usuário. Outro efeito colateral - este código agora é threadsafe, pelo menos do ponto de vista da biblioteca. O programador que chama este método deve verificar se a seção de memória usada é threadsafe.
fonte
Seu problema é com o tipo de retorno da função - deve ser:
... e então sua formulação original funcionará.
Observe que você não pode ter strings C sem ponteiros envolvidos, em algum lugar ao longo da linha.
Além disso: Aumente os avisos do compilador. Ele deveria ter avisado sobre aquela linha de retorno convertendo um
char *
parachar
sem uma conversão explícita.fonte
Com base em sua história de fundo recém-adicionada com a pergunta, por que não retornar um número inteiro de 1 a 12 para o mês e deixar a função main () usar uma instrução switch ou uma escada if-else para decidir o que imprimir? Certamente não é a melhor maneira de ir - char * seria - mas no contexto de uma aula como essa, imagino que seja provavelmente a mais elegante.
fonte
Você pode criar a matriz no chamador, que é a função principal, e passar a matriz para o receptor que é seu myFunction (). Portanto, myFunction pode preencher a string no array. No entanto, você precisa declarar myFunction () como
E na função principal, myFunction deve ser chamada desta forma:
No entanto, um ponteiro ainda é usado.
fonte
O tipo de retorno de sua função é um único caractere (
char
). Você deve retornar um ponteiro para o primeiro elemento da matriz de caracteres. Se você não pode usar ponteiros, está ferrado. :(fonte
Ou que tal este:
E chame isso com o mês que você computou em outro lugar.
fonte
A
char
é apenas um único caractere de um byte. Ele não pode armazenar a sequência de caracteres, nem é um ponteiro (que aparentemente você não pode ter). Portanto, você não pode resolver seu problema sem usar ponteiros (quechar[]
é um açúcar sintático).fonte
Se você realmente não pode usar ponteiros, faça algo assim:
O número mágico 9 é terrível e este não é um exemplo de boa programação. Mas você entendeu. Observe que ponteiros e matrizes são a mesma coisa (mais ou menos), então isso é um pouco trapaça.
fonte
Bem, em seu código, você está tentando retornar a
String
(em C, que nada mais é do que uma matriz de caracteres terminada em nulo), mas o tipo de retorno de sua função é ochar
que está causando todos os problemas para você. Em vez disso, você deve escrever desta forma:E é sempre bom qualificar seu tipo com
const
ao atribuir literais em C a ponteiros, visto que literais em C não são modificáveis.fonte
Seu protótipo de função afirma que sua função retornará um char. Portanto, você não pode retornar uma string em sua função.
fonte
Em C, os literais de string são arrays com a classe de memória constante estática, portanto, retornar um ponteiro para esse array é seguro. Mais detalhes estão na questão Stack Overflow "Life-time" de um literal de string em C
fonte
String de retorno da função
fonte