代码之家  ›  专栏  ›  技术社区  ›  Sam Hammamy

为算术临时铸造void*的正确方法是什么?

  •  9
  • Sam Hammamy  · 技术社区  · 6 年前

    我是C新手,但多年来一直是一名程序员,所以我尝试着从2008年开始跟随斯坦福大学的课程学习C。 Assignment 3 关于c中的向量。

    它基本上只是一个泛型数组,因此数据作为 void * . 编译器标志 -Wpointer-arith 打开了,所以我做不到 arithmetic (我也明白原因)。

    围绕数据的结构 一定不知道 数据是什么类型的,所以它对调用者是通用的。

    为了简化操作,我尝试以下代码:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    typedef struct {
        void *data;
        int aindex;
        int elemSize;
    } trial;
    
    void init(trial *vector, int elemSize)
    {
        vector->aindex = 0;
        vector->elemSize = elemSize;
        vector->data = malloc(10 * elemSize);
    }
    
    void add(trial *vector, const void *elemAddr)
    {
        if (vector->aindex != 0)
            vector->data = (char *)vector->data + vector->elemSize;
    
        vector->aindex++;
        memcpy(vector->data, elemAddr, sizeof(int));
    
    }
    
    int main()
    {
        trial vector;
        init(&vector, sizeof(int));
    
        for (int i = 0; i < 8; i++)
            {add(&vector, &i);}
    
        vector.data = (char *)vector.data - ( 5 * vector.elemSize);
        printf("%d\n", *(int *)vector.data);
        printf("%s\n", "done..");
    
        free(vector.data);
        return 0;
    }
    

    但是我可以免费得到一个错误 free(): invalid pointer . 所以我跑了 valgrind 并收到以下信息:

    ==21006==  Address 0x51f0048 is 8 bytes inside a block of size 40 alloc'd
    ==21006==    at 0x4C2CEDF: malloc (vg_replace_malloc.c:299)
    ==21006==    by 0x1087AA: init (pointer_arithm.c:13)
    ==21006==    by 0x108826: main (pointer_arithm.c:29)
    

    在这一点上,我想我不是在做 char* 正确,或者可能使用 memcpy incorrectly

    3 回复  |  直到 6 年前
        1
  •  10
  •   Sergey Kalinichenko    6 年前

    这是因为您向向量中添加了八个元素,然后在尝试 free . 你可以用 vector->aindex 决定索引展开的程度。

    然而,问题的根本原因是您修改了 vector->data . 您应该首先避免修改它,因为它依赖于您的 add 改为函数:

    void add(trial *vector, const void *elemAddr, size_t sz) {
        char *base = vector->data;
        memcpy(base + vector->aindex*sz, elemAddr, sz);
        vector->aindex++;
    }
    

    注意使用 sz ,你需要通过 sizeof(int) 对它。

    代码中的另一个问题是当您通过强制转换打印时 vector.data int* . 这可能有效,但更好的方法是编写类似的 read 函数提取数据。

        2
  •  4
  •   SenselessCoder    6 年前

    如果您事先不知道数组的数据类型,那么在第一次初始化它时,必须假定有一定数量的内存,例如32字节或100字节。然后,如果内存不足,可以使用realloc进行扩展,并将以前的数据复制到新的插槽中。C++向量Irc遵循X2或X2.2比率重新分配,不确定。

    下一个是你的 free . 这里有件大事你必须知道。如果用户向您发送他们自己的内存分配对象呢?例如a char* 他们以前分配的?如果只删除向量的数据成员,那就不够了。您需要请求一个函数指针,以防数据类型是需要特别注意的输入添加内容。

    最后,你在这一行犯了一个大错误:

    if (vector->aindex != 0)
        vector->data = (char *)vector->data + vector->elemSize;
    

    您正在修改指针地址!!!!您的初始地址在这里丢失!你绝对不能这样做。使用临时 烧焦* 保存初始数据地址并进行操作。

        3
  •  4
  •   unwind    6 年前

    您的代码有些混乱,可能有一两个错误理解隐藏在其中。

    一些观察:

    1. 你不能 改变 返回的指针 malloc() 然后将新值传递给 free() . 传递给的每个值 自由() 必须与某个分配函数返回的值完全相同。
    2. 如你所料,抄袭最好由 memcpy() 你得把球投给 char * 为了算术。

    附加值的函数可以是:

    void add(trial *vector, const void *element)
    {
      memcpy((char *) vector->data + vector->aindex * vector->elemSize, element);
      ++vector->aindex;
    }
    

    当然,这不会处理向量溢出,因为没有存储长度(我不想假定它是硬编码的,为10)。

    改变 data 价值 vector 因为每一个物体都是非常奇怪的,使事情变得更加混乱。只需在需要访问元素时添加所需的偏移量,这非常便宜而且非常直接。