使用C动态字符串

时间:2017-04-11 08:17:45

标签: c parsing memory-management c-strings

以下是需要解析的文件的一部分

record(ai, "SRC01-VA-IMG1:getPressure")
{
    field(DESC, "Reads Cell  SR-GC1 Pressure")
    field(SCAN, "1 second")
    field(DTYP, "stream")
    field(INP, "@vacuum-XGS600-gc.proto getPressure(1) SR-GC1")
    field(PINI, "YES")
    field(VAL, "0")
    field(PREC, "3")
    field(LOLO, "")     field(LLSV, "NO_ALARM")
    field(HIGH, "")     field(HSV,  "NO_ALARM")
    field(HIHI, "")     field(HHSV, "NO_ALARM")
}

解析过程将读取记录名称(在qoutes中)并键入(ai,在行记录中),以及每个字段类型和值(在以字段开头的任何行中。例如类型:PINI,值:“是”)。请注意,每行可以包含多个记录定义。该示例包含一些有趣的案例,例如同一行中的多个字段,qoutes内的括号等。

这是我的代码:

struct field
{
    char* name;
    char* value;
};

struct record
{
    char* name;
    char* type;
    struct field* fields;
};

struct record* get_records(char* file, int* length)
{
    size_t SIZE = 0;
    size_t fSIZE = 1;
    const int N = 100;
    struct record* records = malloc(1 * sizeof(struct record));
    struct field* fields;
    // char line[N];
    char* line = malloc(N);
    char record_name[100];
    char record_type[10];
    char field_name[10];
    char field_value[100];
    char temp[100];

    int open, close, comma, q1, q2;
    FILE* fp = fopen(file, "r");
    if(fp != NULL)
    {
        while(fgets(line, N, fp))
        {
            line = strtrim(line);
            if(strncmp(line, "record", 6) == 0)
            {
                memset(record_name, 0, sizeof(record_name));
                memset(record_type, 0, sizeof(record_type));

                struct record* r = malloc(sizeof(struct record));
                open = strchr(line, '(') - line + 1;
                close = strchr(line, ')') - line + 1;
                comma = strchr(line, ',') - line + 1;
                q1 = strchr(line, '"') - line + 1;
                q2 = strrchr(line, '"') - line + 1;

                strncpy(record_type, &line[open], comma  - open - 1);
                strncpy(record_name, &line[q1], q2 - q1 - 1);
                record_name[q2 - q1 - 1] = '\0';
                record_type[comma  - open - 1] = '\0';
                r->name = record_name;
                r->type = record_type;

                printf("Name: %s\n", r->name);
                printf("Type: %s\n", r->type);

                fSIZE = 0;
                fields = malloc(100 * sizeof(field)); // HERE
                while(fgets(line, N, fp))
                {
                    struct field* f = malloc(sizeof(struct field));
                    if(strncmp(line, "}", 1) == 0)
                        break;

                    if(strncmp(line, "{", 1) == 0)
                        continue;

                    line = strtrim(line);
                    int i1 = 0;
                    int i2 = 0;
                    char* p1 = strstr(line, "field");
                    char* p2;
                    while(p1 != NULL)
                    {
                        i1 = p1 - line;
                        p2 = strstr(p1 + 1, "field");
                        if(p2 != NULL)
                        {
                            i2 = p2 - line;
                            p1 = strstr(p1 + 1, "field");
                        }
                        else
                        {
                            i2 = strlen(line);
                            p1 = NULL;
                        }

                        memset(temp, 0, sizeof(temp));
                        memset(field_name,  0, sizeof(field_name));
                        memset(field_value, 0, sizeof(field_value));

                        strncpy(temp, &line[i1], i2 - i1); temp[i2-i1] = '\0';
                        printf("Line2 : %s\n", temp);

                        open = strchr(temp, '(') - temp + 1;
                        close = strrchr(temp, ')') - temp + 1;
                        comma = strchr(temp, ',') - temp + 1;
                        q1 = strchr(temp, '\"') - temp + 1;
                        q2 = strrchr(temp, '\"') - temp + 1;

                        strncpy(field_value, &temp[q1], q2 - q1 - 1);         field_value[q2-q1-1] = '\0';
                        strncpy(field_name,  &temp[open], comma  - open - 1); field_name[comma-open-1] = '\0';

                        printf("Name : %s\n", field_name);
                        printf("Value: %s\n\n", field_value);

                        f->name = field_name;
                        f->value = field_value;

                        fields[fSIZE++] = *f;
                    }
                    free(line);
                    line = malloc(N);
                }
                r->fields = fields;
                records[SIZE++] = *r;
            }
            else
                continue;
        }
    }
    else
    {
        printf("%s\n", "Unable to open file.");
        exit(1);
    }

    *length = SIZE;
    // fclose(fp);
    return records;
}

int main()
{
    int length = 0;
    struct record* records = get_records("./test.db", &length);

    // printf("Anything \n");
    int i = 0;
    for(i = 0; i < length; i++)
    {
        struct record* r = (struct record*) &records[i];
        printf("Name: %s\n", r->name);
        printf("Type: %s\n", r->type);
    }
    return 0;
}

现在我对这个实现有两个问题,我无法弄清楚:

  1. main函数中有printf语句,如果取消注释,循环内的printf将打印垃圾,否则输出正确。
  2. 取消注释函数fclose中的get_records会产生Segmentation fault (core dumped)。通过反复试验,我发现我要么使用它,要么使用评论malloc指定的HERE行,出于某种原因使用其中一个或非故障消失。我知道我在某处使用内存分配有问题,我使用valgrind但它没有帮助我找到任何东西
  3. 注意:

    1. malloc中使用的常数用于测试目的。我们有包含100条记录的文件。这导致了一个未来的问题,更好地使用足够大的malloc缓冲区或使用realloc
    2. 欢迎使用C中的任何其他实现(如果有):)

1 个答案:

答案 0 :(得分:0)

由于对mallocfree的多次调用,这个实现似乎大量搞砸了内存。我所做的是用数组替换结构中的char*,将line定义转换为char[],并在strtrim调用中取消引用它。