leitura em c [RESOLVIDO]

1. leitura em c [RESOLVIDO]

Perfil removido
removido

(usa Nenhuma)

Enviado em 17/04/2020 - 10:24h

escrevi esse codigo

#include <stdio.h>
#include <stdlib.h>

int main(){
char buffer[1000];
char dir[100];
FILE *file;
printf("file: ");
fgets(dir, 100, stdin);
file = fopen(dir, "r");
if(file == NULL){
printf("arquivo não encontrado\n");
}
else{
do{

printf("%s", buffer);
}
while(fgets(buffer, 1000, file) != NULL);

}


return 0;
}


mas não encontro erro!
sempre cai no if e não no else!
agradeço a quem me ajudar!


  


2. MELHOR RESPOSTA

Paulo
paulo1205

(usa Ubuntu)

Enviado em 18/04/2020 - 13:05h



O material indicado infelizmente tem diversos problemas. Entre eles:

  • Ao longo de todo o capítulo, ele consistentemente chama declarações de “sintaxe”. Por mais que declarações tenham de obedecer regras sintáticas da linguagem, as duas coisas não são sinônimas.

  • A constante EOF é apresentada como um possível valor de retorno de fgetc() que só ocorre caso o fim do arquivo seja atingido. Na verdade, qualquer situação que impeça a leitura do próximo caráter produz EOF como resultado. Chegar ao fim do arquivo é uma dessas situações, mas há também casos como uma falha de disco que ocorra durante a leitura do próximo bloco de dados e situações de erro em nível de sistema operacional, tais como um socket ou pipe marcado como não-blocante e que ainda não tem nenhum dado disponível para leitura, mas que pode vir a ter em um momento posterior.

  • Apesar de ter explicado que fgetc() retorna um valor do tipo int para acomodar todos os possíveis caracteres (valores de 0 a 255, em máquinas cujo tipo char tem oito bits) e também a sinalização de erro (EOF, cujo valor é -1), todos os programas mostrados como exemplo usam variáveis do tipo char para receber o valor retornado por fgetc(), o que elimina completamente a possibilidade de detectar o valor EOF de maneira confiável. Para que EOF possa caber na variável, que só tem o espaço de um char, alguns bits têm de ser truncados, e o resultado desse truncamento pode produzir um valor que é idêntico ao de um caráter válido (num arquivo de texto em um sistema com codificação Windows CP1252 ou ISO-8859-1, esse caráter é o “Y minúsculo com trema”, ou 'ÿ'; num arquivo binário, é o byte com valor '\xff').
    Depois do truncamento, que gera a ambiguidade que já é um problema por si só, existe o problema da comparação desse valor com EOF, que provoca a conversão inversa, de char para int. Essa conversão pode cair em um dos seguintes casos.
      • Se o tipo char, por padrão (como nos nossos PCs com processadores Intel ou AMD) ou por força de alguma opção de compilação, for com sinal (i.e. representa valores entre -128 e +127, em máquinas em que o char tem oito bits), então a ambiguidade mencionada acima pode interromper a leitura antes da hora, pois o caráter com valor -1 (como o 'ÿ' ou o byte '\xff') será convertido para inteiro como -1, que é o mesmo valor de EOF.
      • Se o tipo char, por padrão (como nos nossos celulares como processadores ARM) ou por força de alguma opção de compilação, for sem sinal (i.e. representa valores entre 0 e 255, em máquinas em que o char tem oito bits), a ambiguidade mencionada acima também existe, mas o valor ambíguo é igual a (char)255. Tal valor, ao ser convertido de volta para int durante a operação de comparação, produzirá o valor inteiro 255, e portanto nunca será igual a EOF, de modo que o laço de repetição nunca será interrompido, mesmo que fgetc() repetidamente encontre o fim de arquivo ou algum erro.

  • A declaração mostrada para fscanf() está incorreta (e ele ainda a chama de “sintaxe“).

  • Ao dizer, sobre fscanf(), que “[c]omo as outras, retorna EOF caso não tenha conseguido fazer a leitura”, ele erra de múltiplas maneiras. De cara, a que “outras” ele se refere? O plural não cabe porque, antes de fscanf(), ele só falou de fgetc(); depois, ele só fala de uma função que nem sequer pode retornar EOF, já que o tipo de dados retornado não é compatível com tal valor. Além disso, não existe “a leitura” como operação atômica por parte de fscanf(), e o valor de retorno vai depender do conteúdo da string de formatação, podendo inclusive indicar sucesso parcial. A função só retorna EOF em casos específicos, podendo inclusive não retornar EOF mesmo que o fim de arquivo tenha sido encontrado. É importante ler uma documentação da função para conhecer esses casos (a documentação da manpage da função no Linux é um exemplo de boa documentação).

  • O autor não explica coisa alguma sobre a forma de passar argumentos que devem receber valores como parâmetros para fscanf(). Apesar de ser uma frequente causa de dúvidas entre iniciantes e uma excelente oportunidade para explicar a passagem de referências como argumentos, o artigo simplesmente não fala coisa alguma a respeito (nem ali, nem em capítulos anteriores da mesma apostila).

  • Na descrição de fgets(), o autor menciona o uso de gets(), que era uma função tão mal concebida que acabou sendo eliminada da biblioteca padrão do C no padrão de 2011 (e antes disso, no padrão de 1999, já era marcada como obsoleta, e os compiladores costumavam produzir alertas quando ela era usada). Que ela ainda seja mencionada no material do curso é, por si só, um problema.

  • Ao dizer que “[m]uitas vezes é interessante pegar uma linha inteira de um arquivo, principalmente se nesse arquivo existir (sic) textos”, o autor pode ter cometido, além do erro de concordância, também um erro de categorização. Do ponto de vista do C, um arquivo é integralmente de texto ou integralmente binário, e a existência de linhas é justamente uma das características que definem um arquivo de texto (§7.21.2, parágrafo 2 do padrão do C de 2018). Do modo como ele escreveu, fica a dúvida de se ele imagina tratar partes de um arquivo binário como se fosse texto, o que é até possível, mas tem uma razoável possibilidade de não produzir muito bons resultados.

  • A explicação do funcionamento da função diz que “[a] função vai abrir o arquivo apontado por arq”, o que é falso. O arquivo já tem de estar aberto em modo de leitura, e a função recebe um ponteiro para o stream já aberto.

  • Ao longo da explicação de fgets(), não fica suficientemente claro que a função retém o caráter de fim de linha após a leitura (se ele couber no array de destino). Não que a descrição “vai pegar do primeiro caractere até o new line” esteja incorreta, mas a menção anterior da antiga gets() com praticamente a mesma descrição de funcionamento ajuda ainda mais criar a confusão, uma vez que gets() descartava o caráter de fim de linha, em lugar de copiá-lo para o array. Também contribui para causar confusão dizer a forma de fgets() obter seus dados é “igual aqueles formulários que preenchemos na internet”.

  • Ainda a respeito de manter ou descarar o caráter de fim de linha, seria interessante mostrar como fazer o descarte, caso desejável ou necessário.

  • Por fim, a sugestão de que verificar se o valor retornado por fgets() é igual a NULL é suficiente para indicar que se chegou ao final do arquivo não está correta. Outras situações também podem provocar o retorno de NULL, e o fim de arquivo também pode já ter sido atingido, mas fgets() ainda não refletir essa condição no valor de retorno (e isso é, inclusive, um dos motivos pelos quais a função repassa o caráter de fim de linha à string, em lugar de o descartar).


