COMO FAZER Generalizar sscanf e #DEFINE em programação C

votos
0

O código abaixo tenta analisar um ficheiro que contém estas linhas 3:

 0 2 5 9 10 12
 0 1 0 2 4 1 2 3 4 2 1 4
 2 3 3 -1 4 4 -3 1 2 2 6 1

e armazena-os nessas matrizes:

int Line1[] = { 0, 2, 5, 9, 10, 12 };

int Line2[] =    { 0, 1, 0,  2, 4, 1,  2, 3, 4, 2, 1, 4 };

double Line3[] = { 2, 3, 3, -1, 4, 4, -3, 1, 2, 2, 6, 1 };

No entanto, na prática, o número de campos no arquivo de entrada real são não fixas . Portanto, eles podem ser maior do que 6, 12 e 12 para cada linha.

Existe alguma maneira eu posso generalizar a definee sscanfpara este fim? Aqui está o código completo:

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

// This is hard coded
#define LINE1_COUNT 6
#define LINE2_COUNT 12
#define LINE3_COUNT 12 

int main() {
    int Line1[LINE1_COUNT], Line2[LINE2_COUNT] ;
    float Line3[LINE1_COUNT] ;
    int j, check;

    FILE *file = fopen(test.dat,r);

    if (file) {
        char line[BUFSIZ];

        if (fgets(line, BUFSIZ, file)) { // read line 1, integers
            int *i = Line1;//for easier reading
            check = sscanf(line, %i%i%i%i%i%i, &i[0],&i[1],&i[2],&i[3],&i[4],&i[5]) ;
            if (check != LINE1_COUNT){
                fprintf(stderr, Failed to read expected %d values from line 1\n, LINE1_COUNT);
                exit(1);
            }
        }else fprintf(stderr, Couldn't read line 1!\n);
        if (fgets(line, BUFSIZ, file)) { // read line 2, integers
            int *i = Line2;//for easier reading
            check = sscanf(line, %i%i%i%i%i%i%i%i%i%i%i%i, 
                &i[0],&i[1],&i[2],&i[3],&i[4],&i[5],&i[6],&i[7],&i[8],&i[9],&i[10],&i[11]) ;
            if (check != LINE2_COUNT){
                fprintf(stderr, Failed to read expected %d values from line 2\n, LINE2_COUNT);
                exit(1);
            }
        }else fprintf(stderr, Couldn't read line 2!\n);
        if (fgets(line, BUFSIZ, file)) { // read line 3, floats
            float *f = Line3;//for easier reading
            check = sscanf(line, %f%f%f%f%f%f%f%f%f%f%f%f, 
                &f[0],&f[1],&f[2],&f[3],&f[4],&f[5],&f[6],&f[7],&f[8],&f[9],&f[10],&f[11]) ;
            if (check != LINE3_COUNT){
                fprintf(stderr, Failed to read expected %d values from line 3\n, LINE3_COUNT);
                exit(1);
            }
        }else fprintf(stderr, Couldn't read line 3!\n);
        fclose(file);
    }else {
         perror(test.dat);
    }

    for (j=0;j<LINE1_COUNT;j++){
        printf(%i\t,Line1[j]);
    }
    printf(\n);
    for (j=0;j<LINE2_COUNT;j++){
        printf(%i\t,Line2[j]);
    }
    printf(\n);
    for (j=0;j<LINE3_COUNT;j++){
        printf(%f\t,Line3[j]);
    }
    printf(\n);

    printf(Press return to exit);
    getchar();
    return 0;
}
Publicado 27/08/2009 em 07:46
fonte usuário
Em outras línguas...                            


4 respostas

votos
2

Se o número de elementos em uma linha não é fixo (e talvez o número de linhas bem) você pode fazer uma das seguintes coisas:

  1. Use uma matriz de matrizes - int line_elements[MAX_LINES][MAX_LINE_LENGTH]- mas isso ainda tem apenas um tamanho estático
  2. Use uma matriz de ponteiros - int* lines[]e, em seguida, alocar dinamicamente o espaço necessário quando você iterar linhas de vale.

Você não pode usar um sscanfcom o número pré-definido de %sdentro. Tente usar strtok para tokenizing a string em tokens desde que você separar os números por um espaço.

Respondeu 27/08/2009 em 08:00
fonte usuário

votos
1

Bem, isso parece estar a fazer o que você está pedindo, mas esquentar uso de genéricos (recurso de um c ++ se im não sejam confundidos) ou #define generalizada (que eu acho que é impossível). Além disso, eu não tenho certeza sobre a eficiência:

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

//dont (cant) hard-code sizes (see main())

int* parse_int_line(char* line, int* sz)
    {
    int* line_data;
    int* tmp;
    line_data = malloc(sizeof(int) * ((*sz)=1));
    if(!line_data){return 0;}
    while(1==sscanf(line,"%i",&(line_data[(*sz)-1])))
        {
        while(*(line++)==' '){ /*pass*/ }//chew through leading spaces
        while(*(line++)!=' '){*line=' ';}//and the number we just got
        tmp = realloc(line_data,sizeof(int) * (++(*sz)));
        if(tmp){line_data = tmp;}
        else{fprintf(stderr,"nonfatal memory allocation error\n");break;}
        }
    (*sz)--;
    return line_data;
    }
void print_int_line(int* line, int sz)
    {
    int i;
    for(i=0;i<sz;i++)
        {
        printf(" %i",line[i]);
        }
    printf("\n");
    }
float* parse_float_line(char* line, int* sz)
    {
    float* line_data;
    float* tmp;
    line_data = malloc(sizeof(float) * ((*sz)=1));
    if(!line_data){return 0;}
    while(1==sscanf(line,"%f",&(line_data[(*sz)-1])))
        {
        while(*(line++)==' '){ /*pass*/ }//chew through leading spaces
        while(*(line++)!=' '){*line=' ';}//and the number we just got
        tmp = realloc(line_data,sizeof(float) * (++(*sz)));
        if(tmp){line_data = tmp;}
        else{fprintf(stderr,"nonfatal memory allocation error\n");break;}
        }
    (*sz)--;
    return line_data;
    }
void print_float_line(float* line, int sz)
    {
    int i;
    for(i=0;i<sz;i++)
        {
        printf(" %.2f",line[i]);
        }
    printf("\n");
    }

int main(int argc, char** argv)
    {
    int sz1=0,sz2=0,sz3=0;
    int* line1 = 0;
    int* line2 = 0;
    float* line3 = 0;
    FILE* file = 0;

    file = fopen("C:/DevCpp/Projects/junk/test.txt","r");

    if(file)
        {
        char line[BUFSIZ];
        if(fgets(line,BUFSIZ,file))
            {
            line1 = parse_int_line(line,&sz1);
            print_int_line(line1,sz1);
            }
        else{fprintf(stderr,"line read error\n");}
        if(fgets(line,BUFSIZ,file))
            {
            line2 = parse_int_line(line,&sz2);
            print_int_line(line2,sz2);
            }
        else{fprintf(stderr,"line read error\n");}
        if(fgets(line,BUFSIZ,file))
            {
            line3 = parse_float_line(line,&sz3);
            print_float_line(line3,sz3);
            }
        else{fprintf(stderr,"line read error\n");}
        }
    else
        {
        fprintf(stderr,"could not open \"test.txt\"\n");
        }
    if(line1){free(line1);}
    if(line2){free(line2);}
    if(line3){free(line3);}
    printf("Press return to exit");
    getchar();
    return 0;
    }

By the way, por favor, comentar sobre se / como isso funciona bem para você.

Respondeu 27/08/2009 em 10:11
fonte usuário

votos
0

Isto parece o mesmo problema que esta pergunta . Como o número de campos é variável, sscanf só não vai fazer o trabalho. Ele precisa de um número fixo de campos. E # define mais definitivamente não pode ser parametrizado em tempo de execução. strtok () é definitivamente o caminho a percorrer. Consultar as respostas da outra pergunta para mais detalhes e Armadilhas.

Respondeu 27/08/2009 em 08:05
fonte usuário

votos
0

Eu recomendo usando STL vector classe contêiner <> ou matrizes alocadas dinamicamente para esta finalidade.

Respondeu 27/08/2009 em 07:59
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more