使用 sprintf 构建字符串时出现的问题

Issues when using sprintf to build strings

我有一个基于字符串标签添加图形的代码,类似于:

    struct graph *map = graph_new();

    char *labels[] = { "aa", "ab", "ac", "ad", "ae", "af", "ag", "ah", "ai", 
                        "ba", "bb", "bc", "bd", "be", "bf", "bg", "bh", "bi", 
                        "ca", "cb", "cc", "cd", "ce", "cf", "cg", "ch", "ci", 
                        "da", "db", "dc", "dd", "de", "df", "dg", "dh", "di"};

    for(int i=0; i<36; i++)
        graph_node_add(map, labels[i], i+1);

我正在尝试创建相同的标签,但不是写每个标签,而是从 ascii table 构建字符串,如:

    struct graph *map = graph_new();

    char label[3];

    for(int i=0; i<4; i++) {
        for(int j=0; j<9; j++) {
            sprintf(label, "%c%c", i+97, j+97);
            graph_node_add(map, label, 9*i+j+1);
        }
    }

对我来说,两个片段看起来都一样,但第二个片段不起作用,我不知道为什么。

根据要求我添加了 graph_node_add,它使用 GLib

struct node *
graph_node_add(struct graph *graph,
               gchar        *label,
               gint          weight)
{
    struct node * n = g_new(struct node, 1);
    n->neighbors = g_ptr_array_new_full(1, (GDestroyNotify)graph_node_neighbor_destroyed);
    n->weight = weight;
    n->label = g_string_new(label);
    g_hash_table_insert(graph->nodes, label, n);
    return n;
}

输出:

第一种情况:

aa(1) -> 
ab(2) -> 
ac(3) -> 
ad(4) -> 
ae(5) -> 
ca(19) -> 
... lot of entries ...
da(28) -> 
db(29) -> 
df(33) -> 
dg(34) -> 
de(32) -> 
di(36) -> 
dh(35) -> 

第二种情况:

di(1) -> 
di(2) -> 
di(3) -> 
di(4) -> 
di(5) -> 
di(19) -> 
di(20) -> 
di(21) -> 
... lot of entries ...
di(34) -> 
di(32) -> 
di(36) -> 
di(35) -> 

第一个例子:

graph_node_add(map, labels[i], i+1);

这最终使用标签[i] 作为散列table 键。

第二个例子:

graph_node_add(map, label, 9*i+j+1);

这个使用label作为hash table键,每次添加一个节点都是同一个指针(hashtable不做拷贝,它使用你给它的指针)。当您在循环中修改标签内容时,您也会修改每个插入的键。如果您在将标签添加到哈希table 之前创建了标签的副本,那么它应该可以工作。

可能是这样的:

struct node *
graph_node_add(struct graph *graph,
               gchar        *label,
               gint          weight)
{
    struct node * n = g_new(struct node, 1);
    n->neighbors = g_ptr_array_new_full(1, (GDestroyNotify)graph_node_neighbor_destroyed);
    n->weight = weight;
    n->label = g_string_new(label);
    g_hash_table_insert(graph->nodes, g_strdup(label), n);
    return n;
}

现在您可以修改哈希 table 创建代码,以便在 g_hash_table_new_full() 调用中将 g_free 作为键 GDestroyNotify。

或者你可以避免使用 sprintf 而只使用 g_strdup_printf() 代替:这样你就会在循环的每次迭代中都有一个新的 char* 并且问题根本不会出现 - 你会不过仍然需要注意释放 char*。