Ir ao conteúdo

Posts recomendados

Postado

Estou fazendo um exercício em c, no qual pede  para digitar 10 palavras de no máximo 30 caracteres e ao final pede para dar o total de caracteres digitados. porém meu contadores esta errado. poderiam me mostrar como é?

#include<stdio.h>
#include <string.h>

int main (){
	char pal[30];
	int i,j, contador=0;

	printf ("Digite 10 palavras:\n");
  
	for ( i=0; i<10; i++ ){
      	fgets(pal,30,stdin);
     	}

	printf("a quantidade de caracteres eh:%d",strlen(pal) );
}

 

Postado

@Helio Junnior Sartor Dalmolin     você criou a variáveL contador , creio que foi para armazenar a contagem de caracteres , mas não a usou em nenhum momento , e usando ela o total de caracteres é o que estará nessa variáveL  ,  sendo que no final de pois de ler as dez palavras você mandou escrever apenas o tamanho da Última palavra digitada ,  e dentro do Loop você poderia ter colocado instruções para acumular os tamanhos de todas as Dez palavras Digitadas , assim  :

for ( i=0; i<10; i++ )
{
    fgets(pal,30,stdin);        // o fgets pega o newLine q é o sinal de ENTER do teclado
    pal[strlen(pal)-1] = '\0';  // isso remove o newLine que o fgets pega junto com a
    contador += strlen(pal);    // palavra digitada
}                               // senão a palavra terá hum caractere a mais ou seja o newLine

e no final escreve o valor do contador assim :

#include<stdio.h>
#include <string.h>
#include <conio.h>
int main ()
{
    char pal[30];
    int i,j, contador=0;
    printf ("Digite 10 palavras:\n");
    for ( i=0; i<10; i++ )
    {
        fgets(pal,30,stdin);        // o fgets pega o newLine q é o sinal de ENTER do teclado
        pal[strlen(pal)-1] = '\0';  // isso remove o newLine que o fgets pega junto com a
        contador += strlen(pal);    // palavra digitada
    }
    printf("\n\na quantidade de caracteres eh : %d\n\n",
        /*strlen(pal)*/contador );  // isso q está comentado , pode deletar
    printf("\t\tTecle . . . !\n\n\n");
    getch();
    return 0;
}

 

Postado
13 horas atrás, Helio Junnior Sartor Dalmolin disse:

pede  para digitar 10 palavras de no máximo 30 caracteres e ao final pede para dar o total de caracteres digitados. porém meu contadores esta errado

 

@Helio Junnior Sartor Dalmolin "contadores" indica até mais de um contador. Mas seu programa não conta nada, . Até tem uma variável chamada contador, que nem

é usada.
 

Apenas postou um esqueleto de programa, talvez como "isca" para conseguir uma resposta completa ;)
  

7 horas atrás, devair1010 disse:

e dentro do Loop você poderia ter colocado instruções para acumular os tamanhos de todas as Dez palavras Digitadas , assim  :

for ( i=0; i<10; i++ )
{
    fgets(pal,30,stdin);        // o fgets pega o newLine q é o sinal de ENTER do teclado
    pal[strlen(pal)-1] = '\0';  // isso remove o newLine que o fgets pega junto com a
    contador += strlen(pal);    // palavra digitada
}  


Não, não assim, @devair1010

 

Tem vários erros do modo como escreveu... Testou isso? Leu o manual sobre scanf()? Tem um livro?

 

Declare as variáveis de controle do loop sempre DENTRO do comando, a menos que a lógica não permita, claro. Levou uns 10 anos para corrigir isso na linguagem, mas isso foi há 40 anos atrás.
 

// use:
    for ( int i=0; i<5; i++ )
      
// e nunca:
  int i;
// ...
    for ( i=0; i<5; i++ )

 

Se usar como escreveu uma variável com o ingênuo nome de i será declarada como global no bloco todo, no caso aqui o programa todo, e isso é uma receita pra um desastre. É perseguido e proibido em toda parte, escolas e empresas.

 

fgets() não "pega" um newline. Apenas preserva se tiver espaço. Seu programa não vai funcionar se na entrada o usuário digitar 29 das 30 letrinhas.  Se tiver 29 letras o newline não estará lá e seu programa vai apagar a última letra

 

E o tal newline vai rapidamente passar para a próxima leitura junto com qualquer eventual resto digitado. Não existe lixo no teclado. Apenas programas mal construídos. A próxima leitura não vai ler nada. Ou quase nada. Mas não vai ler o que você espera.

 

Apenas se o usuário entrar tem menos que as (n-1) no caso 29 letrinhas o newline vai estar lá. Só que você não testou.

 

fgets() retorna um ponteiro, char*, e você também não testou, como é comum de ver aqui. Então no caso de fim de arquivo a especificação diz que a string pal nesse caso fica inalterada, e o programa vai "ler" de novo a mesma coisa, de novo e de novo

 

 

        fgets(pal,30,stdin);        // o fgets pega o newLine q é o sinal de ENTER do teclado
        pal[strlen(pal)-1] = '\0';  // isso remove o newLine que o fgets pega junto com a

 

Considere que o cara pode ser seu professor ou que a entrada pode ter sido redirecionada, e EOF é algo tem possível. Se eu fosse revisor de código em sua empresa, ou seu professor, seria o primeiro teste que eu faria. E isso é o comum.

 

No caso de fgets() não ler nada então strlen(pal) vai ser zero. E a linha seguinte vai ficar
 

    pal[-1] = '0';

 

E isso pode levar a qualquer coisa, já que um índice negativo não está previsto. Pode ser inofensivo, pode cancelar o programa, UB, comportamento não especificado.

 

Você não inicializou pal então é um risco porque se fgets() não retornar nada vai ficar o que tinha lá e pode ser qualquer coisa. 

 

    pal[strlen(pal) - 1] = '\0';  // isso remove o newLine que o fgets pega junto com a
    contador += strlen(pal);      // palavra digitada

 

