我最近开始研究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
答案 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;
}
适用于我的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);
}
}
}