Как обобщить SSCANF и #DEFINE в программировании на C - PullRequest
0 голосов
/ 27 августа 2009

Приведенный ниже код пытается проанализировать файл, содержащий эти 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

и сохраняет их в следующих массивах:

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 };

Однако на практике число полей в реальном входном файле не фиксировано Следовательно, они могут быть больше 6, 12 и 12 для каждой строки.

Можно ли как-нибудь обобщить define и sscanf для этой цели? Вот полный код:

#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;
}

Ответы [ 4 ]

2 голосов
/ 27 августа 2009

Если количество элементов в строке не фиксировано (и, возможно, количество строк), вы можете сделать одно из следующих действий:

  1. Использовать массив массивов - int line_elements[MAX_LINES][MAX_LINE_LENGTH] - но он по-прежнему имеет только статический размер
  2. Используйте массив указателей - int* lines[], а затем динамически распределяйте необходимое пространство при итерации по впадинам.

Вы не можете использовать sscanf с заранее определенным номером %s внутри. Попробуйте использовать strtok для токенизации строки в токены, поскольку вы разделяете числа пробелом.

1 голос
/ 27 августа 2009

Что ж, похоже, это делает то, о чем вы просите, но в нем не используются обобщения (функция c ++, если я не ошибаюсь) или обобщенный #define (что, я думаю, невозможно). Кроме того, я не уверен в эффективности:

#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;
    }

Кстати, пожалуйста, прокомментируйте, если / насколько хорошо это работает для вас.

0 голосов
/ 27 августа 2009

Это похоже на ту же проблему, что и этот вопрос . Поскольку количество полей является переменным, sscanf просто не выполнит свою работу. Требуется фиксированное количество полей. И #defines определенно не может быть параметризован во время выполнения. strtok () - определенно путь. Обратитесь к ответам на другой вопрос для получения более подробной информации и ошибок.

0 голосов
/ 27 августа 2009

Я рекомендую использовать для этой цели либо вектор-класс контейнера stl <>, либо динамически размещаемые массивы.

...