Pois é:

  • se pal[0] for zero o índice vai ficar negativo. Deve cancelar seu programa.
  • nem sempre vai ter um newline lá
  • entenda que '\0' é a mesma coisa claro que 0. Qual o propósito de digitar 4 letras ao invés de uma? O programa não vai ficar ais legível por isso.

Ao escrever um programa, em especial quando se está aprendendo e testando, vale a pena mostrar o que foi lido para aumentar a segurança (e no caso aqui a compreensão) do que acontece. Veja o seu programa, ainda com os erros, mas com um pouco mais de informação

 

no Windows

image.png.e5e2579782654d370ac3b4ec8dc7e86b.png

 

Sim, cancela. E estava errado de todo modo.

 

No linux Ubuntu 20
 

toninho@DSK-2009:~/projects/mapa$ cat entrada.txt | ./teste
Digite 5 palavras:

==> [loop 1] Antes de fgets() strlen(pal) = 0
fgets() leu 1 letras.
Os codigos: [ 10 ] 

[palavra considerada na contagem:  (0 letras)]

==> [loop 2] Antes de fgets() strlen(pal) = 0
fgets() leu 3 letras.
Os codigos: [ 49 50 51 ] 

[palavra considerada na contagem: 12 (2 letras)]

==> [loop 3] Antes de fgets() strlen(pal) = 2
fgets() leu 1 letras.
Os codigos: [ 10 ] 

[palavra considerada na contagem:  (0 letras)]

==> [loop 4] Antes de fgets() strlen(pal) = 0
fgets() leu 1 letras.
Os codigos: [ 10 ] 

[palavra considerada na contagem:  (0 letras)]

==> [loop 5] Antes de fgets() strlen(pal) = 0
fgets() leu 0 letras.
Os codigos: [ ] 

[palavra considerada na contagem:  (0 letras)]


a quantidade de caracteres eh : 2

                Tecle . . . !

 

Não cancela, mas está errado.

 

Para o mesmo arquivo entrada.txt
 


123

 

Com 3 linhas. A primeira e a última em branco. undefined behavior = UB = comportamento indefinido. Pode acontecer qualquer coisa. Em especial porque pal não está inicializado....

 

Eis o seu loop como usei
 

    for (i = 0; i < 5; i++)
    {
        printf("\
\n==> [loop %d]\nAntes de fgets() strlen(pal) = %ld\n",
            1+i,strlen(pal));
        fgets(pal, 4, stdin);        // o fgets pega o newLine q é o sinal de ENTER do teclado
        printf("fgets() leu %ld letras.\nOs codigos: [ ", strlen(pal));
        for (unsigned j = 0; j < strlen(pal); j += 1) printf("%d ", (int)pal[j]);
        printf("] \n");
        pal[strlen(pal) - 1] = '\0';  // isso remove o newLine que o fgets pega junto com a
        contador += strlen(pal);    // palavra digitada
        printf("\n[palavra considerada na contagem: %s (%ld letras)]\n", pal, strlen(pal));
    }

 

Claro, mudei de 30 para 4 o tamanho e de 10 para 5 o número de chamadas porque tenho mais o que fazer :D e acrescentei os printf()

 

Agora veja como o programa fica bonitinho se o usuário se comporta e entra com valores que cabem na string, incluso aí o tal newline:
 

Digite 5 palavras:

==> [loop 1]
Antes de fgets() strlen(pal) = 3
12
fgets() leu 3 letras.
Os codigos: [ 49 50 10 ]

[palavra considerada na contagem: 12 (2 letras)]

==> [loop 2]
Antes de fgets() strlen(pal) = 2
34
fgets() leu 3 letras.
Os codigos: [ 51 52 10 ]

[palavra considerada na contagem: 34 (2 letras)]

==> [loop 3]
Antes de fgets() strlen(pal) = 2
56
fgets() leu 3 letras.
Os codigos: [ 53 54 10 ]

[palavra considerada na contagem: 56 (2 letras)]

==> [loop 4]
Antes de fgets() strlen(pal) = 2
78
fgets() leu 3 letras.
Os codigos: [ 55 56 10 ]

[palavra considerada na contagem: 78 (2 letras)]

==> [loop 5]
Antes de fgets() strlen(pal) = 2
90
fgets() leu 3 letras.
Os codigos: [ 57 48 10 ]

[palavra considerada na contagem: 90 (2 letras)]


a quantidade de caracteres eh : 10

                Tecle . . . !

 

Sim, leu 10 letrinhas em 5 grupos de duas. Então está ok! Só que não.

  • Curtir 1
Postado
17 horas atrás, Helio Junnior Sartor Dalmolin disse:

Estou fazendo um exercício em c, no qual pede  para digitar 10 palavras de no máximo 30 caracteres e ao final pede para dar o total de caracteres digitados. porém meu contadores esta errado. poderiam me mostrar como é?

Sugiro que escreva o enunciado completo da questão.

 

Note que:

Uma palavra tem no máximo 30 caracteres (imprimíveis e não) ou termina antes de 30 com nova linha (do inglês: new line).

 

17 horas atrás, Helio Junnior Sartor Dalmolin disse:

[30];

 Não é capacidade desse vetor

 

é 32.

char    palavra[ 32 ];

 

Suponha que o usuário digite o máximo

andorinhas-de-pescoço-vermelho\n
~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~
             |
             |
             + -- -- -- --> A Palavra tem no máximo 30 caracteres
                           (Sem espaço)
                           
                           
andorinhas de pescoço vermelho\n
~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~
             |
             |
             + -- -- -- --> A Palavra tem no máximo 30 caracteres
                           (Com espaço)

 

Com e sem espaços foram digitados 31 caracteres. Por isso é

melhor que post o enunciado completo, seguido de nova tentativa de resposta.

[:)]

 

 

Postado
8 horas atrás, mauro_b disse:

Não é capacidade desse vetor

 

é 32.


char    palavra[ 32 ];

 

Suponha que o usuário digite o máximo

 

Não, não é 32. Está errado.

 

@mauro_b Considerando
 

char *fgets(char *string, int n, FILE* fluxo);


