【问题标题】:C - A line of code is changing the address of a structC - 一行代码正在更改结构的地址
【发布时间】:2018-05-31 07:37:03
【问题描述】:

我的代码出现了一个重大问题,我已经尝试修复了好几个小时。

下面的代码与我遇到的问题相关...

方法addBucket:

void addBucket(SPACE * hashmap,char * tempvalue, char * tempkey){
    printf("BEGINNING OF FUNC...\n");

    void *prevadd = hashmap[0];
    char *value = varString(tempvalue);
    char *key = varString(tempkey);
    void *aftadd = hashmap[0];

    printf("BUCKET %s - %s\n",value,key);

    BUCKET *newBucket = malloc(sizeof(BUCKET *));
    fillBucket(value,key,newBucket);
    int hash = hashFunc(key);

    printf("FILL, FULFILLED\n");

    if(!hashmap[hash]){
        hashmap[hash] = malloc(sizeof(BASE*));
        hashmap[hash]->first = NULL;
    }

    ITEM *location;
    location = hashmap[hash]->first;

    //This creates a new item in the list, if there isn't any.
    //It does this by initialising the base, called box.
    if(!location){
        hashmap[hash]->first = (ITEM *) calloc(1,sizeof(ITEM *));
        hashmap[hash]->first->next = NULL;
        hashmap[hash]->first->prev = NULL;
        hashmap[hash]->first->data = newBucket;
    }

        //This instead adds a new item to the list.
    else{
        //This loop reaches the last ITEM in the linked list itself
        while(location->next){
            location = location->next;
        }

        //This initialises the newItem that will be added
        ITEM *newItem = (ITEM *) calloc(1,sizeof(ITEM));
        newItem->next = NULL;
        newItem->data = newBucket;
        newItem->prev = location;
        location->next = newItem;
    }
}

使用的声明结构:

//Declares a struct called BUCKET.
//Serves as the bucket of the hash table.
typedef struct bucket{
    char * value; //The value inputted.
    char * key; //The key to be hashed.
}BUCKET;

//Declares a struct called ITEM.
//Holds the bucket, as well as the address to the next bucket.
//It also holds the address to the previous bucket.
typedef struct item{
    struct bucket * data;
    struct item * next;
    struct item * prev;
}ITEM;


//Declares a struct called BASE.
//Serves as the base node for the linked lists.
//The amount of initialised linked lists is the same as the amount of bases.
typedef struct base{
    struct item * first;
}BASE;

//Declares a struct of an array of BASES, meaning linked lists.
//Essentially defines the size of the hashspace.
typedef BASE *SPACE;

...还有方法expandHashspace(); :

//Makes the size of the entire hashspace larger.
//Only takes a value larger than the current size due to possible data loss.
SPACE* expandHashspace(SPACE *hashmap, int newSize){
    if(newSize>100 || newSize<hashSpaceSize){
        printf("Exiting...\n");
        return NULL;
    }
    else {
        SPACE *nw = NULL;
        nw = realloc(hashmap, sizeof(SPACE *) * newSize);
        hashmap = nw;
        hashSpaceSize = newSize;
        return hashmap;
    }
}

这里还有 initHashmap() 方法:

SPACE* hashmapInit(SPACE *hashmap){
    hashmap = calloc(5, sizeof(SPACE *));
    hashSpaceSize = 5;
    return hashmap;
}

我在这里做的是初始化哈希图,添加三个桶,扩展哈希图,然后再添加三个桶。这是更简单的顺序:

initHashmap();
addBucket(...); x3
expandHashmap();
addBucket(...); x3

但是,在最后一部分,只要我运行 addBucket 一次,就会收到 SIGSEGV 错误。通过调试检查,我意识到有问题。

您看到变量*prevadd*aftadd 了吗?我在调试时添加了它们,以查看 hashmap[0] 的地址发生了什么。这是我的结果图片:

如您所见,hashmap[0] 的地址在这两行 char * 中变化很大。具体来说,地址的变化发生在char *value这一行。

请放轻松,因为我 3 个月前才开始学习 C,但我仍然非常不习惯内存分配。如果错误很明显,请指出,如果我分配内存或释放内存的方式有问题,我很高兴听到它们(我的代码有一个非常严重的 heisenbug,我无法修复为了我的一生,但这无关紧要)。

在此先感谢您...对于最近的所有问题,我们深表歉意。

更新:忘记添加 varString();...

char* varString(const char *origString){
    size_t i;
    for(i = 0;origString[(int)i]!='\0';i++){}
    if(origString[i-1]=='\n') i-=2;
    char *newString = malloc(i);
    for(int j = 0; j <= i; j++){
        newString[j] = origString[j];
    }
    newString[i+1] = '\0';
    return newString;
}

【问题讨论】:

  • "这是我的结果图片:" => 只有上帝知道你为什么不复制粘贴调试信息。
  • realloc 可能会在不同的地址分配新块。如果没有看到调用expandHashspace 的代码,就无法判断您是否正确处理了此问题,而您没有显示该代码。尝试将其减少到 MCVE
  • 哦,我知道你认为varString 行为不端,而代码转储的所有其余部分可能无关紧要?浏览varString 并检查它是否正常工作,这对我来说看起来很奇怪。可能应该使用strlen/strchr/strncpy 等。
  • 您的varString 没有任何意义并且存在带外问题。
  • @Stargateur - 我正在使用 CLion,所以我觉得展示图片更容易。对不起。

标签: c pointers memory-management struct memory-address


【解决方案1】:

这不是一个答案,但它需要比评论更多的格式:

注意你写的是"Value No. 1"

注意aftadd的值是0x756c6156

在内存中,假设一台 little-endian 机器,aftadd 中数字的布局为:

0x56 0x61 0x6c 0x75

在 ASCII 中它们是:

'V' 'a' 'l' 'u'

提示提示。

【讨论】:

  • ...等一下。字符串是否有可能覆盖了 hashmap[0]?我不知道这是怎么发生的,但这似乎是唯一可能的答案。我不知道检查 aftadd 中值的 ASCII 值...这很有意义!
  • 是的,这恰好是问题所在。注释掉这些行并避免使用该方法完全解决了这个问题。具有讽刺意味的是,您的“不回答”是一个答案!
  • 查看varString,它覆盖hashmap[0] 的事实可能表明hashmap[0] 指向的块在某个时候被释放,使该块再次可供malloc 使用。如果您有valgrind,它可以非常方便地识别这些类型的错误。
  • 老实说,我希望 windows 有一个等效的 valgrind。不得不重新启动到 ubuntu 以使用 valgrind 和调试代码听起来很痛苦,但在这一点上,我觉得这是我唯一的选择。我很确定我也有大量的内存泄漏,内存管理不太好,呵呵。
猜你喜欢
  • 2011-07-29
  • 2020-11-20
  • 1970-01-01
  • 1970-01-01
  • 2012-07-30
  • 1970-01-01
  • 2013-03-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多