使用 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*。
我有一个基于字符串标签添加图形的代码,类似于:
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*。