fgets() lê no máximo (n-1) caracteres. Se quer ler até 30 letras (inclusive) deve usar 31 e não 32 como escreveu. O tal '\n' newline não é digitado propriamente: é a tecla que sinaliza a fgets() o fim do processamento.

 

Pode usar 32, ou 3200. Mas a capacidade mínima necessária é 31.

 

fgets() acrescenta um newline (se tiver espaço) por uma cortesia. A ideia é pode usar puts() direto para imprimir, porque puts() é claro muito mais rápida que printf() e tem casos em que tudo que se quer é mostrar o que foi lido. Isso também vale para C++, inclusive para cout.

 

No enunciado aqui: apenas precisa do total de caracteres digitados, e como não dá pra garantir que toda string tenha um tal '\n' parece claro que não deve fazer parte da conta. Veja o exemplo que mostrei, um simples grupo de 5 linhas de 2 letras retorna 10. Nada mais.

 

fgets(string, n, stdin) por exemplo, retorna de TRES modos:

 

  1. leu n-1 caracteres
  2. leu um newline, o tal '\n'
  3. fim de arquivo na entrada, lembrando que é muito comum redirecionar a entrada desses programas console C e foi o grande mérito inicial do Unix, e fim de arquivo é algo comum. Na entrada em Windows control-Z gera fim de arquivo. 

Exemplo

 

#include "stdio.h"
#include "string.h"
int main (void)
{
    char    pal[31]={0};
    printf ("\
                                    ....*....1....*....2....*....3\n\
                                    1...*....0....*....0....*....0\n\
Digite uma frase com ate 30 letras: ");
    char* p = fgets(pal,31,stdin);
    printf("\tLeu %zd letras. A frase: ", strlen(pal));
    puts(p);
    return 0;
}

 

mostra

 

PS C:\src\C\ch0523> ./t
                                    ....*....1....*....2....*....3
                                    1...*....0....*....0....*....0
Digite uma frase com ate 30 letras: andorinhas de pescoco vermelho 
        Leu 30 letras. A frase: andorinhas de pescoco vermelho
PS C:\src\C\ch0523>

 

E le as 30 letras

 

Ou
 

PS C:\src\C\ch0523> clang -o t.exe t.c
PS C:\src\C\ch0523> echo  "andorinhas de pescoco vermelho" | ./t
                                    ....*....1....*....2....*....3
                                    1...*....0....*....0....*....0
Digite uma frase com ate 30 letras:     Leu 30 letras. A frase: andorinhas de pescoco vermelho
PS C:\src\C\ch0523>

 

Usando redirecionamento da entrada

 

 

  • Curtir 1
Postado
12 minutos atrás, mauro_b disse:

Essa é só a sua opinião

 

Notou o programa que mostrei e que le e mostra 30 bytes usando a própria string que você sugeriu e um vetor de 31 e não 32? @mauro_b

 

Leia a documentação. Poste algo objetivo.  Escreva e mostre um programa

 

Leia a documentação em https://pubs.opengroup.org/onlinepubs/009695399/functions/fgets.html

 

trecho.thumb.png.500cfd9c6263c426b355839a503b1911.png

 

Eu não escrevi fgets(). Acho que Ken Thompson escreveu. Mas está bem documentada.

 

Você pode estar certo, claro. A verdade é aquilo em que você acredita.

 

Mas estamos falando de C, C++ e C# e coisas documentadas.

 

Eu não estava mostrando a minha opinião. Essas coisas são para forums como o Discord imagino. Eu só expliquei porque bastam 31 bytes e mostrei um programa que usa isso.

 

 

 

 

 

 

:D 

  • Curtir 1
Postado

OK :)

 

 

Como disse antes, é melhor com enunciado completo.

 

7 minutos atrás, arfneto disse:

Eu não estava mostrando a minha opinião. Essas coisas são para forums como o Discord imagino. Eu só expliquei porque bastam 31 bytes e mostrei um programa que usa isso.

 

Sim, mais como falei, e vou falar outras vezes caso não tenha entendido da primeira. Eu até gosto de argumentos, porém nesse caso penso ser melhor o enunciado completo do autor da dúvida. 
 

Só para confirmar se um caractere a mais ou a menos faz diferença.

 

No aguardo

[:) 

Postado
10 horas atrás, arfneto disse:

O tal '\n' newline não é digitado propriamente: é a tecla que sinaliza a fgets() o fim do processamento.

 

É digitado sim, quando você aperta Enter o caractere '\n' é inserido na entrada e sinaliza o fim da entrada a ser lida pelo fgets().

 

10 horas atrás, arfneto disse:

Se quer ler até 30 letras (inclusive) deve usar 31 e não 32 como escreveu.

 

Usar 31 é o suficiente para ler 30 caracteres, mas 32 é melhor por garantir que o '\n' também seja lido quando for digitado 30 caracteres (se houver um '\n'), e não fique sobrando o '\n' na entrada padrão podendo causar problemas para leituras de entradas seguintes.

 

 

  • Curtir 1
Postado
1 hora atrás, isrnick disse:

É digitado sim, quando você aperta Enter o caractere '\n' é inserido na entrada e sinaliza o fim da entrada a ser lida pelo fgets().

 

Ok ok . Dá pra imaginar, @isrnick, que possa ser digitado já que é  a maior tecla do teclado e está escrito "ENTER" nela.

 

Vou explicar melhor: é mais que isso e pode nem ter sido digitada.

 

ENTER sinaliza o fim da entrada no modo normal de uso, LINE INPUT MODE no Windows ou Cooked Mode no Linux. E pode ou não estar presente na string retornada por fgets() e se estiver presente pode ou não ter sido de fato digitada a tal tecla.

 

A implementação INSERE um newline se tiver espaço para ele e um não tiver sido digitado na entrada. Isso derruba muitos e muitos programas de iniciantes. E alguns programas de profissionais.

 

A única garantia que se tem é que SE tiver um newline ele estará imediatamente antes do zero, que é garantido pela implementação.

 

 

  • Haha 1
Postado
Em 26/05/2021 às 22:53, Helio Junnior Sartor Dalmolin disse:

para digitar 10 palavras de no máximo 30 caracteres e ao final pede para dar o total de caracteres digitados.

