C - 如何修改函数内部的指针数组

时间:2014-05-23 03:44:38

标签: c arrays function pointers

我正在尝试在C中实现哈希表,几乎拥有它。我正在通过链接使用每个数组槽中的链表来实现冲突解决,我希望能够在函数调用内部进行链接。

现在,问题在于为了使修改成为永久性的,我相信我需要一个额外的间接层。这是一个问题,当我尝试遍历列表时,前一个元素被下一个元素覆盖(请参阅我在insert()函数中的注释)。我试图传递这个数组与额外的间接级别指定几种不同的方式,但我得到编译器警告和seg错误。

这对你们中的一些人来说可能看起来很简单,但是现在我已经抓住了很长一段时间了,这个场景(传递修改指针的数组)在我的文本中没有处理,我似乎无法找到问这个确切的问题(虽然它可能是我不认识的形式)。我不一定在寻找代码的“快速修复”,但我想了解完成我想要做的事情的最佳实践。

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
//#include "list.c"
struct node{
    int key;
    struct node* next;
};

void createTable(struct node *table[], int numEls, int numSlots);
int hash(int key, int numSlots);
void insert(struct node *table[], int key, int slot, int numSlots);
void display(struct node *table[], int numEls);

int main(void){
    srand(time(NULL));
    int numEls, numSlots;
    printf("Please enter the desired number of slots in the hash table: ");
    scanf("%d", &numSlots);
    struct node *table[numSlots];
    printf("\nPlease enter the desired number of elements: ");
    scanf("%d", &numEls);
    printf("\nYour load factor will be %f", (float)numEls/numSlots);
    createTable(table, numEls, numSlots);
}

void createTable(struct node *table[], int numEls, int numSlots){
    for(int i = 0; i < numSlots; i++)
        table[i] = NULL;
    for(int j = 0; j < numEls; j++){
        for(int k = 0; k < 99999999; k++){}//give the rand function time 
        int el = rand()%100;
        insert(table, el, hash(rand()%100, numSlots), numSlots);
    }
    display(table, numSlots);
}

int hash(int key, int numSlots){
    return((int)(pow(key, 2.819)) % numSlots);
}

void insert(struct node *table[], int key_, int slot, int numSlots){
    printf("\nInserting %d into slot %d", key_, slot);
    fflush(stdout);
    struct node* new = malloc(sizeof(struct node));
    (new)->key = key_;
    (new)->next = NULL;
    struct node** temp = &(table[slot]);
    if((*temp) == NULL){
        printf(" (*temp) == NULL");
        (*temp) = new;
    }
    else{
        printf(" %d", (*temp)->key);
        while((*temp)->next != NULL){
            printf(" %d", (*temp)->next->key);
                (*temp) = (*temp)->next;  //head is overwritten with head->next 
        }
        (*temp)->next = new;
        printf(" %d", (*temp)->next->key);
    }
}

void display(struct node *table[], int numSlots){
    for(int i = 0; i < numSlots; i++){
        printf("\nSlot %d:", i);
        struct node* temp = table[i];
        while(temp != NULL){
            printf(" %d", temp->key);
            temp = temp->next;
        }
    }
}

2 个答案:

答案 0 :(得分:2)

在注释的行中,您使用链接列表中的下一个元素将指针覆盖到头部(最外层数组内),这可能不是您的意图。

更正是沿着指针列表向下走,直到找到最后一个指针,而不是在步行期间修改主数据结构。

以下是insert()的更正版本。

void insert(struct node *table[], int key_, int slot, int numSlots){
    printf("\nInserting %d into slot %d", key_, slot);
    fflush(stdout);
    struct node* new = malloc(sizeof(struct node));
    new->key = key_;
    new->next = NULL;

    // Here we make a copy of the pointer to the head node in the linked list.
    // This way, we never overwrite the original copy which lives in the array itself.
    struct node* head = table[slot];
    if(head == NULL){
        printf(" head == NULL");
        table[slot] = new;
    }
    else{
        while(head->next != NULL) {
            head = head->next;  //head is overwritten with head->next 
        }
        head->next = new;
    }
}

答案 1 :(得分:1)

这不是一个答案,但对于评论来说太大了......你能解释一下这段代码应该做什么吗?

while((*temp)->next != NULL)
{
    printf(" %d", (*temp)->next->key);
    (*temp) = (*temp)->next;  //head is overwritten with head->next 
}
(*temp)->next = new;

我希望您希望将新节点附加到此插槽中现有节点的链接列表的末尾。但是这段代码实际上更新了头部以指向列表中的最后一个节点,就像你的评论所说的那样(泄漏内存 - 列表中的早期节点现在无法访问)。然后它使最后一个节点(现在是列表中唯一的节点)指向new

所以你的&#34;列表&#34;只有长度为1或2,并且每次尝试输入第三个条目时它会泄漏内存。

在我看来,你传递table(链接列表的头部列表)没有任何问题,但问题是维护这些列表的列表的代码是不对。