Ir ao conteúdo
  • Cadastre-se

C estou tentando rodar uma string em um for, mas não vai


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

Posts recomendados

Estou aprendendo String e me deparei com um exercício, percorrer com for uma string, pensei ter feito certo, mas ao rodar não me apareceu o esperado, se alguém achar o erro fico grato.

 

main()
{
    char str[15];
    int i;
    printf("Digite um nome: ");
    scanf("%s", str);
    for(i=0;i<10;i++);
    {
        printf("valor do elemento %d da string = %c\n",i,str[i]);
    }
}

 

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

@Midori

6 horas atrás, Midori disse:

E você deve informar o tamanho da string no loop, use a função strlen.

Vai printar o /0 do final da string?

adicionado 10 minutos depois

@Malcolm X Sempre quando for manipular string com scanf use fflush(stdin); ou de um espaço antes do formatador.

 

Exemplo errado:

printf("Digite um nome: ");
scanf("%s", str);
//caso tenha isso
printf("Digite um nome: ");
scanf("%s", str);

printf("Digite o segundo nome: ");
scanf("%s", str2);
//já da erro, porque ele armazena o enter do click na proxima variável
//no caso --->   scanf("%s", str2);

Exemplos corretos:

printf("Digite um nome: ");
scanf("%s", str);
//disso pra isso
printf("Digite um nome: ");
scanf(" %s", str); // observe que tem um espaço antes do %s, estão o computador vai ignorar o ENTER

// outra opção, usada em gets que não tem formatador

printf("Digite o segundo nome: ");
fflush(stdin);
scanf("%s", str);

// ou
printf("Digite o segundo nome: ");
fflush(stdin);  //limpa o buffer do teclado antes de ler
gets(str); 

// no caso de linux seria algo assim:
printf("Digite o segundo nome: ");
 __fpurge(stdin);
gets(str);

 

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

@Luiz Paulo Escobar Entendi, então existe várias opções. Estava estudando e vi em um site que falava que usar gets e puts não eh muito profissional, não entendi muito porque, mas acho q está relacionado ao uso da memória, eu sei usar, mas evito.

Eu aprendi esse outro caso abaixo, nesse caso seria pra "apagar" o Enter certo?

scanf("%[^\n]", str);

scanf("%30[^\n]", str); //limita o tamanho da string em 30

A forma que eu achei melhor foi colocando o espaço antes do %.

Já tive problemas antes com isso 

 

Enfim, agradeço a ajuda de todos. Prazer em aprender 😃

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

 

Opções de Alerta

 

Compiladores emitem alertas para os casos ambíguos e não; ambíguos porque declaração nula é uma das especificações da linguagem e do Idioma C'18, significa dizer que não é um erro, entretanto não será ignorado. 

 

O GCC, um dos mais importantes quiçá o melhor compilador porque é livre e atualizado, tem duas importantes opções.

 

-Wall

-Wextra

 

que usamos p.ex.:

gcc -std=c18 -Wall -Wextra draft.c

 

No Caso

10 horas atrás, Malcolm X disse:

 


main()
{
    char str[15];
    int i;
    printf("Digite um nome: ");
    scanf("%s", str);
    for(i=0;i<10;i++);
    {
        printf("valor do elemento %d da string = %c\n",i,str[i]);
    }
}

 

 

Inteligentemente define que (;) é talvez engano porque vem uma declaração nula seguida de um bloco anônimo com indentação. Logo fica fácil presumir que possivelmente um pertence ao outro.

 

Veja um alerta de código semelhante

#include <stdio.h>
int main(void){
	for (unsigned int index = 0; index < 10; ++ index);
	{
		printf ("Oh! Que inteligente !!!");
	}
    	return 0;
}

 

GCC_inteligente.png.5c2a8959b541e386a34b78064894d6c7.png

 

😉 GCC

 

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

  • Solução
main()
{
    char str[15];
    int i;
    printf("Digite um nome: ");
    scanf("%s", str);
    for(i=0;i<10;i++);
    {
        printf("valor do elemento %d da string = %c\n",i,str[i]);
    }
}

