【问题标题】:How to assign values to a void array如何为空数组赋值
【发布时间】:2014-05-09 21:24:12
【问题描述】:

在发现C语言中没有模板后,我决定使用指针数组自己创建动态数组。

我认为这个答案可能是一个好的开始,但是,它只考虑整数数组,这并不完全适合我的需要。为此,我决定将其更改为 void 数组。

我的结构目前是这样的:

typedef struct {
  void *array;
  size_t length;  //How many spaces in array are occupied at the moment
  size_t size;    //How many spaces were allocated
  size_t elm_size;//How large one member of the array is
} Array;

我关心的是,如何设置这样的数组的元素。我计划使用我的函数array_get 来获取它们。问题是,variable[n] 运算符对void 数组没有意义,因为该运算符表示*(variable + sizeof(variable)*n),而对于void,大小为零。此时,您会同意以下是检索元素的合法方式:

void* array_get(Array *a, size_t offset) {
  if(offset>=a->used) {
    println("Error: access of undefined offset in array.");
    exit(1);
  }
  return void* (((char*)array) + offset*a->elm_size);
}

然后在程序中:

int retrieved_value;
retrieved_value = *((int*)array_get(&my_array, 2)); //The outer star is for dereferencing

但是,在设置元素时,我很无奈。

请不要以为我打算随机设置这些值。我知道必须先分配内存。

对于那些喜欢给出有时会出现在 SO 上的完美答案的人,我想问一下我将如何制作一个函数来将成员推送到数组。同样,void 在这里会造成很多麻烦,请参阅:

void array_push(Array *a, void* element) {
  if (a->used == a->size) {
    a->size *= 2;
    a->array = (int *)realloc(a->array, a->size * sizeof(int));
  }
  /*array set expression*/ = *(element); //Error! Can't dereference void pointer. Size unknown!
}

但是必须有一个void* 参数,数组成员的大小将在运行时决定。所以我想知道如何将void* 转换为var_of_sizex*。那时,我会申请Array.elm_size,但我不知道这种灵活的变量类型。

【问题讨论】:

  • 您可以使用memcpy 将字节从输入复制到数组中的适当位置,使用与array_get 中相同的偏移量计算。
  • 不应该 a->useda->size
  • 事实上,a->useda->length,但感谢您指出了混淆,我会纠正它。是的,mempcpy 正是我没有想到的——我想它会解决我的问题。
  • +1 用于开始您的问题... 在发现 C 没有模板之后... :-)
  • array_push 应在必要时重新分配数组,然后调用 array_set

标签: c arrays void-pointers


【解决方案1】:
void array_set(Array *a, size_t offset, void* new_value) {
    if (offset >= a->size) {
        fprintf(stderr, "Error: assigning beyond end of array.\n");
        exit(1);
    }
    memcpy(((char*)(a->array)) + offset*a->elm_size, new_value, a->elm_size);
}

根据您的操作方式,您可能希望将realloc 逻辑从array_push 移动到array_set。所以array_set 会自动增加数组,而不是在你尝试写超出结尾时报告错误。

【讨论】:

  • 你可能想确保他坚持使用 C 并使用 printf :P
  • 哦,我又遇到了一件事情——如何将常量转换为 void 指针,以推送常量值(这可能仅在调试期间需要,但仍然需要)?
  • 我不认为你可以。常量不一定有地址,因为编译器可能会将它们转换为即时数据或将它们存储在寄存器中。
猜你喜欢
  • 2019-03-14
  • 1970-01-01
  • 2011-08-13
  • 1970-01-01
  • 2021-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多