Lendo ou relendo só esse trecho, porque é tudo que existe do enunciado, alguém pode se pergunta qual é o separado das palavras?  Toda resposta é o máximo 30 caracteres ou a linha, o que vier primeiro.

 

 

22 horas atrás, mauro_b disse:

Note que:

Uma palavra tem no máximo 30 caracteres (imprimíveis e não) ou termina antes de 30 com nova linha (do inglês: new line).

 Ou seja, usualmente para toda situação em que a palavra tem menos de 30 caracteres está capturando a nova linha, exceto quando a palavra tem os exatos 30 caracteres.

22 horas atrás, mauro_b disse:

Suponha que o usuário digite o máximo





andorinhas-de-pescoço-vermelho\n
~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~
             |
             |
             + -- -- -- --> A Palavra tem no máximo 30 caracteres
                           (Sem espaço)
                           
                           
andorinhas de pescoço vermelho\n
~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~
             |
             |
             + -- -- -- --> A Palavra tem no máximo 30 caracteres
                           (Com espaço)

 

 

Na expressão que realiza a contagem, pode ou não contar o newline com um digitável, depende do que está escrito no enunciado, mas o caractere precisa ser capturado.

 

 

Por esse motivo

3 horas atrás, isrnick disse:

Usar 31 é o suficiente para ler 30 caracteres, mas 32 é melhor por garantir que o '\n' também seja lido quando for digitado 30 caracteres (se houver um '\n'), e não fique sobrando o '\n' na entrada padrão podendo causar problemas para leituras de entradas seguintes.

 

 

1 hora atrás, arfneto disse:

ENTER sinaliza o fim da entrada no modo normal de uso

Nada no enunciado leva a acreditar que essa não é uma situação normal e que os dados fornecidos, sendo as palavras no limite do máximo, estarão fora do limite do que estipula o exercício. São hipóteses que o usuário criou para justificar sua opinião. 

 

Se tratando de exercício, a menos que se prenuncie contrário; os dados fornecidos são ideais (sem falhas).

 

 

Postado
41 minutos atrás, arfneto disse:

A implementação INSERE um newline se tiver espaço para ele e um não tiver sido digitado na entrada.

A função fgets não insere caractere nova linha '\n'.

 

Como exemplo veja esse simples código:

#include <stdio.h>

int main()
{
    char s[32];
    fgets(s, sizeof s, stdin);
    printf("\n%sAAA", s);
    return 0;
}

 

Quando executado no site https://www.onlinegdb.com/online_c_compiler e digitado abc e a aperta Enter, resultando em "abc\n" na entrada padrão stdin, a execução do programa fica assim:

 

abc

abc
AAA

 

Mas quando digita abc e aperta Ctrl+D para sinalizar o fim da entrada sem inserir o caractere '\n' (equivalente de Ctrl+Z no Windows), resultando em "abc" no stdin, a execução do programa fica assim:

 

abc
abcAAA

 

 

Observe que não é inserido o caractere '\n' no fim da string lida pelo fgets, pois não foi criada uma linha entre abc e AAA neste segundo caso.

 

fgets apenas lê caracteres da stream/arquivo que foi passada para ele, e nunca insere nada a mais do que está lá além do caractere nulo no fim da string (como todas as funções entrada da biblioteca padrão).

  • Curtir 1
Postado
13 horas atrás, arfneto disse:

No enunciado aqui: apenas precisa do total de caracteres digitados, e como não dá pra garantir que toda string tenha um tal '\n' parece claro que não deve fazer parte da conta. Veja o exemplo que mostrei, um simples grupo de 5 linhas de 2 letras retorna 10. Nada mais.

 

Essa é a sua opinião.

 

12 horas atrás, arfneto disse:

Eu não escrevi fgets(). Acho que Ken Thompson escreveu. Mas está bem documentada.

Você pode estar certo, claro. A verdade é aquilo em que você acredita.

 

Não entendi...

[:)]

 

Esta é a documentação dela, onde errei

image.png.836ec47bd50e7789cd023c1df5cbd46c.png

  • Curtir 1
Postado
3 horas atrás, isrnick disse:

A função fgets não insere caractere nova linha '\n'.

 

 

Você está enganado, @isrnick. É decisão da implementação em algumas situações. Se o total de caracteres for menor que (n-1) onde n é o parâmero para fgets() um newline será inserido. Ou não. O seu teste online é pouco objetivo. Compiladores online são ambientes estranhos, em especial quando se trata de arquivos e I/O. E são Linux em geral.

 

Como eu disse, 

 

4 horas atrás, arfneto disse:

A implementação INSERE um newline se tiver espaço para ele e um não tiver sido digitado na entrada. Isso derruba muitos e muitos programas de iniciantes. E alguns programas de profissionais.

 

A única garantia que se tem é que SE tiver um newline ele estará imediatamente antes do zero, que é garantido pela implementação.

 

3 horas atrás, mauro_b disse:

Esta é a documentação dela, onde errei

 

já expliquei isso nesse mesmo tópico, acho que 3 vezes e com exemplos: procure por exemplo onde eu disse das 3 condições de retorno de fgets(). Não precisaria de 32 no seu exemplo, apenas 31. E mostrei porque.

 

Como indicou @isrnick é mais conveniente, mas só isso. Não é necessário nem suficiente, porque sempre o usuário pode digitar algo mais e o newline sumir e "sobrar" com o resto  para a próxima leitura em programas ingenuamente escritos. Você põe 32 o cara usa 33. Você põe 300 e o professor usa um arquivo de 1MB para redirecionar ;) Essa é a primária razão de gets() ter sido marcada obsoleta dez anos atrás: buscar um buffer overflow era trivial. Com fgets() não é, mas pode sobrar um troco. E sobra.

 

Vou mostrar um exemplo.

 

Em geral os temas aqui são discussões mais elementares, mas vou deixar um exemplo em C desse caso. Não um para ser compilado online. 

 

Basicamente o mesmo programa que deixei aqui em um post anterior:

 