Imagino que a partir de todas as sugestões que recebeu já tenha entendido o que houve com seu programa e tenha feito ele funcionar :) 

 

Mas vou deixar uma análise do que você escreveu e umas notas a mais

 

int i;
 

Como está aprendendo é uma boa hora para novos costumes. Sempre inicialize as variáveis. No caso de uma variável que só vai ser usada como índice em um loop, desde 1990 se pode declarar a variável no próprio comando for, escrevendo

	for(int i=0; i<10;i++);

E se tivesse escrito assim não teria errado no seu programa: ao encontrar o ';' terminaria o for e então o printf()

   printf("valor do elemento %d da string = %c\n",i,str[i]);

ia dar erro. A variável 'i' que só deveria existir dentro do loop não estaria declarada. E você teria notado o ';' ou não ia conseguir compilar o programa. Erros de compilação são muito melhores que erros de execução, como você viu aqui.

 

scanf()
 

scanf() é problemática para ler coisas do teclado. Essa função foi escrita para ler entrada formatada --- scan formatted input --- e a entrada pelo teclado não é nada formatada. O usuário tem 105 teclas ou mais de liberdade para digitar qualquer m#$d@. Evite usar. É possível mas só vai te dar dor de cabeça.  Entenda também que scanf() retorna um valor e você deveria tratar isso. Muitas vezes ela não lê nada e se você não testar não vai saber. Muitas vezes ela não lê tudo e logo depois você vai saber.

E você pode limitar o tamanho de cada campo a ser lido, usando o tamanho como em %14s no seu exemplo.

 

for(i=0;i<10;i++);


Em programas não é assim incomum esse comando estar certo. Mas entenda que ';' indica o final do comando em C. De qualquer comando. Uma maneira de diminuir a chance de você digitar isso por engano é escrever o loop sempre já com as chaves e depois digitar dentro...

	for( ;; ){ };

Se não precisar das chaves depois você apaga. Mas assim não vai esquecer delas ou colocar o ';' no lugar errado...

Acho que entendeu.

Se ficou curioso por isso poder estar certo, entenda que o comando for tem 3 partes, todas opcionais, separadas por dois ';' esses sim obrigatórios. Muitas vezes a lógica do loop está toda contida aí e não sobra nada para ficar dentro das  { } e elas podem ser então omitidas e fica só o ';'

 

Em seu programa pode ler até 14 letras, já que str é char[15] e tem que ter espaço para o zero no fim. Mas usou o limite de 10 fixo no loop. E se o cara digitar apenas 2? Ou 13? Ou teclar ENTER direto?

 

Na verdade você quer rodar o loop para mostrar o que tem na string e isso vai até o zero final, exclusive. Quase todo mundo iria rodar strlen(str) para ver o tamanho da string. E você pode fazer isso e ficar seguro de que o loop estará dentro dos limites do que foi digitado. Como você está começando agora pode ser boa hora de evitar também esse hábito. strlen() é uma função. Um pedaço de código escrito por alguém e que vai ser chamado, como scanf(). e vai retornar um valor, como scanf(). E tem um custo chamar uma função. E não é pequeno, em especial em um programa... pequeno :) E no seu caso ela vai ser chamada uma vez para cada letra. Pense nisso. Dentro do loop o tamanho da string pode ser alterado afinal.

 

E você não precisa nesse caso saber o tamanho da string: só quer mostrar o que tem dentro e ela termina com um zero. Isso quer dizer que você pode escrever

    for (int i = 0; str[i] != 0; i++)

simplesmente, já que o zero marca o fim da string.


i++


Evite essa construção.


Pode usar:

  • ++i
  • i++
  • i+=1
  • i = i + 1

Não faltam opções. Por razões históricas esse operador pós- é o mais usado. Mas é o menos esperto. O i++ ou i-- indica que a operação vai ser feita depois de o operando ser usado. Pesquise isso.


Esse trecho de programa

        int j = 2;
        int k = 3;
        printf("j = %d j++ = %d k = %d e ++k = %d\n",
            j, j++, k, ++k);
        printf("k = %d\n", k);

Mostra

j = 3 j++ = 2 k = 4 e ++k = 4
k = 4

Não escreva essas coisas. É só um exemplo. Mas entenda que toda vez que escreve isso o compilador salva e usa o valor da variável para depois fazer a soma. Use ++x se gosta desses, porque aí a operação é executada direto no operando.

 

	printf("valor do elemento %d da string = %c\n",i,str[i]);

 

Você está tentando mostrar algo que pode estar em branco, é uma string afinal. Se acostume a usar nesses casos um delimitador, tipo '%c' e assim saberá que está funcionando mesmo que na posição tenha um espaço ou um TAB por exemplo.

Escreva por exemplo

        printf("valor do elemento %d da string = '%c'\n", i, str[i]);


Seu programa um pouco diferente

#include <stdio.h>
int main(void)
{
    char str[15];
    printf("Digite um nome: ");
    scanf("%14s", str);
    for (int i = 0; str[i] != 0; i++)
        printf("valor do elemento %d da string = '%c'\n",
            i, str[i]);
}

Mostra

Digite um nome: abcdeABCDE1234
valor do elemento 0 da string = 'a'
valor do elemento 1 da string = 'b'
valor do elemento 2 da string = 'c'
valor do elemento 3 da string = 'd'
valor do elemento 4 da string = 'e'
valor do elemento 5 da string = 'A'
valor do elemento 6 da string = 'B'
valor do elemento 7 da string = 'C'
valor do elemento 8 da string = 'D'
valor do elemento 9 da string = 'E'
valor do elemento 10 da string = '1'
valor do elemento 11 da string = '2'
valor do elemento 12 da string = '3'
valor do elemento 13 da string = '4'
Pressione qualquer tecla para continuar. . .


 

Em 21/07/2020 às 16:22, Malcolm X disse:

Estava estudando e vi em um site que falava que usar gets e puts não eh muito profissional, não entendi muito porque, mas acho q está relacionado ao uso da memória, eu sei usar, mas evito

 

Não evite enquanto não entender :) 

De todo modo é bobagem. 

Use scanf() quando a entrada for formatada, como ler uma tabela ou um arquivo csv. Use fgets() para ler linhas e fgetc() para ler letras sempre que sua lógica permitir.

No "mundo profissional" não se lê valores do teclado para mostrar na tela desde os 90. Quanto são poucos argumentos são passados direto na linha de comando, como um MKDIR c:\teste no Windows. Quando são muitos e tem uma tela mesmo, e não tem MESMO jeito de usar uma interface gráfica, o que se faz é separar teclado e tela: 

  • você uma tecla por vez mas não mostra
  • se for algo válido aí sim você mostra e avança o cursor
  • se for inválido você apaga e pisca a tela ou toca um bip e continua

Usando scanf() sempre tem chance de zoar a tela. fgetc() e fgets() são mais seguras nesse aspecto mas não 100%

 

Em 21/07/2020 às 16:22, Malcolm X disse:

Eu aprendi esse outro caso abaixo, nesse caso seria pra "apagar" o Enter certo?

image.png.d3ba91b7ff9da9cc7710e8955ef5b027.png

 

Não, não vai apagar um enter.
 

O que está entre colchetes é uma lista dos caracteres que serão aceitos por scanf() para montar o campo. [1234] aceita só esses números, por exemplo. Mas se o primeiro caracter for ^ inverte o significado e passa a ser a lista dos caracteres que NÃO são aceitos. [ ^1234] vai ler em str até o primeiro desses dígitos aparecer: se o cara digitar 1234x scanf() vai ler "1234" em str. E vai retornar 1 o que deveria er lido e tratado pelo programa como eu expliquei. E vai deixar o 'x' lá para ser lido depois.

 

Então esse especificador que mostrou lê tudo que vier, até o ENTER, exclusive. Porque a lista tem só o '\n'.

Só que se o cara digitar ENTER direto scanf() não vai ler nada. Vai retornar zero só que você não está testando, como ninguém aparentemente testa. E eu programa vai imprimir um monte de bobagens provavelmente.

 

 

 

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

 

GRÁTIS: ebook Redes Wi-Fi – 2ª Edição

EBOOK GRÁTIS!

CLIQUE AQUI E BAIXE AGORA MESMO!