微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

取消引用指针会更改其值

如何解决取消引用指针会更改其值

我试图在c中实现生锈样式的矢量,

typedef struct
{
    int *ptr,// pointer to starting element
    int len,// length of the vector
    int cap,// capacity; it does not reallocate the whole vector till len == cap
} vector;

除get-value函数外,我几乎所有工作正常。不管向量的长度如何,调用vec_getval函数始终会将第3个元素和第4个元素分别更改为1936877926和10。这是所有相关代码,省略了错误检查:

#define ELEMENT_SIZE sizeof(int)

extern vec_data vec_getval(vector *vec,size_t index)
{
    return *(vec->ptr + (ELEMENT_SIZE * index));
}

extern void vec_push(vector *vec,vec_data val)
{
    if (vec->len < vec->cap)                                    // Don't reallocate if length < capacity
    {
        *(vec->ptr + (ELEMENT_SIZE * vec->len)) = val;
        vec->len++;
        return;
    }

    realloc(vec->ptr,ELEMENT_SIZE * (vec->len + 1));
    *(vec->ptr + (ELEMENT_SIZE * vec->len)) = val;
    vec->len++;
    vec->cap++;
}

extern void vec_with_capacity(vector *vec,size_t cap)
{
    vec->ptr = (int *)malloc(ELEMENT_SIZE * cap);
    vec->cap = cap;
    vec->len = 0;
}

int main(int argc,char **args)
{
    vector vec;

    vec_with_capacity(&vec,5);
    vec_push(&vec,50u);
    vec_push(&vec,15u);
    vec_push(&vec,40u);
    vec_push(&vec,80u);
    vec_push(&vec,70u);

    printf("first value\t: %d\n",vec_getval(&vec,0)); // Works as expected,but changes 3rd and 4th elements
    printf("third value\t: %d\n",2)); // Does not work fine!
    return 0;
}

这是输出

first value     : 50
third value     : 1936877926

解决方法

对于任何指针或数组p和索引i,表达式*(p + i) 精确地等于p[i]

现在,如果我们对*(vec->ptr + (ELEMENT_SIZE * index)进行此转换,则会得到vec->ptr[ELEMENT_SIZE * index]。这可能与您的想法不符。

假设sizeof(int)ELEMENT_SIZE的扩展名)是4(非常常见),则尝试使用索引2实际上将使用索引84 * 2)。哪个超出了您分配的内存范围(因为它仅包含5元素),并导致未定义的行为。

解决方案很简单:访问数组的元素时不要与ELEMENT_SIZE相乘。


您还有另外两个非常严重的错误:

realloc(vec->ptr,ELEMENT_SIZE * (vec->len + 1))
*(vec->ptr + (ELEMENT_SIZE * vec->len)) = val;

由于第一行缺少分号,因此该语句变为

realloc(vec->ptr,ELEMENT_SIZE * (vec->len + 1)) * (vec->ptr + (ELEMENT_SIZE * vec->len)) = val;

那没有任何意义。

除了缺少分号之外,第二个问题是realloc可以分配一个 new 内存区域,然后该内存区域返回一个指针。这将使旧指针无效,因为它随后指向您不再拥有的内存。始终使用realloc返回的结果。

还要注意,realloc可以返回NULL,在这种情况下,旧指针仍然有效,因此请始终使用一个临时变量:

int *new_ptr = realloc(vec->ptr,ELEMENT_SIZE * (vec->len + 1));
if (new_ptr == NULL)
{
    // TODO: Handle error
}
vec->ptr = new_ptr;
vec->ptr[vec->len] = val;

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。