【问题标题】:Using asprintf inside another function to allocate Memory for String在另一个函数中使用 asprintf 为字符串分配内存
【发布时间】:2015-11-19 19:16:27
【问题描述】:

我想知道这是否是好的做法:

  • 从函数内部的数据库中获取字符串
  • 使用 asprintf 为要存储在传递给函数的 Struct 中的字符串分配内存

我已经阅读了几篇关于 C 中的内存管理和内存泄漏的文章和文章。除此之外,我还读到在函数内部分配内存并不好,但我应该如何在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
}

另外:我使用自己编写的函数来初始化和重置/销毁结构my_struct,这可以认为是安全的吗?还是内存损坏的定时炸弹?

【问题讨论】:

    标签: mysql c memory-management memory-leaks printf


    【解决方案1】:

    这看起来不错,除了一件事:

    void init_my_struct(my_struct * s){
        s->age=0;
        s->name="";     // assigns a const char * to s->name
    }
    

    在这里,您将 s->name 设置为非 NULL 值。空字符串与 NULL 不同。它是一个包含值 0 的单个字符数组,即一个以 null 结尾的字符串,在 null 终止符之前没有任何内容。

    如果您在分配任何内容之前尝试free(s->name),您可能会发生核心转储,因为malloc 未返回常量字符串""

    在函数内部分配内存很好,特别是如果确定需要多少内存是函数的任务。但是你必须确保在函数调用之后的某个时刻free它。

    【讨论】:

    • 我是否也可以在 main 中执行此操作:my_struct * person=calloc(1, sizeof(my_struct)); //Do something free(person); //to free all memory consumed by person 或者我是否需要释放 my_struct 的每个成员(在完整的程序中有更多字符串)?跨度>
    • @Cdrmoi 您可以这样做,但这只是为结构本身分配内存,而不是为其成员指向的任何内容。您仍然需要 malloc/free 结构中包含的任何指针。
    【解决方案2】:

    在函数中(m)分配内存很好。您阅读的文章可能意味着最好预先分配内存并在同一个函数中释放它。但是,正如您所发现的,这只有在调用者(在您的情况下为main)知道要分配多少内存时才有可能。在这种情况下,我建议您在 get_data 函数的文档中添加注释,说明它在 p 中分配内存,应该是 freed。

    拥有单独的函数来初始化和销毁​​structs 也很好。但是,您的 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{
    

    【讨论】:

    • 好的。感谢这两个(@Kninnug 和@dbush)快速回答。在我的代码中,我将其更改为 s->name = NULL; 我应该在我的问题中也将其更改,还是应该作为其他人的示例?
    • @Cdrmoi 您应该保留您的问题,以便未来的访问者可以从中学习。不过,您可以更改 rwo 错字,因为它与问题无关:)。
    猜你喜欢
    • 2016-10-20
    • 2016-03-25
    • 1970-01-01
    • 1970-01-01
    • 2012-08-04
    • 2011-06-01
    • 1970-01-01
    • 2019-10-13
    • 1970-01-01
    相关资源
    最近更新 更多