Ir ao conteúdo

C Printf não mostra valor armazenado da String


Ir à solução Resolvido por arfneto,

Posts recomendados

Postado

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
Postado

@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
Postado

@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
  • Solução
Postado
  • 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
Postado
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
Postado
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
Postado
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
Postado

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
Postado
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

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...