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

时间:2010-06-13 17:18:47

标签: c memory-management

我最近开始研究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;

数据来自带插入的文件(为Wisconsin基准测试生成),我正在解析。我只有整数或字符串值。示例行看起来像:

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

只得到“对象0x100108e98的malloc:***错误:释放对象的校验和不正确 - 对象可能在被释放后被修改。”据我所知这个错误,已经为这个对象分配了内存,但是我没有看到这发生了什么。 malloc(sizeof(属性))是否只分配存储整数和两个指针所需的内存(即不是那些指针所指向的内存)?

任何帮助将不胜感激!

此致 Vassil

3 个答案:

答案 0 :(得分:1)

因此,对于字符串,您要在attribute的值字段中保存指向字符串的指针,但对于整数,您希望将整数本身放在值字段中?然后你太努力了。只需使用:

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

如果要保存指向整数的指针,则需要为其分配空间,因为存储指向本地范围变量的指针将以撕裂的方式结束。像这样:

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

同样对于字符串,您始终将相同的局部变量指针value存储到数据结构中。您可能应该进行一些复制或内存分配,以防止不断覆盖您的数据。

答案 1 :(得分:1)

#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。

感谢您回忆记忆(15年左右)

答案 2 :(得分:1)

所以,你有几件事情在这里发生。首先,不要在C编程语言中强制转换malloc的返回值。接下来,这会引起麻烦:

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

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

此外,您没有使用任何分支条件来确定值是字符串还是int。因此,假设您按照前面提到的方式正确分配了内容,最终会导致内存泄漏。我怀疑这部分是因为它只是一个例子。

检查malloc的返回值。您可以创建一个包装函数来为您执行此操作。此外,您可能希望做一些更好的日志记录。

基本上,您需要更熟悉指针在C中的工作方式以及在堆上分配和在堆栈上分配之间的区别。堆栈或自动变量超出范围。当你malloc它永远存在,直到你摆脱它。不要将指针设置为等于堆栈上分配的内存的位置,除非你真的想要这样做(再次,你的例子用“v”,一旦循环的特定迭代,该内存地址将是无效的完成后,最糟糕的情况是,当你测试它并且你没有注意到错误时它会起作用。

此外,“//”不是ANSI-C89样式注释。使用“/ ”和“ /”

我做了一些改变;我不能保证它现在可以工作,因为我没有明显地测试它。不过,我建议您阅读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);
                        }
    }


}