如何在C编程中推广SSCANF和#DEFINE

时间:2009-08-27 06:46:27

标签: c generics parsing

下面的代码试图解析包含这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。

我是否可以为此目的概括definesscanf? 这是完整的代码:

#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 个答案:

答案 0 :(得分:2)

如果一行中的元素数量不固定(也可能是行数),您可以执行以下操作之一:

  1. 使用数组数组 - int line_elements[MAX_LINES][MAX_LINE_LENGTH] - 但这仍然只有静态大小
  2. 使用指针数组 - int* lines[],然后在迭代线条时动态分配所需的空间。
  3. 您无法使用预定义数量为sscanf的{​​{1}}。尝试使用strtok将字符串标记为标记,因为您将数字用空格分隔。

答案 1 :(得分:1)

好吧,这似乎做了你要求的,但它不使用泛型(如果我没有弄错的话是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;
    }

顺便说一下,请评论一下这项工作是否适合你。

答案 2 :(得分:0)

我建议使用stl容器类向量&lt;&gt;或为此目的动态分配的数组。

答案 3 :(得分:0)

这看起来与this question的问题相同。由于字段数是可变的,因此sscanf无法完成工作。它需要固定数量的字段。并且#defines绝对不能在运行时参数化。 strtok()绝对是要走的路。有关更多详细信息和问题,请参阅其他问题的答案。