... Então Jesus afirmou de novo: “(...) eu vim para que tenham vida, e a tenham plenamente.” (João 10:7-10)

3. Re: leitura em c

Paulo
paulo1205

(usa Ubuntu)

Enviado em 17/04/2020 - 13:28h

A função fgets() não remove o caráter de fim de linha que corresponde à tecla Enter.

Muita gente não gosta dessa característica da função, mas eu penso que ela é útil para ajudar o programador a diagnosticar se ele realmente recebeu uma linha inteira ou se houve truncamento dos dados. Sem essa marca, a detecção de truncamento seria muito mais difícil.

O que normalmente se faz é extirpar manualmente a marca de fim de linha.
size_t l=strlen(str);
if(l-- > 0 && str[l]=='\n')
str[l]='\0';


Você pode inclusive transformar isso numa função, que poderá então ser chamada após cada chamada que você fizer a fgets().
// Função de remoção de '\n' do fim de uma string.  Retorna 1 se remoção ocorrer; 0 se não ocorrer.
int chomp(char *str){
size_t l=strlen(str);
if(l-- > 0 && str[l]=='\n'){
str[l]='\0';
return 1;
}
return 0;
}



A despeito disso, seu programa tem outro problema: você manda imprimir buffer antes de colocar nele qualquer valor. Isso pode ter resultados imprevisíveis sobre a saída.


... Então Jesus afirmou de novo: “(...) eu vim para que tenham vida, e a tenham plenamente.” (João 10:7-10)


4. Re: leitura em c [RESOLVIDO]

Perfil removido
removido

(usa Nenhuma)

Enviado em 17/04/2020 - 14:30h

paulo1205 escreveu:

A função fgets() não remove o caráter de fim de linha que corresponde à tecla Enter.

Muita gente não gosta dessa característica da função, mas eu penso que ela é útil para ajudar o programador a diagnosticar se ele realmente recebeu uma linha inteira ou se houve truncamento dos dados. Sem essa marca, a detecção de truncamento seria muito mais difícil.

