Ir ao conteúdo
  • Cadastre-se

C Printf não mostra valor armazenado da String


Malcolm X
Ir à solução Resolvido por arfneto,

Posts recomendados

Pessoal estou fzndo um exercício em C. Mas meu programa está dando uns espaços indesejados e não consigo imprimir o valor final na tela, alguém dá um help.

 

Fac¸a um programa que receba uma palavra e a imprima de tr ´as-para-frente.

 

main()
{
    char str[30],contrario[30];
    int i,c;
    printf("Digite uma palavra: ");
    fgets(str,30,stdin);
    c=strlen(str);
    printf("Valor recebido: %s\n", str);
    for(i=0;i<=strlen(str);i++,c--)
    {
        contrario[i]=str[c];
        printf("%c", contrario[i]);
    }
    printf("\nString ao contrario: %s", contrario);
}

 

  • Amei 1
Link para o comentário
Compartilhar em outros sites

@Malcolm X  Como fgets também pega '\n' no input, a função strlen vai considerar esse caractere. Além disso no seu loop você vai considerar 0 como o primeiro índice.

 

Na atribuição de c, tire 2.

 

c = strlen(str) - 2;

 

E no loop o critério de parada deve ser,

 

i<strlen(str)-1

Outra forma de resolver poderia ser assim,

 

int main(){
    char str[30];
    int i = strlen(fgets(str,30,stdin))-1;
    
    while(i--){
        printf("%c",str[i]);
    }    
    return 0;
}

 

  • Curtir 3
Link para o comentário
Compartilhar em outros sites

@Malcolm X    você quer dizer que está pulando linha ,  a cada palavra escrita  ? ,    isso é porque o comando fgets pega o newline também , e na hora que escreve com printf ele vê esse newline e pula uma linha , e se você quiser cancelar esse newline que o fgets pega , você pode incluir essa linha logo abaixo do comando fgets   :

palavra[strlen(palavra)-1] = '\0';

 

  • Curtir 2
Link para o comentário
Compartilhar em outros sites

  • Solução
  • Está claro que a string de saída vai ter o mesmo tamanho que a de entrada. Mas do jeito que você escreveu precisa colocar um zero lá no fim de 'contrario'
     
  • fgets() foi escrita para você poder ler e já copiar a string para outro lugar. Isso quer dizer que fgets() lê a string inteira, incluído o '\n' do final. Isso é bom, desde que você tenha lido o manual ou queira fazer o normal que é gravar em outro lugar com fputs() por exemplo. Aí você gosta de ter o '\n' lá porque se fgets() o tirasse você teria que por de volta linha por linha ou ia ficar tudo grudado na saída em uma linha só.
    Só que aqui você não pode copiar a partir do último valor em str[] porque é garantido que é um '\n', e isso é bom. Mesmo que não tenha um newline lá para ler fgets() vai colocar um automaticamente. Isso porque muitas vezes a última linha de um arquivo texto não tem o '\n'e aí ficaria um tratamento especial a toa. É mais simples assim e está escrito em todo manual que eu já vi até hoje. Como você só quer ler a string, não pode começar a inverter pela última posição dela.
    Exemplo: se a linha era 'azul\n' fgets() leu exatamente assim: 
    		'a' 'z' 'u' 'l' '\n'

    E o primeiro que você quer copiar é o 'l' e a posição dele é (strlen(str) - 2). Esse é o maior problema de seu programa
     

  • Você precisa terminar a string de saída com um zero. Uma string em C é isso. Você sabe que ela vai ter o mesmo comprimento da string de entrada, exceto o '\n' e então faça isso: coloque um zero lá ou não vai funcionar e vai imprimir um monte de lixo na tela até achar um zero... Algo simples assim resolve:
    int c = strlen(str) - 2; // primeiro indice a copiar
    contrario[c + 1] = 0;
  • E você copia de str para contrario até c ser menor que zero
     
  • Quando você mostra uma string que pode espaços sugiro sempre mostrar entre algum delimitador, afinal não dá pra ver os espaços. Algo simples como '%s' no printf()
     
  • se você não está usando um compilador medieval pode declarar int i=0 dentro do for apenas
     
  • para imprimir str[] você deve tirar o '\n'de lá. Pode usar o simples 
        str[strlen(str) - 1] = 0;
    Compare com o EXEMPLO
#include <stdio.h>
main()
{
    char str[30], contrario[30];
    printf("Digite uma palavra: ");
    fgets(str, 30, stdin);
    int c = strlen(str) - 2; // primeiro indice a copiar
    contrario[c + 1] = 0;
    str[strlen(str) - 1] = 0;
    printf("\nValor recebido: '%s'\n", str);
    for (int  i = 0; c >= 0; i+=1, c-=1 )
        contrario[i] = str[c];
    printf("String ao contrario: '%s'\n\n", contrario); 
}