#include "stdio.h"
#include "string.h"
int main(void)
{
    char    pal[31] = { 0 };
    printf("\
                                    ....*....1....*....2....*....3\n\
                                    1...*....0....*....0....*....0\n\
Digite uma frase com ate 30 letras: ");
    char* p = fgets(pal, 31, stdin);
    printf("\tLeu %zd letras. A frase:\n", strlen(pal));
    for (int i = 0; i < strlen(pal); i += 1) printf("%d ", pal[i]);
    printf("\nA frase: ");
    puts(p);
    return 0;
}

 

Simplesmente lê até 30 letrinhas, como mostrei em reação à afirmação de @mauro_b que dizia que eram precisos 32. E não são.

 

Eis o programa rodando e lendo 30 letrinhas:
 

toninho@DSK-2009:~/projects/mapa$ 
toninho@DSK-2009:~/projects/mapa$ ./t-clang
                                    ....*....1....*....2....*....3
                                    1...*....0....*....0....*....0
Digite uma frase com ate 30 letras: 123456789A123456789A123456789A 
        Leu 30 letras. A frase:
49 50 51 52 53 54 55 56 57 65 49 50 51 52 53 54 55 56 57 65 49 50 51 52 53 54 55 56 57 65 
A frase: 123456789A123456789A123456789A
toninho@DSK-2009:~/projects/mapa$ 

 

O programa mostra uma guia com os números da colunas para ajudar a contar :) le a string via fgets(,31,) e não 32, e lê as 30 letrinhas sem problema. E sem newline porque não cabe. E claro que ele foi digitado, o tal ENTER

 

 

Considerando também a afirmação de @irsnick vou mostrar ainda um quarto exemplo, logo mais.

 

Agora veja o que acontece no Linux usando clang e gcc para compilar o tal programa e ler esse arquivo "um.txt":
 

toninho@DSK-2009:~/projects/mapa$ 
toninho@DSK-2009:~/projects/mapa$ od -xc um.txt
0000000    6761    726f    2061    6f6e    4c20    6e69    7875    2e2e
          a   g   o   r   a       n   o       L   i   n   u   x   .   .
0000020    002e
          .
0000021
toninho@DSK-2009:~/projects/mapa$ ls -l um.txt
-rw-r--r-- 1 toninho toninho 17 May 28 16:26 um.txt
toninho@DSK-2009:~/projects/mapa$ cat um.txt
agora no Linux...toninho@DSK-2009:~/projects/mapa$ 

 

O arquivo tem 17 bytes e não tem um newline. E 15 é menor que 30 então tem espaço para um newline.

Veja o que acontece compilando isso com gcc e clang  em Ubuntu 20:

 

oninho@DSK-2009:~/projects/mapa$ 
toninho@DSK-2009:~/projects/mapa$ gcc -o t-gcc -Wall -O2 t.c
toninho@DSK-2009:~/projects/mapa$ clang -o t-clang -Wall -O2 t.c
toninho@DSK-2009:~/projects/mapa$ cat um.txt | ./t-clang
                                    ....*....1....*....2....*....3
                                    1...*....0....*....0....*....0
Digite uma frase com ate 30 letras:     Leu 17 letras. A frase:
97 103 111 114 97 32 110 111 32 76 105 110 117 120 46 46 46 
A frase: agora no Linux...
toninho@DSK-2009:~/projects/mapa$ cat um.txt | ./t-gcc
                                    ....*....1....*....2....*....3
                                    1...*....0....*....0....*....0
Digite uma frase com ate 30 letras:     Leu 17 letras. A frase:
97 103 111 114 97 32 110 111 32 76 105 110 117 120 46 46 46 
A frase: agora no Linux...
toninho@DSK-2009:~/projects/mapa$ 

 

E fgets() reporta o que tem no disco, 17 letras

 

Agora no Windows, usando o compilador da Microsoft e versões recentes dos mesmos clang e gcc e esse arquivo, trocando Linux por Windows

 

C:> od -xc um.txt
0000000    6761    726f    2061    6f6e    5720    6e69    6f64    7377
          a   g   o   r   a       n   o       W   i   n   d   o   w   s
C:> dir um.txt


    Diretório: C:\Users\toninho\source\repos\ConsoleApplication51\Release


----                 -------------         ------ ----
-a----        28/05/2021     16:45             19 um.txt


C:> clang -o t-clang.exe -Wall -O2 t.c
C:> gcc -o t-gcc.exe -Wall -O2 t.c    
                                    ....*....1....*....2....*....3
                                    1...*....0....*....0....*....0
Digite uma frase com ate 30 letras:     Leu 20 letras. A frase:
97 103 111 114 97 32 110 111 32 87 105 110 100 111 119 115 46 46 46 10
A frase: agora no Windows...

C:> type um.txt | .\t-clang.exe
                                    ....*....1....*....2....*....3
                                    1...*....0....*....0....*....0
Digite uma frase com ate 30 letras:     Leu 20 letras. A frase:
97 103 111 114 97 32 110 111 32 87 105 110 100 111 119 115 46 46 46 10
A frase: agora no Windows...

C:> type um.txt | .\t-gcc.exe
                                    ....*....1....*....2....*....3
                                    1...*....0....*....0....*....0
Digite uma frase com ate 30 letras:     Leu 20 letras. A frase:
97 103 111 114 97 32 110 111 32 87 105 110 100 111 119 115 46 46 46 10
A frase: agora no Windows...

C:>

 

E as 17 letrinhas viram 19., Mas fgets() reporta 20... E lá no fim está o newline, com os 3 compiladores. Código 10.

 

É uma situação limite, mas erros tipo  one-off são as causas mais frequentes de erro em programas de toda sorte. E é o caso. Pode acontecer e acontece.

 

Para quem ficou com preguiça de ler e pulou para o fim:

 

 

PS C:\Users\toninho\source\repos\ConsoleApplication51\Release> echo "1" |  .\t-clang.exe 
                                    ....*....1....*....2....*....3
                                    1...*....0....*....0....*....0
Digite uma frase com ate 30 letras:     Leu 2 letras. A frase:
49 10
A frase: 1

PS C:\Users\toninho\source\repos\ConsoleApplication51\Release>

 

