代码之家  ›  专栏  ›  技术社区  ›  VHristov

关于内存分配和值分配的基本C问题

  •  2
  • VHristov  · 技术社区  · 16 年前

    我最近开始用C写硕士论文,我已经很久没用了。由于习惯了Java,我现在一直面临着各种各样的问题。我希望有人能帮我做下一件事,因为我已经挣扎了两天了。

    typedef struct attribute
    {
        int type;
        char * name;
        void * value;
    } attribute;
    
    typedef struct tuple
    {
        int tuple_id;
        int attribute_count;
        attribute * attributes;
    } tuple;
    
    typedef struct table
    {
        char * name;
        int row_count;
        tuple * tuples;
    } table;
    

    数据来自一个带有插入的文件(为威斯康辛州基准测试生成),我正在解析这个文件。我只有整数值或字符串值。示例行如下所示:

    insert into table values (9205, 541, 1, 1, 5, 5, 5, 5, 0, 1, 9205, 10, 11, 'HHHHHHH', 'HHHHHHH', 'HHHHHHH');
    

    我已经“设法”加载和解析数据,并分配它。但是,赋值位有问题,因为所有的值都指向相同的内存位置,也就是说,在我加载数据之后,所有的行看起来都一样。我是这样做的:

    char value[10]; // assuming no value is longer than 10 chars
    int i, j, k;
    
    table * data = (table*) malloc(sizeof(data));
    data->name = "table";
    data->row_count = number_of_lines;
    data->tuples = (tuple*) malloc(number_of_lines*sizeof(tuple));
    
    tuple* current_tuple;
    
    for(i=0; i<number_of_lines; i++)
    {
        current_tuple = &data->tuples[i];
        current_tuple->tuple_id = i;
        current_tuple->attribute_count = 16; // static in our system
        current_tuple->attributes = (attribute*) malloc(16*sizeof(attribute));
    
        for(k = 0; k < 16; k++)
        {
            current_tuple->attributes[k].name = attribute_names[k];
    
            // for int values:
            current_tuple->attributes[k].type = DB_ATT_TYPE_INT;
            // write data into value-field
            int v = atoi(value);
            current_tuple->attributes[k].value = &v;
    
            // for string values:
            current_tuple->attributes[k].type = DB_ATT_TYPE_STRING;
            current_tuple->attributes[k].value = value;
        }
    
        // ...
    }
    

     memcpy(current_tuple->attributes[k].value, &v, sizeof(int));
    

    这将导致错误的访问错误。以下代码也是如此(因为我不确定哪一个是正确的用法):

     memcpy(current_tuple->attributes[k].value, &v, 1);
    

    我都不知道我需要的是不是memcpy。。。

    我也尝试过分配内存,比如:

     current_tuple->attributes[k].value = (int *) malloc(sizeof(int));
    

    只得到“malloc:**error for object 0x100108e98:incorrect checksum for freed object-object maybuly was modified after been freed.”据我所知,这个错误已经为这个对象分配了内存,但是我不知道发生了什么。malloc(sizeof(attribute))是否只分配了存储一个整数和两个指针所需的内存(即,不是指针指向的内存)?

    任何帮助都将不胜感激!

    瓦西里

    3 回复  |  直到 16 年前
        1
  •  1
  •   BobbyShaftoe    16 年前

    所以,你有几件事要做。首先,不要强制转换 malloc 用C语言编程。接下来,这会引起麻烦:

    int v = atoi(value);
    current_tuple->attributes[k].value = &v;
    

    您在堆栈上分配了指向内存的值。如果在当前“v”超出范围后访问它,那就太糟糕了。

    另外,您没有使用任何分支条件来确定值应该是string还是int。因此,如果您像前面提到的那样正确地分配了内容,那么最终将导致内存泄漏。我怀疑这部分是因为这只是一个例子。

    检查返回值 马洛克 . 您可以创建一个包装函数来完成这项工作。另外,您可能需要做一些更好的日志记录。

    马洛克

    “和” /"

    C Programming Language

    char value[10]; /* assuming no value is longer than 10 chars */
    int i, j, k;
    
    table * data = malloc(sizeof(table));
         if(!data)
             exit(1); /* error */
    
    data->name = "table";
    data->row_count = number_of_lines;
    data->tuples = malloc(number_of_lines*sizeof(tuple));
         if(!data->tuples)
             exit(1); /* error */
    
    tuple* current_tuple;
    
    for(i=0; i<number_of_lines; i++)
    {
        current_tuple = &data->tuples[i];
        current_tuple->tuple_id = i;
        current_tuple->attribute_count = 16; /* static in our system */
        current_tuple->attributes = malloc(16*sizeof(attribute));
    
        for(k = 0; k < 16; k++)
        {
            current_tuple->attributes[k].name = attribute_names[k];
    
                            if(k % 2)
                            {
                   /* for int values:*/
                   current_tuple->attributes[k].type = DB_ATT_TYPE_INT;
                   /* write data into value-field */
                                   current_tuple->attributes[k].value = malloc(sizeof(int));
                                   if(!current_tuple->attributes[k].value)
                                   {
                                        exit(1); /* error */
                                   }    
                   *current_tuple->attributes[k].value = atoi(value);
    
                            }
                            else
                            {
                   /* for string values: */
                   current_tuple->attributes[k].type = DB_ATT_TYPE_STRING;
                                   current_tuple->attributes[k].value = malloc(strlen(value) +1);
                                   if(!current_tuple->attributes[k].value)
                                   {
                                        exit(1); /* error */
                                   }
                   strcpy(current_tuple->attributes[k].value, value);
                            }
        }
    
    
    }
    
        2
  •  1
  •   Carl Norum    16 年前

    因此,对于字符串,您将在 attribute ,但对于整数,是否要将整数本身放入值字段?那你太努力了。只需使用:

    current_tuple->attributes[k].value = (void *)v;
    

    如果要保存指向整数的指针,则需要为其分配空间,因为存储指向局部作用域变量的指针将以失败告终。像这样:

    int *v = malloc(sizeof(int));
    *v = atoi(value);
    current_tuple->attributes[k].value = v;
    

    同样,对于字符串,您总是存储相同的局部变量指针 value

        3
  •  1
  •   renick    15 年前
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    #define STR_TYPE 1
    #define INT_TYPE 2
    
    typedef struct tagAttribute
    {
        int type;
        char *name; 
        // anonymous union here
        union {
            char *value;
            int  ivalue;
        };
    } attribute, *PATTRIBUTE;
    
    
    typedef struct tagTuple
    {
        int tuple_id;
        int attribute_count;
        attribute *attributes;
    } tuple, *PTUPLE;
    
    
    typedef struct tagTable
    {
        char *name;
        int row_count;
        tuple *tuples;
    } table, *PTABLE;
    
        // allocator for table 
    PTABLE allocTable(char* name, int row_count) {
        PTABLE mytable = calloc(sizeof(table),1);
        mytable->row_count = row_count;
        mytable->name = strdup(name);
        mytable->tuples = (PTUPLE)calloc(row_count,sizeof(tuple));
        for(int i=0; i< row_count; i++) {
            mytable->tuples[i].tuple_id= i; // ?
        }
        return(mytable);
    }
    
        // allocator for attributes
    void allocAttributes( PTUPLE mytuple,  int attr_count) {
        mytuple->attributes =   (PATTRIBUTE) calloc(attr_count, sizeof(attribute));
        mytuple->attribute_count = attr_count;
    }
    
    void setAttributeStr(PATTRIBUTE pa, char *name, char *value) {
        pa->type = STR_TYPE;
        pa->name = strdup(name);
        pa->value = strdup(value);
    }
    
    void setAttributeInt(PATTRIBUTE pa, char *name, int value) {
        pa->type = INT_TYPE;
        pa->name = strdup(name);
        pa->ivalue = value;
    
    }
    
    int main (int argc, const char * argv[]) {
        // insert code here...
        printf("Test!\n");
    
            // allocate a table with two tuples
        PTABLE mytable = allocTable("my_table", 2);
            // allocate two attributes in the first tuple
    
        PTUPLE t0 = & mytable->tuples[0];
        PTUPLE t1 = & mytable->tuples[1];
    
        allocAttributes( t0, 2);
        allocAttributes( t1, 2);
    
        setAttributeStr(  &t0->attributes[0], "my_strng_field", "value0");
        setAttributeInt( &t0->attributes[1], "my_int_field", 0xBEEF);
            // now assign 
        setAttributeStr(  &t1->attributes[0], "my_second_strng_field", "value0");
        setAttributeInt( &t1->attributes[1], "my__second_int_field", 0xDEAD);
    
    
        return 0;
    }
    
    • 你需要小心你的分配
    • 或者对字符串使用strdup(),以便它们为您处理此问题

    在我的MAC上工作。