在我的项目中,我遇到了C程序。
htmp
是结构指针。我们首先为它分配一个内存。但是为什么我们要再为它的元素word
分配一个内存呢?id
和next
分配内存?#define HASHREC bitewisehash
typedef struct hashrec {
char *word;
long long id;
struct hashrec *next;
} HASHREC;
/* Move-to-front hashing and hash function from Hugh Williams, http://www.seg.rmit.edu.au/code/zwh-ipl/ */
/* Simple bitwise hash function */
unsigned int bitwisehash(char *word, int tsize, unsigned int seed) {
char c;
unsigned int h;
h = seed;
for (; (c =* word) != '\0'; word++) h ^= ((h << 5) + c + (h >> 2));
return((unsigned int)((h&0x7fffffff) % tsize));
}
/* Insert string in hash table, check for duplicates which should be absent */
void hashinsert(HASHREC **ht, char *w, long long id) {
HASHREC *htmp, *hprv;
unsigned int hval = HASHFN(w, TSIZE, SEED);
for (hprv = NULL, htmp = ht[hval]; htmp != NULL && scmp(htmp->word, w) != 0; hprv = htmp, htmp = htmp->next);
if (htmp == NULL) {
htmp = (HASHREC *) malloc(sizeof(HASHREC)); # allocate memory for htmp
htmp->word = (char *) malloc(strlen(w) + 1); # why allocate memory again ?
strcpy(htmp->word, w); #
htmp->id = id; # why not allocate memory for htmp->id ?
htmp->next = NULL; # why nor allocate memory for htmp->next?
if (hprv == NULL) ht[hval] = htmp;
else hprv->next = htmp;
}
else fprintf(stderr, "Error, duplicate entry located: %s.\n",htmp->word);
return;
}
答案 0 :(得分:3)
你需要在脑海中分离两件事(1)我想存储的东西是什么内存? (2)什么变量(指针)将地址保存到存储的位置,以便我可以再次找到它。
首先声明两个指向struct hashrec
的指针:
HASHREC *htmp, *hprv;
指针只不过是一个变量,它将地址保存为其他值作为其值。当您第一次声明两个指针时,它们是未初始化并且不保留地址。然后,你以一种相当尴尬的方式,在for
循环声明中初始化两个指针,例如: hprv = NULL, htmp = ht[hval]
以及之后hprv = htmp, htmp = htmp->next
所以大概两个指针现在都有一个地址并指向某处。
在循环(使用空体)之后,您测试if (htmp == NULL)
,这意味着htmp
未指向地址(如果您找到了感兴趣的哈希索引,则可能就是这种情况空)。
然后,为了为一个HASHREC
(例如struct hashrec
)提供存储空间,您需要分配存储空间,以便在内存块中存储要存储的内容。所以你分配一个块来保存一个结构。 (见:Do I cast the result of malloc?)
现在,看看为内存分配的内容:
typedef struct hashrec {
char *word;
long long id;
struct hashrec *next;
} HASHREC;
您为包含(1)char *word;
的结构分配了存储空间(指向char的指针 - 8字节(x86上为4字节)); (2)一个long long id;
(两个都是8个字节)和(3)一个指针,用于保存序列中下一个HASHREC
的地址。
毫无疑问id
可以保留long long
值,但word
和next
呢?它们都是指针。指针有什么作用?可以找到他们指向的东西的地址。哪里可以word
找到?你想要的东西目前由w
指向,但不能保证w
将继续保留你想要的单词,所以你要制作一份副本并将其存储为HASHREC
。所以你看:
htmp->word = malloc(strlen(w) + 1); /* useless cast removed */
现在malloc
会返回什么?它将地址返回到新的内存块的开头,strlen(w) + 1
个字节长。由于指针将其他值保存为其值,因此htmp->word
现在将地址存储到新内存块的开头作为其值。所以htmp->word
“指向”到新的内存块,您可以使用htmp->word
作为参考来引用该内存块。
接下来发生的事情很重要:
strcpy(htmp->word, w); #
htmp->id = id; # why not allocate memory for htmp->id ?
htmp->next = NULL; # why nor allocate memory for htmp->next?
strcpy(htmp->word, w);
将w
复制到新的内存块中。 htmp->id = id;
将id
的值分配给htmp->id
,不需要分配,因为当您分配时:
htmp = malloc(sizeof(HASHREC)); /* useless cast removed */
您为(1)char *
指针,(2)long long id;
和(3)struct hashrec*
指针分配存储 - 您已经已分配对于long long
,htmp->id
可以将id
的值存储在long long
的内存中。
htmp->next = NULL; # why nor allocate memory for htmp->next?
您尝试存储的内容是什么,需要htmp->next
的新分配? (提示:目前没有)它将指向下一个struct hashrec
。目前它已初始化为NULL
,以便下次迭代到所有struct hashrec next
指针的末尾时,当您到达NULL
时,您知道自己就在最后。
另一种思考方式是,之前的struct hashrec next
现在可以指向刚分配的节点。同样不需要额外的分配,前一个节点->next
指针只是依次指向下一个节点,不需要分配任何特定的新内存。它仅用作引用(或指向)链中下一个节点的引用。
这里有很多信息,但是当你经历了确定(1)在我想要存储的东西存储的思维过程中? (2)什么变量(指针)将地址保存到存储的位置,以便我可以再次找到它... - 事情开始落实到位。希望这会有所帮助。
答案 1 :(得分:1)
当为结构分配内存时,只为成员word
分配了足够的内存来保存指针,该指针也必须指向有效的内存,然后你可以分配它。
如果没有指向有效内存,它的值是 indeterminate 并尝试使用 indeterminate 值取消引用此类指针是未定义的行为。
答案 2 :(得分:1)
malloc(size)
将分配给定大小的内存并返回已分配内存的起始地址。地址存储在指针变量中。
在char *word
中,变量word
是指针类型,它只能保存char类型的指针,即内存中字符数据的地址。
所以,当你为结构类型变量htmp
分配内存时,它将按如下方式分配内存, 2 字节为*word
, 4 id
的字节数和*next
现在,假设您要将以下内容存储到结构中:
{
word = Elephant
id = 1245
}
现在,您可以通过执行此id
将ID直接保存到htmp->id = 1245
成员中。但你也想保存一个单词&#34; 大象&#34;在你的结构中,如何实现这个目标?
htmp->word = 'Elephant'
会导致错误,因为word是指针。所以,现在你分配内存来存储实际的字符串文字大象,并将起始地址存储在htmp->word
。
您可以使用char *word
而不是在您的结构中使用char word[size]
,而无需为成员word
单独分配内存。不这样做的原因是你要为单词选择一些随机大小,如果你存储较少的字符会浪费内存,如果单词太大则甚至会掉落。