que mostra para 'azul'
 

Digite uma palavra: azul

Valor recebido: 'azul'
String ao contrario: 'luza'

 

adicionado 16 minutos depois

Não seria justo não incluir o clássico exemplo de inverter a string usando recursão :D 

 

Veja que nesse caso só precisa de uma variável, a string em si. E precisa daquela jogada no final da entrada apenas para poder mostrar a string inicial sem pular de linha por causa do '\n' no final.

#include <stdio.h>

void inverte(char*);

main()
{
    char str[30];
    printf("Digite uma palavra: ");
    fgets(str, 30, stdin);
    str[strlen(str) - 1] = 0;
    printf("\nValor recebido: '%s'\n", str);
    printf("String ao contrario: '");
    inverte(str);
    printf("'\n");
};

void inverte(char* str)
{
    if ((str[0] == 0) || (str[0] == '\n')) return;
    inverte(str + 1);
    printf("%c", *str);
};

O resultado, claro, é o mesmo.

  • Curtir 3
  • Obrigado 1
Link para o comentário
Compartilhar em outros sites

3 horas atrás, Midori disse:

int main(){ char str[30]; int i = strlen(fgets(str,30,stdin))-1; while(i--){ printf("%c",str[i]); } return 0; }

Minha lógica foi completamente diferente, foi de acordo com o que eu aprendi com Vetores e Loop, mas o seu está muito melhor. Mais compacto e rápido.

3 horas atrás, devair1010 disse:

fgets pega o newline também

O certo nesse caso então seria usar o gets(); porque ele não coloca o caracter de nova linha na string.

 

2 horas atrás, arfneto disse:

(strlen(str) - 2)

por que é -2? '\n' é considerado apenas um carácter certo?

 

2 horas atrás, arfneto disse:

contrario[c + 1] = 0;

Não entendi muito bem aqui nessa parte, então, a variável contrario recebe o valor de c(que seria o tamanho de str -2) e acrescenta o delimitador '\0', já que eu determino o tamanho, porém não determino o final.  Seria isso ou não tem nada a ver?

 

2 horas atrás, arfneto disse:

se você não está usando um compilador medieval pode declarar int i=0 dentro do for apenas

😅😂

2 horas atrás, arfneto disse:

para imprimir str[] você deve tirar o '\n'de lá. Pode usar o simples

:tw_thumbsup:

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

31 minutos atrás, Malcolm X disse:

por que é -2? '\n' é considerado apenas um carácter certo?

 

continuando com o exemplo "azul\n"

			'a' 'z' 'u' 'l' '\n'

entenda que

  • na verdade você quer copiar até 'l' e os índices começam de zero então 'l' é str[3]
  • strlen() nesse caso vale 5
  • depois do '\n' tem um '\0' porque assim são as strings em C.
36 minutos atrás, Malcolm X disse:

O certo nesse caso então seria usar o gets(); porque ele não coloca o caracter de nova linha na string

 

Não há nada de especial em usar fgets(). Mas gets() não existe em compiladores da Microsoft e acho que da Intel então se for compilar em algum desses vai ter que alterar. A toa. fgets() tem em todas as plataformas e é mais esperta porque tem um parâmetro que limita o tamanho, como você usou. E então te dá uma segurança sobre a entrada que gets() não tem e por isso foi abandonada em muitos círculos. E GARANTE o newline no final então se você está copiando dados vai achar vantagem porque pode copiar linhas de um arquivo para outro usando pares fgets()/fputs() direto.
 

Entenda que se você escrever

	char str[30];
	str = gets(str);

E o usuário digitar 30 letrinhas seu programa já era assim que ele teclar ENTER. Por isso essa função foi abandonada. E até abre uma porta para injeção de código por hackers, o tal buffer overflow.


Mas se você escrever 

	char str[30];
	fgets(str, 30, stdin);

E rodar aquele programa que te mostrei

Digite uma palavra: sssssssssddddddddddllllllllllldddddddddddd

Valor recebido: 'sssssssssddddddddddlllllllll'
String ao contrario: 'lllllllllddddddddddsssssssss'

Note que ele para de ler em 29 letrinhas e seu programa não cancela. E compila em qualquer plataforma, de bonus.


Esqueça essas "recomendações" e NUNCA use gets(). Ou mesmo scanf() para esses casos de ler do teclado.

  • leia letra a letra usando fgetc()
  • leia linha a linha usando fgets()
  • ou para ter real controle leia do buffer de teclado diretamente usando PeekConsoleInput() no Windows ou ioctl() no Linux.

 

37 minutos atrás, Malcolm X disse:

Não entendi muito bem aqui nessa parte, então, a variável contrario recebe o valor de c(que seria o tamanho de str -2) e acrescenta o delimitador '\0', já que eu determino o tamanho, porém não determino o final.  Seria isso ou não tem nada a ver?

 

Não tem nada a ver. Em C as strings são terminadas por um zero. Acho que agora já entendeu isso.

Seu enunciado aparentemente não exige ter uma string de saída: pede só para mostrar letra a string de entrada invertida.

Então pode só mostrar letra a letra do fim para o começo e pronto, como no exemplo de @Midori. E como na função recursiva que eu mostrei.

Só que você está criando uma nova string, contrario[] e depois usando '%s' no printf() para mostrar. E assim precisa ter um zero ao final da string.

		contrario[c + 1] = 0;

contrario[c+1] é um char. Uma única letra. Se você vai copiar c caracteres, na posição (c+1) tem que ter um zero. É assim em C. Essa instrução só faz isso. Termina sua string de saída para você poder usar printf() com a máscara %s, uma string. Se você não colocar isso ele vai mostrar tudo que tiver na memória no momento , até achar um zero. Teste.
 

44 minutos atrás, Malcolm X disse:

se você não está usando um compilador medieval pode declarar int i=0 dentro do for apenas

 

A partir de 1990 passou a ser legal declarar variáveis dentro do for. Use a opção --std=c17 em seu compilador.

 

ISO/IEC 9899:2018; it is known as C17 and is supported with -std=c17 or -std=iso9899:2017; the corrections are also applied with -std=c11, and the only difference between the options is the value of __STDC_VERSION__

 

Isso é prático e evita muitos efeitos colaterais. Foi esperado por muitos anos por quem escrevia software em C desde os 80 porque muitas vezes variáveis só existiam dentro de um loop, casos como o do seu programa ;) 

  • Curtir 2
Link para o comentário
Compartilhar em outros sites

2 horas atrás, arfneto disse:

\0

Sempre me esqueço que esse delimitador existe, grande erro hahaha.

2 horas atrás, arfneto disse:

'a' 'z' 'u' 'l' '\n'

'a' 'z' 'u' 'l' '\n' '\0'

6-2=4

Dessa Vez entendi tudo, eh questão de interpretar e vê como o vetor irá percorrer dentro do for.

Agradeço a todos que me ajudaram.

Enfim, segue os códigos finais já testados, o meu, um do @arfneto e outro do @Midori :

main()
{
    char str[30],contrario[30];
    int c;
    printf("Digite uma palavra: ");
    fgets(str,30,stdin);
    c = strlen(str) - 2;
    contrario[c+1]=0;
    for(int i=0;c  >= 0;i++,c--)
    {
        contrario[i]=str[c];
    }
    printf("%s\n",contrario);
}

//Modelo 2
/*main()
{
    char str[30], contrario[30];
    printf("Digite uma palavra: ");
    fgets(str, 30, stdin);
    int c = strlen(str) - 2; // primeiro indice a copiar
    contrario[c + 1] = 0;
    str[strlen(str) - 1] = 0;
    printf("\nValor recebido: '%s'\n", str);
    for (int  i = 0; c >= 0; i++, c-- )
        contrario[i] = str[c];
    printf("String ao contrario: '%s'\n\n", contrario);
}*/


//Modelo 3
/*int main(){
    char str[30];
    int i = strlen(fgets(str,30,stdin))-1;

    while(i--){
        printf("%c",str[i]);
    }
    return 0;
}*/

 

  • Obrigado 1
Link para o comentário
Compartilhar em outros sites

Modelo 1 e 2 é praticamente o mesmo código.

Modelo 3, achei bem compacto e eficiente meu professor de arquitetura iria amar esse código kkk, e tem coisas que aprendi nesse 3. Tipo declarar a variável e já pedir o valor. E é a primeira vez q vejo um while(i--){} ele decrementa até chgar em 0.

adicionado 0 minutos depois

@devair1010 ah sim hahaha

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

6 minutos atrás, devair1010 disse:

o finalizador de string antes do newline  ;.

 

É claro. Ou vai pular uma linha quando mostrar na tela. Isso é o sentido de newline, '\n", Line Feed na tabela ASCII.

 

12 minutos atrás, Malcolm X disse:

Enfim, segue os códigos finais já testados, o meu, um do @arfneto e outro do @Midori :

 

Considere sempre a versão recursiva também. como eu te mostrei. Fora o fatorial acho que é o exemplo mais comum de todos.

  • Obrigado 2
Link para o comentário
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisa ser um usuário para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...

Ebook grátis: Aprenda a ler resistores e capacitores!

EBOOK GRÁTIS!

CLIQUE AQUI E BAIXE AGORA MESMO!