Use a variable to limit reading of characters with fscanf and data mask

Asked

Viewed 104 times

0

I’ve created a structure that holds three records of any kind. These records I read from an f file. They have a set size, in the case below the first dice has three characters, the second 17 and the third three. I used it because the data may come anyway, but the default is guaranteed. Example inside the f file:

999 Eduardo Oliveira SI

111EduardoOliveira SI (Two spaces before SI, could not put here)

for (i = 0; i < qtde_registros; i++)
{
    fscanf(f,"%3s",rt[i].m);
    rt[i].m[3]='\0';
    fscanf(f,"%17c",rt[i].n);
    rt[i].n[17]='\0';
    fscanf(f,"%3c",rt[i].c);
    rt[i].c[3]='\0';
}

It is working perfectly, the problem is that I do not want to leave this fixed size, I want to get the size of each of the three data with the user or by another file. How can I replace these number "3,17,3" with variables. Example of what I want:

int tamPrimeiroDado=3;
int tamSegundoDado=17;
int tamTerceiroDado=3;

for (i = 0; i < qtde_registros; i++)
{
    fscanf(f,"% >>AQUI(tamPrimeiroDado)<< s",rt[i].m);
    rt[i].m[tamPrimeiroDado]='\0';
    fscanf(f,"% >>AQUI(tamSegundoDado)<< c",rt[i].n);
    rt[i].n[tamSegundoDado]='\0';
    fscanf(f,"% >>AQUI(tamTerceiroDado)<< c",rt[i].c);
    rt[i].c[tamTerceiroDado]='\0';
}

With one or more 'for', 'fseek', 'fgetc' ... I get what I want, but is there any way to do this with C data masks? Thank you.

1 answer

0


Scanf, sscanf and fscanf do not directly support variable field size specification.

It is possible however to use tricks as shown here.

The best solution however is to use fgets and calloc, and separate the fields manually.
These functions (scanf, fscanf, sscanf) are very fragile, in practice are not used "in real life".

#include <stdio.h>  // fgets, printf
#include <stdlib.h> // calloc
#include <string.h> // memcpy

int main()
{
  // definicao dos tamanhos dos campos
  int tamCpo1 = 3;
  int tamCpo2 = 17;
  int tamCpo3 = 3;

  // definicao do tamanho do registro
  int tamRegistro = tamCpo1 + tamCpo2 + tamCpo3;

  // aloca memoria para os campos individuais
  // soma 1 para zero binario no final
  char* cpo1 = calloc(tamCpo1+1, 1);
  char* cpo2 = calloc(tamCpo2+1, 1);
  char* cpo3 = calloc(tamCpo3+1, 1);

  // aloca memoria para o registro
  // soma 2 para reservar espaco para \n\0
  char* registro = calloc(tamRegistro+2, 1);

  // para computar tamanho do registro lido
  int tamRegLido;

  // arquivo a ser lido
  FILE* arq;

  // abre arquivo arq
  arq = fopen("teste.txt", "r");
  if (!arq)
  {
    printf("*\n");
    printf("* arquivo 'teste.txt' inexistente\n");
    printf("*\n");
    exit(1);
  }

  printf("*\n");

  // loop de leitura dos registros
  for (;;)
  {
    // tenta ler um registro
    if (!fgets(registro, tamRegistro+2, arq))
    {
      printf("*\n");
      if (feof(arq))
        printf("* fim de arquivo\n");
      else
        printf("* erro na leitura\n");
      break; // sai do while
    }

    // ok, leu um registro

    // computa o tamanho do registro lido
    tamRegLido = strlen(registro);

    if (tamRegLido < tamRegistro + 1)
    {
      printf("* ignorando registro com tamanho menor\n");
      continue; // volta para inicio do while
    }

    if (registro[tamRegistro] != '\n')
    {
      printf("* ignorando registro com tamanho maior\n");
      continue; // volta para inicio do while
    }

    // registro lido com tamanho correto

    // separa os campos
    memcpy(cpo1, registro, tamCpo1);
    memcpy(cpo2, registro+tamCpo1, tamCpo2);
    memcpy(cpo3, registro+tamCpo1+tamCpo2, tamCpo3);

    // mostra os campos1 lidos
    printf("* campo 1: [%s]\n", cpo1);
    printf("* campo 2: [%s]\n", cpo2);
    printf("* campo 3: [%s]\n", cpo3);
    printf("*\n");
  }

  printf("*\n");
  printf("* fim\n");
  printf("*\n");
}

Browser other questions tagged

You are not signed in. Login or sign up in order to post.