O que normalmente se faz é extirpar manualmente a marca de fim de linha.
size_t l=strlen(str);
if(l-- > 0 && str[l]=='\n')
str[l]='\0';


Você pode inclusive transformar isso numa função, que poderá então ser chamada após cada chamada que você fizer a fgets().
// Função de remoção de '\n' do fim de uma string.  Retorna 1 se remoção ocorrer; 0 se não ocorrer.
int chomp(char *str){
size_t l=strlen(str);
if(l-- > 0 && str[l]=='\n'){
str[l]='\0';
return 1;
}
return 0;
}



A despeito disso, seu programa tem outro problema: você manda imprimir buffer antes de colocar nele qualquer valor. Isso pode ter resultados imprevisíveis sobre a saída.


... Então Jesus afirmou de novo: “(...) eu vim para que tenham vida, e a tenham plenamente.” (João 10:7-10)


amigo, sou novo em programação, tem como dar uma resposta mais simples?


5. Re: leitura em c

Paulo
paulo1205

(usa Ubuntu)

Enviado em 17/04/2020 - 14:42h

0100 escreveu:

amigo, sou novo em programação, tem como dar uma resposta mais simples?


Prezado,

Poderia dizer o que não ficou claro para você?

Pode ser até dificuldade de me colocar no seu lugar, mas, para mim, a resposta já está bastante “mastigada”: ela tem a explicação da causa do problema, código que você pode simplesmente copiar e colar para o seu programa (trocando apenas o nome da variável contendo a string), sugestão de melhoria, e o apontamento de outro bug no programa, diferente daquele da pergunta original.


... Então Jesus afirmou de novo: “(...) eu vim para que tenham vida, e a tenham plenamente.” (João 10:7-10)


6. Linguagem C

João Bosco de F. N.
boscofreitas

(usa Ubuntu)

Enviado em 17/04/2020 - 15:52h

Favor dizer qual o problema que está tentando resolver ou proposto.


7. Linguagem C

8. Re: leitura em c [RESOLVIDO]

Adriano Siqueira
adrisiq

(usa KDE Neon)

Enviado em 18/04/2020 - 10:19h

Segue um exemplo mínimo:
#include <stdio.h>
#include <stdlib.h>

int main() {
FILE *file = fopen("", "r");
char buffer[1000] = "";

if (file == NULL) {
printf("[ E ]: Arquivo nao pode ser aberto. \n");
return EXIT_FAILURE;
}

while (fgets(buffer, sizeof(buffer), file) != NULL) {
printf("%s", buffer);
}

fclose(file);
return EXIT_SUCCESS;
}



9. Re: leitura em c

Paulo
paulo1205

(usa Ubuntu)

Enviado em 18/04/2020 - 14:26h

adrisiq escreveu:

Segue um exemplo mínimo:
#include <stdio.h>
#include <stdlib.h>

int main() {


Para atender ao padrão do C (§5.1.2.2 do padrão do C de 2018), para um ambiente de execução hospedado, que é o caso dos nossos PCs com sistemas operacionais tais como UNIX, Linux, Windows, macOS ou mesmo MS-DOS e outras coisas mais antigas, a declaração da função main() tem de ser feita de uma de duas maneiras (§5.1.2.2.1):

  • se você não quiser receber parâmetros do sistema operacional
int main(void) 

  • se você quiser receber parâmetros do sistema operacional
int main(int argc, char **argv) 

(os nomes argc e argv podem ser trocados por outros, mas eles representam, respectivamente, a quantidade de argumentos passados ao programa, e um array de strings compostas por cada um dos argumentos).

    FILE *file = fopen("", "r"); 


A string vazia como nome do arquivo não deve funcionar na maioria dos sistema operacionais. Foi isso realmente que você quis dizer?

    char buffer[1000] = ""; 


Posso estar enganado na escolha, mas eu tenho ficado cada dia mais propenso a usar, para objetos grandes tais como arrays, ou alocação estática (principalmente numa função não-reentrante, como é o caso de main()) ou alocação dinâmica (especialmente em C++, através de std::string ou std::vector), em lugar de alocação automática. Penso que isso é útil porque há cenários em que a pilha é um recurso escasso, quer em termos absolutos, tais como sistemas embarcados, e microcomputadores antigos de 16 ou mesmo 8 bits, quer em termos relativos, como na programação com múltiplos threads.

Ter a cultura de não sair sempre colocando tudo na pilha, mesmo quando seria possível, acaba sendo positivo para educar para o dia em que é necessário colocar em outros lugares.

No caso deste programa, eis como eu sugiro fazer.
    static char buffer[1000];  // Nem mesmo é necessário inicializar explicitamente, pois dados estáticos são automaticamente preenchidos com nulos. 



if (file == NULL) {
printf("[ E ]: Arquivo nao pode ser aberto. \n");
return EXIT_FAILURE;
}

while (fgets(buffer, sizeof(buffer), file) != NULL) {
printf("%s", buffer);
}

fclose(file);
return EXIT_SUCCESS;
}



