在循环中初始化一个唯一指针(用于散列table)
Initialising a unique pointer in a loop (to be used in a hash table)
在过去的几年里,我一直在 Python 使用字典进行数字运算。几年后我正在重述 C,我正在尝试使用散列 table 来模仿 python 字典功能。我的散列 table 工作正常,但我正在努力在循环中以编程方式添加新条目。这是我的代码:
#define TABLE_SIZE 16
typedef struct item{
char key[64];
int value;
int list[5];
struct item *next;
} item;
// Create hash table array
item *hash_table[TABLE_SIZE];
void init_hash_table(){
for (int i = 0; i < TABLE_SIZE; i++)
hash_table[i] = NULL;
}
int hash(char *key){
unsigned long H = 5381;
int c;
while ((c = *key++))
H = ((H << 5) + H) + c;
H = H % TABLE_SIZE;
int hash = (int)H;
return hash;
}
int insert_item(item *pItem){
if (pItem == NULL){
printf("Invalid item");
return -1;
}
else {
int index = hash(pItem->key);
pItem->next = hash_table[index];
hash_table[index] = pItem;
return index;
}
}
void print_table(){
printf("\n--- Table Start ---\n");
for (int i = 0; i < TABLE_SIZE; i++){
if (hash_table[i] == NULL)
printf("\t %d \t --- \t\n", i);
else {
item *tmp = hash_table[i];
printf("\t %d ", i);
while(tmp != NULL){
printf("\t --- \t %s", tmp->key);
tmp = tmp->next;
}
printf("\n");
}
}
printf("--- Table End ---");
}
int main(){
// Initialise hash table
init_hash_table();
char letters[] = "ABCDEFGHIJ";
// Insert data
for (int i = 0; i < 10; i++){
item itemN = {.key = letters[i]};
printf("%s ", itemN.key);
printf("%p\n", &itemN);
insert_item(&itemN);
}
// Print the table
print_table();
return 0;
}
基本上我想将 10 个条目添加到散列 table,每个条目都是唯一的,键是不同的字母(A 到 J)。问题是 main 中的每个 itemN 在内存中都有相同的地址,因此每次都会覆盖相同的指针。因此我的输出看起来像:
A 0061FEB0
B 0061FEB0
C 0061FEB0
D 0061FEB0
E 0061FEB0
F 0061FEB0
G 0061FEB0
H 0061FEB0
I 0061FEB0
J 0061FEB0
--- Table Start ---
0 ---
1 ---
2 ---
3 --- J
4 ---
5 ---
6 --- J
7 --- J
8 --- J
9 --- J
10 --- J
11 --- J
12 --- J
13 --- J
14 --- J
15 ---
--- Table End ---
问题是,如何在循环中生成一个具有唯一地址的新项目变量?这似乎是实现起来非常标准的功能,因为我们不能总是手动初始化变量。对不起,如果我遗漏了一些明显的东西!
谢谢
代码不断插入相同的项目。 &itemN
是本地对象的地址 itemsN
。该项目超出范围,在循环 { ...}
后不再有效
for (int i = 0; i < 10; i++){
item itemN = {.key = letters[i]};
...
insert_item(&itemN);
}
print_table(); // no longer valid for code to use `&itemN`.
.key = letters[i]
也是无效的,因为它试图将 char
分配给 char *
。这意味着警告未完全启用。节省时间,全部启用。
也许插入 10 个不同的 item
。
item items[10] = { 0 };
for (int i = 0; i < 10; i++){
items[i].key[0] = letters[i];
printf("%s ", items[i].key);
printf("%p\n", &item[i]);
insert_item(&items[i]);
}
GTG
基本问题是你的散列 table 实际上并不存储项目,它存储指针,而你的 insert_item
函数接受一个指针并将该指针直接插入散列 table,这意味着它只有在该对象还活着时才有效。当对象的生命周期结束时,指针变得悬空并且您的散列 table 变得无效,因此之后的几乎所有行为都是未定义的行为。
无论何时在 C 中处理指针(几乎所有时间),您都需要了解所指向对象的生命周期,并确保指针在生命周期结束后不会被使用.在您的情况下,您将 item
定义为 main 循环内的本地(自动),因此生命周期将在循环迭代结束后立即结束。因此,当您将第二个项目放入散列 table 时,您在 table 中有一个悬空指针,并且所有赌注都已关闭。
通常的处理方法是让您的散列 table“拥有”table 中的对象,并让您的 insert_item
复制项目(使用 malloc 为副本分配一些内存):
int insert_item(item *pItem){
if (pItem == NULL){
printf("Invalid item");
return -1;
}
else {
int index = hash(pItem->key);
item *copy = malloc(sizeof(item));
if (copy == NULL) {
printf("Ran out of memory\n");
return -1; }
*copy = *pItem;
copy->next = hash_table[index];
hash_table[index] = copy;
return index;
}
}
这样,实际上在散列 table 中的所有项目对象都将具有延长的生命周期——它们将一直存在,直到您明确释放它们。当你完成哈希 table 本身时,你想这样做,所以你可能有一个 destroy_table
函数来做到这一点。
在过去的几年里,我一直在 Python 使用字典进行数字运算。几年后我正在重述 C,我正在尝试使用散列 table 来模仿 python 字典功能。我的散列 table 工作正常,但我正在努力在循环中以编程方式添加新条目。这是我的代码:
#define TABLE_SIZE 16
typedef struct item{
char key[64];
int value;
int list[5];
struct item *next;
} item;
// Create hash table array
item *hash_table[TABLE_SIZE];
void init_hash_table(){
for (int i = 0; i < TABLE_SIZE; i++)
hash_table[i] = NULL;
}
int hash(char *key){
unsigned long H = 5381;
int c;
while ((c = *key++))
H = ((H << 5) + H) + c;
H = H % TABLE_SIZE;
int hash = (int)H;
return hash;
}
int insert_item(item *pItem){
if (pItem == NULL){
printf("Invalid item");
return -1;
}
else {
int index = hash(pItem->key);
pItem->next = hash_table[index];
hash_table[index] = pItem;
return index;
}
}
void print_table(){
printf("\n--- Table Start ---\n");
for (int i = 0; i < TABLE_SIZE; i++){
if (hash_table[i] == NULL)
printf("\t %d \t --- \t\n", i);
else {
item *tmp = hash_table[i];
printf("\t %d ", i);
while(tmp != NULL){
printf("\t --- \t %s", tmp->key);
tmp = tmp->next;
}
printf("\n");
}
}
printf("--- Table End ---");
}
int main(){
// Initialise hash table
init_hash_table();
char letters[] = "ABCDEFGHIJ";
// Insert data
for (int i = 0; i < 10; i++){
item itemN = {.key = letters[i]};
printf("%s ", itemN.key);
printf("%p\n", &itemN);
insert_item(&itemN);
}
// Print the table
print_table();
return 0;
}
基本上我想将 10 个条目添加到散列 table,每个条目都是唯一的,键是不同的字母(A 到 J)。问题是 main 中的每个 itemN 在内存中都有相同的地址,因此每次都会覆盖相同的指针。因此我的输出看起来像:
A 0061FEB0
B 0061FEB0
C 0061FEB0
D 0061FEB0
E 0061FEB0
F 0061FEB0
G 0061FEB0
H 0061FEB0
I 0061FEB0
J 0061FEB0
--- Table Start ---
0 ---
1 ---
2 ---
3 --- J
4 ---
5 ---
6 --- J
7 --- J
8 --- J
9 --- J
10 --- J
11 --- J
12 --- J
13 --- J
14 --- J
15 ---
--- Table End ---
问题是,如何在循环中生成一个具有唯一地址的新项目变量?这似乎是实现起来非常标准的功能,因为我们不能总是手动初始化变量。对不起,如果我遗漏了一些明显的东西!
谢谢
代码不断插入相同的项目。 &itemN
是本地对象的地址 itemsN
。该项目超出范围,在循环 { ...}
for (int i = 0; i < 10; i++){
item itemN = {.key = letters[i]};
...
insert_item(&itemN);
}
print_table(); // no longer valid for code to use `&itemN`.
.key = letters[i]
也是无效的,因为它试图将 char
分配给 char *
。这意味着警告未完全启用。节省时间,全部启用。
也许插入 10 个不同的 item
。
item items[10] = { 0 };
for (int i = 0; i < 10; i++){
items[i].key[0] = letters[i];
printf("%s ", items[i].key);
printf("%p\n", &item[i]);
insert_item(&items[i]);
}
GTG
基本问题是你的散列 table 实际上并不存储项目,它存储指针,而你的 insert_item
函数接受一个指针并将该指针直接插入散列 table,这意味着它只有在该对象还活着时才有效。当对象的生命周期结束时,指针变得悬空并且您的散列 table 变得无效,因此之后的几乎所有行为都是未定义的行为。
无论何时在 C 中处理指针(几乎所有时间),您都需要了解所指向对象的生命周期,并确保指针在生命周期结束后不会被使用.在您的情况下,您将 item
定义为 main 循环内的本地(自动),因此生命周期将在循环迭代结束后立即结束。因此,当您将第二个项目放入散列 table 时,您在 table 中有一个悬空指针,并且所有赌注都已关闭。
通常的处理方法是让您的散列 table“拥有”table 中的对象,并让您的 insert_item
复制项目(使用 malloc 为副本分配一些内存):
int insert_item(item *pItem){
if (pItem == NULL){
printf("Invalid item");
return -1;
}
else {
int index = hash(pItem->key);
item *copy = malloc(sizeof(item));
if (copy == NULL) {
printf("Ran out of memory\n");
return -1; }
*copy = *pItem;
copy->next = hash_table[index];
hash_table[index] = copy;
return index;
}
}
这样,实际上在散列 table 中的所有项目对象都将具有延长的生命周期——它们将一直存在,直到您明确释放它们。当你完成哈希 table 本身时,你想这样做,所以你可能有一个 destroy_table
函数来做到这一点。