Jump to content

Dúvida em C -- leitura de números no meio de strings


FrostPt

Recommended Posts

Boas, este é o meu primeiro post aqui no forum 😄 espero não fazer má figura :O Especialmente porque ainda sou um bocado nabo a programar em C.

Vá, agora coisas sérias, tenho um pequeno problema num código que escrevi. Basicamente só preciso que leia de uma string se tem números ou não. O problema é que estou a trabalhar com ficheiros o que me anda a baralhar um bocado. Enfim é melhor meter o código, para perceberem o que quero dizer.

#include <stdio.h>
#include <stdlib.h>
#define MAX_Linha 200

int main()
{
 FILE *texto; 
 FILE *texto_dig; 
 int n, i, m; 
 char string [MAX_Linha];

 /* 1. abra arquivo texto.txt para leitura */
 texto = fopen("texto.txt","r");
 if (texto == NULL)
   {
     printf("Erro na abertura do arquivo texto.txt.\n");
     exit(-1); 
   }

 /* 2. abra arquivo texto_dig para escrita */
 texto_dig = fopen("texto_digito.txt","w");
 if (texto_dig == NULL)
   {
     printf("Erro na abertura do arquivo texto_digitado.txt.\n");
     exit(-1); 
   }

fscanf(texto,"%d", &m);

 for (i = 0; i<m; i++)
    {
      if (fgets (string , MAX_Linha , texto) != NULL)
        {
          fscanf(texto,"%d", &n);
          if (n != 0)
            {
              fprintf(texto_dig,"%s", string);
            }
        }
    }

 /* 6. feche o arquivo texto.txt */
 fclose(texto);

 /* 7. feche o arquivo texto_dig */
 fclose(texto_dig);
 return 0;
}

Pensei meter na linha 34, em vez de 'texto', mudar para 'string' mas parece piorar :/

Erros/Avisos: Não dá nenhum

Problemas/Inconvenientes: Não lê números nas strings do ficheiro de texto

Enunciado: Desenvolva um programa que leia um ficheiro de texto (texto.txt) e

imprima num outro ficheiro (texto_digito.txt) todas as linhas que tiverem pelo

menos um dígito, imprimindo no final no ecrã o total de linhas nessas

condições. Se o ficheiro inicial não existir, deverá imprimir zero. As linhas não

têm mais de 200 caracteres cada.

(O código ainda não está completo)

Obrigado, desde já a quem possa ajudar. Deêm-me um desconto se o erro for obvio ainda dou bastante inexperiente 😞

Edited by pmg
pastebin nao á necessário
Link to comment
Share on other sites

O teu problema é com o scanf(). Essa não é a função indicada para fazer o que pretendes.

<parentesis>

A função scanf (ou outras da mesma familia) pára quando o input não "servir" para o formato pedido. No teu caso, ao pedires um inteiro com "%d", mal o scanf veja uma letra pára. Se não encontrou nenhum número devolve 0 e deixa a variável num estado desconhecido.

Por exemplo, se o input fosse "foo42" quando o scanf visse o 'f' parava e já não via o 'o', nem o "42".

</parentesis>

Tens de usar outra maneira de verificar se o input tem digitos.

Sugestão: faz um ciclo para passar por todos os elementos do input e verifica se são dígitos ('0', '1', ..., '9').

--------

Sugestão #2: não uses o identificador string para as tuas variaveis. Tem dois inconvenientes:

1. É um identificador reservado, como todos os que começam por "str" e têm uma letra minuscula a seguir

2. É incompatível com C++ e com muitos "syntax highlighters" (incluindo o do P@P)

Edited by pmg
incompatibilidade com syntax highlighters

What have you tried?

Não respondo a dúvidas por PM

A minha bola de cristal está para compor; deve ficar pronta para a semana.

Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!

Link to comment
Share on other sites

lendo o enunciado à risca tem um problema ainda maior.

nele (o enunciado) nada indica que a primeira linha é o número de linhas do ficheiro.

para resolver o teu problema, digo-te já que o código final tem menos linhas das que apresentaste aqui.

e como apresentaste uma tentativa de tentativa com pés e cabeça, onde se vê claramente que o problema é o desconhecimento dos pormenores do das funções do libc, vou te apresentar a minha solução:

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

#define BUFFER_SIZE 256

int main() {
 FILE * input = NULL, * output = NULL; // ponteiros para os streams a usar
 char buffer[bUFFER_SIZE]; // buffer de leitura da linha do dficheiro ( > 200)
 int count = 0, i = 0; // contador e iterador de posição da linha

 /* abrir os ficheiros */
 if ((input = fopen("texto.txt","r")) == NULL || (output = fopen("texto_digitos.txt","r")) == NULL) {
   perror("fopen");
   exit(1);
 }

 /* ciclo de leitura do ficheiro de entrada */
 while (fgets(buffer, BUFFER_SIZE, input)) {
   /* ciclo que verifica todos as caracteres da linha */
   for (i = 0; i < (int)strrchr(buffer, '\n') - (int)buffer; i++) {
     /* verifica se o caracter é um digito */
     if (buffer[i] >= '0' || buffer[i] <= '9') {
       /* inprimir a linha no ficheiro de saida, incrementar o contador e
        * sair do ciclo de verificação da linha */
       fprintf(output, "%s", buffer);
       count++;
       break;
     }
   }
   /* limpar a linha do buffer para não haver problemas com a chamada
    * da função strrchr (nunca se sabe  ) */
   memset(buffer, 0, BUFFER_SIZE);
 }
 /* fechar os streams */
 fclose(input);
 fclose(output);
 /* apresentar o numero de linhas copiadas */
 printf("%d\n", count);

 return 0;
}

