我想知道这是不是很好的做法:
我已经阅读了几篇关于内存管理和内存泄漏的帖子和文章。除此之外,我还读到在函数内部分配内存不被认为是好的但是我应该如何在main中分配内存,如果我在函数内部只知道要分配多少,因为要分配的内存大小取决于数据库中字符串的长度?
typedef struct{
int age;
char * name;
}my_struct;
bool get_data(my_struct * p){
bool succes=false;
if(mysql_real_connect(my, "localhost", SQL_USER, SQL_PASS, SQL_BASE, 0, NULL, 0) == NULL){
fprintf(stderr,"MYSQL-connection error!");
success=false;
}
if(mysql_query(my, "SELECT * FROM Persons WHERE id=1")){ // Assume this would be where the real data came from
fprintf(stderr, "sql_query: %s\nfailed\n", query);
success=false;
}else{
MYSQL_RES * result=NULL;
result = mysql_store_result(my);
if(mysql_num_rows(result) == 1){
MYSQL_ROW row=NULL;
row=mysql_fetch_row(result);
p->age=atoi(row[1]);
if(asprintf(&p->name, "%s", row[2])==-1){
success=false;
p->name=NULL;
}else{
success=true;
}
}else{
success=false;
}
mysql_free_result(result);
}
mysql_close(my);
return(success);
}
void init_my_struct(my_struct * s){
s->age=0;
s->name=""; // This should be: s->name=NULL;
}
void reset_my_struct(my_struct * s){
if(s->name)free(s->name);
init_my_struct(s);
}
int main(int argc, char **argv){
my_struct person;
init_my_struct(&person);
if(get_data(&person)){
puts("OK");
}else{
puts("Not OK");
}
reset_my_struct(&person); // Frees memory if it was allocated
}
另外:我使用自己编写的函数来初始化和重置/解析struct my_struct
,这可以被认为是安全的吗?或者它是内存腐败的定时炸弹?
答案 0 :(得分:3)
这看起来不错,除了一件事:
void init_my_struct(my_struct * s){
s->age=0;
s->name=""; // assigns a const char * to s->name
}
在这里,您将s->name
设置为非NULL值。空字符串与NULL不同。它是一个包含值0的单字符数组,即空终止字符串之前没有任何内容的空终止字符串。
如果您在为其分配任何内容之前尝试free(s->name)
,那么您可能会进行核心转储,因为""
未返回常量字符串malloc
。
在函数内部分配内存很好,特别是如果确定需要多少内存是一个留给函数的任务。但是你必须确保在函数调用后的某个时刻free
。
答案 1 :(得分:2)
(m)在函数中分配内存是可以的。你读到的文章可能意味着最好先分配内存并在同一个函数中释放它。但是,正如您所发现的那样,这只有在调用者(在您的情况下为main
)知道要分配多少内存时才有可能。在这种情况下,我建议您在get_data
函数的文档中添加一条注释,说明它在p
中分配的内存应为free
d。
具有单独的功能来初始化&摧毁struct
也很好。但是,init_my_struct
函数会导致reset_my_struct
中的未定义行为,因为它会向""
成员分配一个(n为空)字符串常量name
。如果reset_my_struct
尝试free
此字符串,则会导致未定义的行为,因为即使空字符串也不是NULL
/ 0
/ false。你应该改为:
s->name = NULL;
最后,您使用asprintf
很好,但如果您只想复制字符串而不添加任何其他内容,则strdup
可能更合适。例如:
p->name = strdup(row[2]);
if(p->name == NULL){
success=false;
}else{