... Então Jesus afirmou de novo: “(...) eu vim para que tenham vida, e a tenham plenamente.” (João 10:7-10)


10. Re: leitura em c [RESOLVIDO]

Perfil removido
removido

(usa Nenhuma)

Enviado em 18/04/2020 - 14:58h

paulo1205 escreveu:

adrisiq escreveu:

Segue um exemplo mínimo:
#include <stdio.h>
#include <stdlib.h>

int main() {


Para atender ao padrão do C (§5.1.2.2 do padrão do C de 2018), para um ambiente de execução hospedado, que é o caso dos nossos PCs com sistemas operacionais tais como UNIX, Linux, Windows, macOS ou mesmo MS-DOS e outras coisas mais antigas, a declaração da função main() tem de ser feita de uma de duas maneiras (§5.1.2.2.1):

  • se você não quiser receber parâmetros do sistema operacional
int main(void) 

  • se você quiser receber parâmetros do sistema operacional
int main(int argc, char **argv) 

(os nomes argc e argv podem ser trocados por outros, mas eles representam, respectivamente, a quantidade de argumentos passados ao programa, e um array de strings compostas por cada um dos argumentos).

    FILE *file = fopen("", "r"); 


A string vazia como nome do arquivo não deve funcionar na maioria dos sistema operacionais. Foi isso realmente que você quis dizer?

    char buffer[1000] = ""; 


Posso estar enganado na escolha, mas eu tenho ficado cada dia mais propenso a usar, para objetos grandes tais como arrays, ou alocação estática (principalmente numa função não-reentrante, como é o caso de main()) ou alocação dinâmica (especialmente em C++, através de std::string ou std::vector), em lugar de alocação automática. Penso que isso é útil porque há cenários em que a pilha é um recurso escasso, quer em termos absolutos, tais como sistemas embarcados, e microcomputadores antigos de 16 ou mesmo 8 bits, quer em termos relativos, como na programação com múltiplos threads.

Ter a cultura de não sair sempre colocando tudo na pilha, mesmo quando seria possível, acaba sendo positivo para educar para o dia em que é necessário colocar em outros lugares.

No caso deste programa, eis como eu sugiro fazer.
    static char buffer[1000];  // Nem mesmo é necessário inicializar explicitamente, pois dados estáticos são automaticamente preenchidos com nulos. 



if (file == NULL) {
printf("[ E ]: Arquivo nao pode ser aberto. \n");
return EXIT_FAILURE;
}

while (fgets(buffer, sizeof(buffer), file) != NULL) {
printf("%s", buffer);
}

fclose(file);
return EXIT_SUCCESS;
}



... Então Jesus afirmou de novo: “(...) eu vim para que tenham vida, e a tenham plenamente.” (João 10:7-10)


Foi bastante esclarecedor!
Obrigado pela explicação explicação =D
O problema estava no caminho do arquivo
Resolvi usando

scanf(%[^\n]s);

Eu não conhecia static, obrigado por avisar sobre ele!


11. Re: leitura em c [RESOLVIDO]

Adriano Siqueira
adrisiq

(usa KDE Neon)

Enviado em 18/04/2020 - 17:24h

A string vazia como nome do arquivo não deve funcionar na maioria dos sistema operacionais. Foi isso realmente que você quis dizer?

Deixei vazia para o autor preencher com o nome do arquivo que ele queira trabalhar.


12. Re: leitura em c [RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 20/04/2020 - 17:28h

0100 escreveu:

Obrigado pela explicação explicação =D
O problema estava no caminho do arquivo
Resolvi usando

scanf(%[^\n]s);

Eu não conhecia static, obrigado por avisar sobre ele!


Entendo que você quis dizer "scanf("%[^\n]s", dir)".

Mas mesmo isso está incorreto. Muita gente pensa que a especificação dentro de colchetes de caracteres a aceitar ou a rejeitar (no seu caso é a rejeitar) é um modificador do comportamento padrão da conversão %s de scanf(). Só que não é assim que funciona. Na verdade, %[ é uma conversão de seu próprio direito, e essa recebe um argumento pós-fixado, que é um conjunto de um ou mais caracteres a incluir ou a excluir da lista de possíveis caracteres que vão entrar na composição da string lida, e essa lista não-vazia de caracteres termina quando se encontra o caráter ].

O certo, portanto, seria somente o seguinte.
scanf("%[^\n]", dir) 



... Então Jesus afirmou de novo: “(...) eu vim para que tenham vida, e a tenham plenamente.” (João 10:7-10)






Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts