Pergunta

Estou usando o Linux. Estou tentando escrever um programa em C que imprimirá uma string para trás. Aqui está o meu código:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main (){
    char string[100];
    printf ("Enter string:\n");
    gets (string);
    int length = strlen (string)-1;
    for (length = length; length>=0; length--){
        puts (string[length]);
    }
}

E aqui está o erro:

a.c:10: warning: passing argument 1 of ‘puts’ makes pointer from integer without a cast
/usr/include/stdio.h:668: note: expected ‘const char *’ but argument is of type ‘char’
/tmp/cc5rpeG7.o: In function `main':
a.c:(.text+0x29): warning: the `gets' function is dangerous and should not be used.

O que devo fazer?

Foi útil?

Solução

Primeiro:

NUNCA, NUNCA, NUNCA, NUNCA, NUNCA usar gets(); isto vai Apresente um ponto de falha em seu código. Não há como contar gets() Quão grande é o buffer de destino, por isso, se você passa em um buffer do tamanho de 10 caracteres e há 100 caracteres no fluxo de entrada, gets() Felizmente, armazenará esses 90 caracteres extras na memória além do final do seu buffer, potencialmente batendo algo importante. Os excedentes de buffer são uma exploração fácil de malware; o morris morris explorou especificamente um gets() Ligue para o Sendmail.

Usar fgets() em vez de; Ele permite que você especifique o número máximo de caracteres para ler a partir do fluxo de entrada. No entanto, ao contrário gets(), fgets() Salvará o caráter de nova linha de rescisão no buffer se houver espaço para ele, então você precisará explicar isso:

char string[100]; 
char *newline;
printf("Enter a string: ");
fflush(stdout);
fgets(string, sizeof string, stdin);
newline = strchr(buffer, '\n');      // search for the newline character
if (newline)                         // if it's present
  *newline = 0;                      // set it to zero

Agora isso está fora do caminho ...

Seu erro vem do fato de que puts() espera um argumento do tipo char *, mas você está passando um argumento do tipo char, daí o "ponteiro do número inteiro sem elenco" (char é um tipo integral). Para escrever um único personagem para stdout, use putchar() ou fputc().

Outras dicas

Esqueça que a função gets() Existe - é letal. Usar fgets() Em vez disso (mas observe que ele não remove a nova linha no final da linha).

Você quer colocar um único personagem de cada vez: Use putchar() para escrever para stdout. Não se esqueça de adicionar uma nova linha à saída após o loop.

Também, for (length = length; length >= 0; length--) não é idiomático C. Use um de:

  • for ( ; length >= 0; length--)
  • for (length = strlen(string) - 1; length >= 0; length--)
  • for (int length = strlen(string) - 1; length >= 0; length--)

A última alternativa usa um recurso adicionado ao C99 (que estava disponível em C ++ muito antes).

Além disso, poderíamos debater se length é o nome apropriado para a variável. Seria melhor renomeado como i ou pos Ou algo semelhante porque, embora seja inicializado com o comprimento da entrada, ele é realmente usado como um índice de matriz, não como o comprimento de qualquer coisa.

Subjetivo: Não coloque um espaço entre o nome de uma função e sua lista de parâmetros. Os pais fundadores de C não fazem isso - você também não deveria.


Por que Gets () é letal?

O primeiro verme da Internet - o Morris Worm de 1988 - explorou o fingerd programa que usou gets() ao invés de fgets(). Desde então, vários programas foram travados porque usaram gets() e não fgets() ou outra alternativa.

O problema fundamental é que gets() Não sabe quanto espaço está disponível para armazenar os dados que lê. Isso leva ao 'buffer transbordante', um termo que pode ser pesquisado em seu mecanismo de pesquisa favorito que retornará um número enorme de entradas.

Se alguém digita 150 caracteres de entrada para o programa de exemplo, então gets() armazenará 150 caracteres na matriz com comprimento 100. Isso nunca leva à felicidade - geralmente leva a um dump do núcleo, mas com entradas cuidadosamente escolhidas - geralmente geradas por um script Perl ou Python - você provavelmente pode fazer com que o programa execute arbitrário arbitrário outro código. Isso realmente importa se o programa será executado por um usuário com 'privilégios elevados'.

Aliás, gets() é provável que seja removido da biblioteca C padrão na próxima versão (C1X - ver N1494 de WG14). Ainda não desaparecerá das bibliotecas C reais por um longo tempo (20 anos?), Mas deve ser substituído por esta implementação (ou algo semelhante):

#undef NDEBUG
#include <assert.h>
char *gets(char *buffer)
{
    assert("Probability of using gets() safely" == 0);
}

Um outro detalhe menor, discutido em parte sob os comentários da questão principal.

O código mostrado é claramente para C99; a declaração de length Parte interna da função é inválida em C89. Dado isso, é 'ok' para o main() função não retornar explicitamente um valor, porque o padrão C99 segue o líder do padrão C ++ e permite omitir o retorno do main() e o efeito é o mesmo que return(0); ou return 0; no final.

Como tal, o programa nesta questão não pode ser estritamente culpado por não ter um return no final. No entanto, considero que como uma das decisões de padronização mais peculiares e preferiria se os padrões tivessem deixado essa disposição - ou fizeram algo mais radical, como permitir o onipresente, mas errôneo void main() Observando que, quando o controle retorna disso, o resultado é que um status de sucesso é devolvido ao meio ambiente. Não vale a pena lutar para mudar esse aspecto do padrão - infelizmente - mas como uma decisão de estilo pessoal, não aproveito a licença concedida para omitir a final return a partir de main(). Se o código tiver que funcionar com compiladores C89, deve ter o explícito return 0; no final (mas depois a declaração de length tem que ser consertado também).

Você também pode usar a recursão para fazê -lo. Eu acho que parece melhor do que usar um loop.

Basta ligar para o método com sua string e, antes de imprimir o char no método, ligue para o método novamente com a mesma string, menos o primeiro char.

Isso imprimirá sua corda em ordem invertida.

Você deveria usar putchar ao invés de puts

Então, este loop:

for (length = length; length>=0; length--){
    puts (string[length]);
}

Vai ser:

for (length = length; length>=0; length--){
    putchar (string[length]);
}

putchar levará um único char como um parâmetro e o imprimirá para stdout, que é o que você quer. puts, por outro lado, imprimirá toda a string para stdout. Então, quando você passa um único char para uma função que espera uma string inteira (matriz char, NULO string encerrada), o compilador fica confuso.

Usar putc ou putchar, Como puts é especificado para tomar um char* E você está alimentando um char.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top