PS : isto foi tudo feito de cabeça, pode existir algum bugzito, mas sempre dá para tirares ideias

Edited by HappyHippyHippo
IRC : sim, é algo que ainda existe >> #p@p
Link to comment
Share on other sites

Então pelo que percebi tudo o que esteja relacionado com scanf está fora de questão? Porque vai sempre parar, caso o input não seja um inteiro.

Não percebi muito bem, o porquê de 'string' ser um identificador reservado, mas de qualquer das maneiras vou evitar usar, dessa forma.

Quanto à primeira sugestão, já vi que a 'HappyHippyHippo' fez usando 'strrchr'. Admito que não sabia o que isso fazia :/ Pelo que deu a entender, nos sites que consultei, procura no buffer onde está o "\n", que corresponde ao final da string? Não percebi o que veio a seguir. Isto aqui

- (int)buffer
Nem porque é que o tamanho do buffer está a 256:S

O resto também está bastante explícito, só não percebi o uso do memset :/ Acho que foi para iniciar a zero, para quando o 'strrchr' chamasse uma nova string do ficheiro texto.txt? Se fosse esse o caso, quando se chamasse, não substituia pelo que estava antes?

Obrigado, por explicarem os meus erros, já estava a stressar todo porque não lia os números do ficheiro (ainda não lê, mas já estou mais perto de conseguir meter a funcionar ^^) Ah e pelas sugestões, vão ser úteis no futuro 😛

Edited by FrostPt
Link to comment
Share on other sites

ok ... vamo slá por partes então

- o que o @pmg disse sobre a palavra reservada "string" é relevante ao C++. na realidade não é uma palavra reservada mas sim um identificador pré-definido da STL.

o que acontece quando tentares utiliza código C++ é que ao definires que estás a usar a biblioteca STL:

#include <string>
using namespace std;

a palavra "string" já se encontra definida o que irá causar colisão de definições.

- a função strrchr retorna o ponteiro para a última ocorrência do caracter X na string dada.

- é normal não teres percebido bem o

(int)strrchr(buffer, '\n') - (int)buffer

isto porque estás a começar , mas vou tentar explicar. buffer e strrchr são ponteiros/arrays, logo o seu valor é um número que representa a posição de memória onde se encontra os dados. como os dados do array são caracteres o seu tamanho/espaço de memória é 1 byte, logo a diferença das duas posições dá diretamente o número de caracteres/bytes entre a primeira posição (buffer) e a posição da última ocorrência do caracter '\n' (strrchr).

claro que podias usar strlen(buffer) que daria o mesmo resultado, mas foi um desvaneio meu para tentar ver se percebias o que estava escrito.

- o uso do memset é para "limpar" o buffer e fazer com que todos os caracteres deste tomem o valor de '\0' (que é o valor de termino da string). É certo que a especificação do fgets dita que o caracter '\0' é adicionado no fim da leitura, mas já diz o ditado : "fiar nem na virgem maria". Agora porque forçar a existência do '\0'. Imagina que a segunda string lida é menor que a primeira. Se o fgets não colocar o caracter '\0' no final estás gravar a segunda string no início da primeira ficando com uma salgalhada tremenda.

IRC : sim, é algo que ainda existe >> #p@p
Link to comment
Share on other sites

Ok, já percebi melhor aquela parte relacionada com o identificador pré-definido 'string'. Isso significa que em C não causa problemas, mas se for em C++ já se chateia. Bem, vou evitar usá-la para esses fins, assim ninguém tem problemas xD

A parte do memset também já entendi, era mais ou menos o que tinha em mente, está relacionado um bocado com organização e estética do programa 😄

Agora, estou a tentar digerir a função 'strrchr' xD Hmmm isso significa que vai a posição de memória onde começa o array e a posição onde acaba? Sendo a diferença o tamanho total da string? Daí teres dito que o strlen ia dar ao mesmo?

Mas o strrchr não dá um char ou uma coisa do género, enquanto o strlen dá um inteiro?

Algo assim:

strrchr("Hello world!","world");

world!

a = 'abcdef';

strlen (a); /* Que dá 6 */

Não sei se me fiz entender :/

Edited by FrostPt
Link to comment
Share on other sites

Ok, já percebi melhor aquela parte relacionada com o identificador pré-definido 'string'. Isso significa que em C não causa problemas, mas se for em C++ já se chateia. Bem, vou evitar usá-la para esses fins, assim ninguém tem problemas xD

fazes bem

A parte do memset também já entendi, era mais ou menos o que tinha em mente, está relacionado um bocado com organização e estética do programa 😄

em programação a única coisa que tem haver com estética é a indentação, todo o resto é funcional ...

Agora, estou a tentar digerir a função 'strrchr' xD Hmmm isso significa que vai a posição de memória onde começa o array e a posição onde acaba?

Sendo a diferença o tamanho total da string? Daí teres dito que o strlen ia dar ao mesmo?

epa ... a tamanho é dado pela diferença entre as duas posições ... foi isso que escrevi ... já estás a inventar.

volta a ler o que escrevi mas com calma.

IRC : sim, é algo que ainda existe >> #p@p
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.