E uma letra virou duas: o 1 e o newline

 

 

 

 

  • Obrigado 1
Postado
26 minutos atrás, arfneto disse:

Você está enganado, @isrnick. É decisão da implementação em algumas situações. Se o total de caracteres for menor que (n-1) onde n é o parâmero para fgets() um newline será inserido. Ou não.

esse não é o  texto na norma (padrão).

 

26 minutos atrás, arfneto disse:

Não é necessário nem suficiente, porque sempre o usuário pode digitar algo mais e o newline sumir e "sobrar" com o resto  para a próxima leitura em programas ingenuamente escritos. Você põe 32 o cara usa 33. Você põe 300 e o professor usa um arquivo de 1MB para redirecionar

Só especulação, o enunciando garante que a palavra tem no máximo 30 caracteres, mas não diz nada sobre exceções do tipo que leva o usuário a cometer erros, nem se que sabe ao certo se O usuário é humano, a entrada pode bem vir formada de outra sistema.

 

Decerto a palavra tem no máximo 30... isso é garantido por razão do enunciado

 

 

 

Exemplo:

castanhas-subterrâneas-maiores
acetilparaetoxilfeniluretânico
capins-finos-de-folha-comprida
canelas-sassafrasinho-do-campo
cabeças-duras-focinhos-de-rato
brocas-do-coleto-do-algodoeiro
borboleta-amarela-da-mamoneira
bicos-de-brasa-de-testa-branca
bico-grosso-da-garganta-branca
besouros-amarelos-do-eucalipta
beija-flores-de-orelha-violeta
beija-flor-de-gravata-vermelha
beija-flor-azul-de-rabo-branco

 

 

 

@arfneto Quais dos programas  testamos um arquivo assim?

  • Curtir 1
Postado

 

 

13 minutos atrás, mauro_b disse:

esse não é o  texto na norma (padrão).

 

@mauro_b eu te mostrei que o comportamento de fgets() é diferente do Windows e no Mac e no Linux e no Unix. E usando 3 compiladores no Windows e dois no Linux. A decisão do que fazer naquela condição é dependente da implementação.  E aquilo é uma condição que afeta todo programa que usa fgets() para ler um fluxo. Deve imaginar que são muitos programas. e um pode ser seu: recomendo que faça como eu e escreva um, teste e poste aqui, se acha que pode acrescentar algo objetivo em C, C# ou C++.

 

19 minutos atrás, mauro_b disse:

Só especulação, o enunciando garante que a palavra tem no máximo 30 caracteres, mas não diz nada sobre exceções do tipo que leva o usuário a cometer erros, nem se que sabe ao certo se O usuário é humano, a entrada pode bem vir formada de outra sistema.

 

Decerto a palavra tem no máximo 30... isso é garantido por razão do enunciado

 

Acho que não percebeu que nos exemplos que te mostrei a entrada era por duas maneiras distintas: um echo e um pipe... Não por um "usuário"

 

Não, não se trata de especulação. Estou tentando explicar para quem esteja lendo isso e esteja começando, ou qualquer um que ache que pode aprender algo, que há diferenças importantes e condições limite a serem testadas no uso dessas funções. Como eu disse, não é um tema para iniciantes, mas acho que o que importa saber é que:

  • fgets() pode retornar por 3 maneiras distintas
  • fgets() retorna um char* que pode ser NULL
  • se retornar NULL a string passada como primeiro parâmetro fica inalterada
  • errno é ajustado em caso de erro
  • se tiver um newline ele é único e estará no final
  • a rotina é diferente em Linux/Mac e Windows
  • o que tiver além do limite vai ficar lá para ser lido depois

 

  • Confuso 1
Postado

Não sei qual dos programas desses (na discussão) me permitiria testar um arquivo naquele formato padrão da função fgets.

:) 

 

39 minutos atrás, arfneto disse:

Deve imaginar que são muitos programas. e um pode ser seu: recomendo que faça como eu e escreva um, teste e poste aqui, se acha que pode acrescentar algo objetivo em C, C# ou C++.

Por quê? Eu não preciso provar nada a ninguém  @arfneto , muito menos para um estranho que frequenta o mesmo fórum de discussão. Não é você que decide o que é objetivo ou não. Mas está livre para deixar sua OPINIÃO, como sempre fez.

 

Além disso, não seguirei sua recomendação porque poderia está resolvendo o exercício por ele (o autor do tópico) sem haver necessidade para tanto,

 

mas não me importo que outros o faça, cada qual usa o fórum do seu modo, e isso é super normal.

[:)

Postado

@arfneto No Windows você redirecionou a saída de type (e depois de echo) para os executáveis dos seus programas, e é o type quem adiciona o caractere nova linha '\n' no fim do texto do arquivo um.txt ...

 

O modo correto de redirecionar um arquivo texto como entrada de um executável no Windows é assim:

 

t-gcc.exe < um.txt

 

Veja o resultado do seu programa compilado em ambos no MSVC (cl) e no Mingw/GCC, fazendo o redirecionamento corretamente:

 

C:\C-Cpp>type um.txt
agora no Windows...
C:\C-Cpp>cl t.c
Microsoft (R) C/C++ Optimizing Compiler Versão 19.16.27045 para x86
Copyright (C) Microsoft Corporation. Todos os direitos reservados.

t.c
Microsoft (R) Incremental Linker Version 14.16.27045.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:t.exe
t.obj

C:\C-Cpp>gcc -o t-gcc.exe t.c

C:\C-Cpp>t.exe < um.txt
                                    ....*....1....*....2....*....3
                                    1...*....0....*....0....*....0
Digite uma frase com ate 30 letras:     Leu 19 letras. A frase:
97 103 111 114 97 32 110 111 32 87 105 110 100 111 119 115 46 46 46
A frase: agora no Windows...

C:\C-Cpp>t-gcc.exe < um.txt
                                    ....*....1....*....2....*....3
                                    1...*....0....*....0....*....0
Digite uma frase com ate 30 letras:     Leu 19 letras. A frase:
97 103 111 114 97 32 110 111 32 87 105 110 100 111 119 115 46 46 46
A frase: agora no Windows...

 

Não há exceções, a função fgets() não adiciona caractere '\n' no fim do texto em nenhum deles.

 

 

  • Curtir 2
Postado
                                    ....*....1....*....2....*....3
                                    1...*....0....*....0....*....0
Digite uma frase com ate 30 letras: 	Leu 30 letras. A frase:
97 99 101 116 105 108 112 97 114 97 101 116 111 120 105 108 102 101 110 105 108 117 114 101 116 -61 -94 110 105 99 
A frase: acetilparaetoxilfeniluretânic
                                    ....*....1....*....2....*....3
                                    1...*....0....*....0....*....0
Digite uma frase com ate 30 letras: 	Leu 3 letras. A frase:
111 13 10 
A frase: o

                                    ....*....1....*....2....*....3
                                    1...*....0....*....0....*....0
Digite uma frase com ate 30 letras: 	Leu 30 letras. A frase:
97 108 102 97 102 97 115 45 100 101 45 115 101 109 101 110 116 101 115 45 101 115 112 105 110 104 111 115 97 115 
A frase: alfafas-de-sementes-espinhosas
                                    ....*....1....*....2....*....3
                                    1...*....0....*....0....*....0
Digite uma frase com ate 30 letras: 	Leu 2 letras. A frase:
13 10 
A frase: 

                                    ....*....1....*....2....*....3
                                    1...*....0....*....0....*....0
Digite uma frase com ate 30 letras: 	Leu 30 letras. A frase:
97 110 100 111 114 105 110 104 97 115 45 100 101 45 112 101 115 99 111 -61 -89 111 45 118 101 114 109 101 108 104 
A frase: andorinhas-de-pescoço-vermelh
                                    ....*....1....*....2....*....3
                                    1...*....0....*....0....*....0
Digite uma frase com ate 30 letras: 	Leu 3 letras. A frase:
111 13 10 
A frase: o

                                    ....*....1....*....2....*....3
                                    1...*....0....*....0....*....0
Digite uma frase com ate 30 letras: 	Leu 30 letras. A frase:
98 97 108 97 110 -61 -89 97 45 114 97 98 111 45 100 101 45 103 97 114 103 97 110 116 97 45 112 114 101 116 
A frase: balança-rabo-de-garganta-pret
                                    ....*....1....*....2....*....3
                                    1...*....0....*....0....*....0
Digite uma frase com ate 30 letras: 	Leu 3 letras. A frase:
97 13 10 
A frase: a

                                    ....*....1....*....2....*....3
                                    1...*....0....*....0....*....0
Digite uma frase com ate 30 letras: 	Leu 30 letras. A frase:
98 101 105 106 97 45 102 108 111 114 45 97 122 117 108 45 100 101 45 114 97 98 111 45 98 114 97 110 99 111 
A frase: beija-flor-azul-de-rabo-branco
                                    ....*....1....*....2....*....3
                                    1...*....0....*....0....*....0
Digite uma frase com ate 30 letras: 	Leu 2 letras. A frase:
13 10 
A frase: 

output.txt

 

main.c

#include "stdio.h"
#include "string.h"
int func( void ){
    char    pal[31] = { 0 };
    printf("\
                                    ....*....1....*....2....*....3\n\
                                    1...*....0....*....0....*....0\n\
Digite uma frase com ate 30 letras: ");
    char* p = fgets(pal, 31, stdin);
    printf("\tLeu %zd letras. A frase:\n", strlen(pal));
    for (int i = 0; i < strlen(pal); i += 1) printf("%d ", pal[i]);
    printf("\nA frase: ");
    puts(p);
    return 0;
}
int main( void ){
        for(int i = 0 ;    i < 10    ; ++i){
                func( );
        }
        return 0;
}

image.png.92ef5b4389d77f9121d1b6816cb92b05.png

 

 

image.png.7f9068ffcc34d2ff47d39022fc5c832c.png

O caractere newLine (que nos arquivos do Windows é; CRLF) sendo capturado.

Porque arquivos gerados no Windows tem um padrão.

 

[:)]  Função fgets para no LF, conforme a normal (padrão)

  • Curtir 1
Postado

Fiz o teste para um só palavra sem dar NL no arquivo.

Ele não aparece, porque não tem.

 

Legal :D 

Dar um Enter lá, e pronto ele aparece junto a última letra.

acetilparaetoxilfeniluretanico[CRFL]

 

 

 

image.png.b735ca93e4d323a67299e83b1dc49360.png

 

 

Ainda não entendi porque 32 ou 33 caracteres não resolve esse problema.

Se tem que resolver com fgets então:

 

Captura-se a linha com 32 ou 33 caracteres, pois sabemos que se não for assim vai ter que liberar esses não uteis para o resultado de outra maneira. Já sabe que 2 deles é newLine então subtraia do resultado do retorno da strlen.

 

:thumbsup: 

Postado
12 horas atrás, mauro_b disse:

Fiz o teste para um só palavra sem dar NL no arquivo.

Ele não aparece, porque não tem

 

Ele aparece, desde que tenha espaço. Como está no manual. Como te mostrei. com limite de 31 lê até 30. Se digitar menos que 30 um newline estará no fim.

 

Se não digitar ENTER um fgets() não retorna a menos que tenha desligado LINE INPUT no Windows ou esteja usando Raw Mode no Linux/Mac.

 

Como eu disse umas vezes, fgets() retorna em tres casos.

 

12 horas atrás, mauro_b disse:

Captura-se a linha com 32 ou 33 caracteres, pois sabemos que se não for assim vai ter que liberar esses não uteis para o resultado de outra maneira

 

Não, não sabemos. Se pode usar também 34 ou qualquer valor até LINE_MAX (em limits.h). O usuário sempre pode estourar esse limite e deixar algo para ser lido depois. A garantia de fgets() é que não vai ter buffer overflow na chamada. Mas por certo pode ter um troco no buffer. Até LINE_MAX.

 

 

14 horas atrás, isrnick disse:

Não há exceções, a função fgets() não adiciona caractere '\n' no fim do texto em nenhum deles

 

@isrnick sim! tem razão. Eu até gostei de achar que tinha, mas usei apenas echo e type porque usava o terminal do Windows e o terminal não aceita '<' e não vi importância. My bad. Obrigado por apontar isso.

 

13 horas atrás, mauro_b disse:

O caractere newLine (que nos arquivos do Windows é; CRLF) sendo capturado.

Porque arquivos gerados no Windows tem um padrão

 

São dois mas são lidos como um newline apenas. No disco estarão os dois, carriage return, 13, line feed 10, mas ao ler sem um "b" no modo de abertura os dois são lidos como um só, o 10, newline

 

PS C:\Users\toninho\source\repos\ConsoleApplication51\Release> echo "clube" | od -xc
0000000    6c63    6275    0d65    000a
          c   l   u   b   e  \r  \n
0000007

 

  • Confuso 1
Postado
3 horas atrás, arfneto disse:

Ele aparece, desde que tenha espaço. Como está no manual. Como te mostrei. com limite de 31 lê até 30. Se digitar menos que 30 um newline estará no fim. Se não digitar ENTER um fgets() não retorna a menos que tenha desligado LINE INPUT no Windows ou esteja usando Raw Mode no Linux/Mac.

 

Como eu disse umas vezes, fgets() retorna em tres casos.

Não, não, está comentando de outra situação, que não é que se encontra no enunciado do exercício. E sim, penso que a maioria entendeu o que tentou explicar e as diferenças dos diferentes retornos da função.

 

 

3 horas atrás, arfneto disse:

Não, não sabemos. Se pode usar também 34 ou qualquer valor até LINE_MAX (em limits.h). O usuário sempre pode estourar esse limite e deixar algo para ser lido depois. A garantia de fgets() é que não vai ter buffer overflow na chamada. Mas por certo pode ter um troco no buffer. Até LINE_MAX.

 

Sim, sim, sabemos o que tem no enunciado para a partir disso racionalizar um programa, ao menos uma solução que funcione num caso específico sem se preocupar se o tal "usuário" vai teclar com bund4 ou bater com teclado na cabeça, ou digitará além do permitido, ou quais enganos de poderiam afetar a resposta, ou quais situações fora do escopo normal de leitura da função  fgets.

 

 

 

3 horas atrás, arfneto disse:

São dois mas são lidos como um newline apenas. No disco estarão os dois, carriage return, 13, line feed 10, mas ao ler sem um "b" no modo de abertura os dois são lidos como um só, o 10, newline

 

Não, não... eu não preciso que diga nada sobre abrir fluxos ou traga outras complicações para o que já está por demais discutido. Vamos usar redirecionamento na linha de comando, na forma correta, e avaliar o newLine (no padrão Windows).

 

Vejam abaixo, usei um programa dessa discussão e um arquivo digitado com newLine.

image.png.3472000b4cb2038ff2764639e3bdc95d.png

Resultado 2 letras ou 2 char. Por ora isso é tudo que precisamos para escrever uma solução.

 

A situação [aquela definida pelo enunciado]

Em 26/05/2021 às 22:53, Helio Junnior Sartor Dalmolin disse:

Um exercício em c, no qual pede  para digitar 10 palavras de no máximo 30 caracteres e ao final pede para dar o total de caracteres digitados. porém meu contadores esta errado. poderiam me mostrar como é?

 

Como pretende ler os dados? Redirecionando o fluxo de entrada no Windows

Supondo que o arquivo tem 10 palavras e cada palavra de no máximo 30 caracteres [conforme enunciado], e estão separadas por ENTER

Desse jeito:

canelas-sassafrasinho-do-campo
cabecas-duras-focinhos
brocas-do-coleto-do-algodoeiro
borboleta-amarela-da-mamoneira
bicos-de-brasa-de-testa-branca
bico-grosso-da-garganta-branca
besouros-amarelos-do-eucalipta
beija-flores-de-orelha-violeta
beija-flor-de-gravata
beija-flor-azul-de-rabo-branco

 

O vetor vai precisar de no máximo capacidade suficiente para 30 caracteres ou letras + o separador de palavras.

main.c

#include <stdio.h>
#include <string.h>
int func( void ){
    char palavra[33] = { 0 };
    fgets( palavra , 33 , stdin );
    if (palavra[0])
            printf( "Leu %zd letras.\n" ,  strlen( palavra ) - 2 );
    return 0;
}
int main( void ){
        for (int i = 0 ;    i < 10    ; ++i){
                func( );
        }
        return 0;
}

 

Ilustração

image.png.2fbf02aebf7865767af4687da6107080.png

 

Um padrão Windows que difere do padrão (Norma) do C não dificulta em nada a solução, em específico, para leitura com redirecionamento.

 

Veja o texto da normal

image.png.836ec47bd50e7789cd023c1df5cbd46c.png

 

 

Numa situação normal a função não mais captura dados, após encontrar o caractere de nova linha ou atingir o limite especificado pela variável com valor do tamanho.

 

Tradução Eletrônica:

Descrição

Citação

A função   fgets   lê no máximo um a menos do que o número de caracteres especificado por n do stream apontado por stream na matriz apontada por s. Nenhum caractere adicional é lido após um caractere de nova linha (que é retido) ou após o fim do arquivo. Um caractere nulo é escrito imediatamente após o último caractere lido no array.

 

 

 

No portal: https://www.cplusplus.com/reference/cstdio/fgets/

image.png.72be7367958e04391c996a53a3353f27.png

 

 

Aqui a discrição é um pouco mais clara, principalmente, com o significa de retido:

 

Um caractere de nova linha faz com que fgets pare, porém, é um caractere válido pela função e incluído na ‘string’ copiada para str. Ou seja, a função para de lê de duas maneiras: quando atinge o limite estipulado e quando o caractere de nova linha é lido, o que vier primeiro em caso de sucesso.

 

Portanto, o caractere de nova linha é considerado um caractere válido pela função, havendo espaço ele será copiado para o vetor com os outros isso pode estar afetando seus "contadores", caro usuário.

:thumbsup: 

  • Curtir 1

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!