如何获取向量的第i个元素
How to get the i-th element of vector
我想获取void*的第i个元素。我知道它是 void 类型,我必须给它一个特定的数据类型。这背后的想法是它应该适用于不同的数据类型。如果我对这个问题的看法是正确的,我该如何实施?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX_STR_LEN 64
typedef struct Vector {
void *data;
size_t element_size;
size_t size;
size_t capacity;
} Vector;
// Allocate vector to initial capacity (block_size elements),
// Set element_size, size (to 0), capacity
void init_vector(Vector *vector, size_t block_size, size_t element_size){
vector->data = (void*) malloc(block_size * element_size); // i am questioning whether this is correct
vector->element_size = element_size;
vector->size = 0;
vector->capacity = block_size * element_size;
}
void resize(Vector *vector, size_t new_size){
void *data2 = (void*) malloc(new_size * vector->element_size);
int i=0;
memmove(data2,vector->data,new_size * vector->element_size);
vector->data = data2;
if(new_size > vector->size){
for(i=vector->size-1;i<new_size;i++){
vector->data[i]=0; // here is the problem
}
}else{
vector->size = new_size;
}
vector->capacity = new_size*vector->element_size;
}
您的矢量函数可以不能 [有意义地]使用索引或指针语法访问数组数据,例如:
vector->data[i]=0;
那是因为它是一个 void *
指针,但更重要的是,如果 element_size
是(例如)8,这是否意味着 vector->data
指向一个 double
或unsigned long long
?
只有您函数的 调用者 可以执行此操作:
Vector *vec = calloc(1,sizeof(*vec));
init_vector(vec,100,sizeof(double));
double *ptr = vec->data;
for (size_t idx = 0; idx < vec->size; ++idx)
ptr[idx] = idx;
当您扩展 resize
中的数组时,您只能 mem*
个函数。
将您的 for
循环替换为:
memset(&vector->data[vector->size * vector->element_size],0,
(new_size - vector->size) * vector->element_size);
更新:
还有一些问题。尽管您 可以 让 capacity
成为 字节 计数,但更常见的是 元素 计数(就像 size
)。
当我创建这样的动态 array/vector objects/functions 时,我通常 而不是 resize
对元素进行初始化。
那是因为它 [真的] 不知道如何初始化元素。对于 c++
向量, 构造函数 知道。
所以,如果我们希望resize
[和init_vector
]这样做,我们需要为此提供一个函数指针。
这里有一些重构代码来说明:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX_STR_LEN 64
typedef struct Vector Vector;
typedef void (*vecinit_p)(Vector *,size_t idx,size_t count);
struct Vector {
void *data; // pointer to array data
size_t element_size; // number of bytes in an array element
size_t capacity; // number of elements allocated
size_t size; // number of elements in use
vecinit_p initfnc; // pointer to init function
};
// vecptr -- get pointer to i'th element
void *
vecptr(Vector *vec,size_t idx)
// idx -- index of desired element
{
void *ptr;
idx *= vec->element_size;
ptr = vec->data;
ptr += idx;
return ptr;
}
// init_data -- initialize data elements
void
init_data(Vector *vec,size_t idx,size_t count)
// idx -- starting index
// count -- number of elements to initialize
{
void *ptr = vecptr(vec,idx + 0);
void *end = vecptr(vec,idx + count);
memset(ptr,0,end - ptr);
}
// Allocate vector to initial capacity (block_size elements),
// Set element_size, size (to 0), capacity
void
init_vector(Vector *vec, size_t block_size, size_t element_size,vecinit_p fnc)
// block_size -- number of elements
// element_size -- number of bytes in a single element
{
size_t new_len = block_size * element_size;
vec->data = calloc(1,new_len);
vec->element_size = element_size;
vec->size = 0;
vec->capacity = block_size;
// provide a "default" constructor
if (fnc == NULL)
fnc = init_data;
vec->initfnc = fnc;
fnc(vec,0,vec->capacity);
}
// resize -- resize the array
void
resize(Vector *vec, size_t new_cap)
// new_cap -- desired new capacity
{
// get byte length
size_t new_len = new_cap * vec->element_size;
void *data2 = malloc(new_len);
if (data2 == NULL) {
perror("malloc");
exit(1);
}
vec->data = data2;
// get old capacity and set new capacity
size_t old_cap = vec->capacity;
vec->capacity = new_cap;
// initialize new elements
if (new_cap > old_cap)
vec->initfnc(vec,old_cap,old_cap - new_cap);
}
// vecpush -- append element to array
// RETURNS: pointer to "pushed" element
void *
vecpush(Vector *vec)
{
// increase array capacity if needed
if (vec->size >= vec->capacity)
resize(vec,vec->capacity + 10);
// point to element
void *ptr = vecptr(vec,vec->size++);
return ptr;
}
C 是一种为肾上腺素瘾君子准备的语言。它总是类似于自由攀登、跳伞和一级方程式赛车。
防御性编程并不是针对调用者各种“破坏”的完美保护,但总比没有好。
下面的代码正是本着这种精神。它无法检测到所有可能出错的地方(比如损坏的内存或者向量中的数据指针是否只是一个随机值),但它展示了如果用该语言编写应该使用的最少防御性编程。
C 具有“指针运算”这一特性。所以,如果你有uint16_t * p = 1000;
并且您访问 p + 1
,它正在访问 1002
(即 p + sizeof(uint16_t) * 1
)。
这就是诀窍,您如何访问此类非常弱类型的向量中的元素。您将 void 指针转换为字节指针(作为示例),然后使用指针算法。
void* at(Vector* v, size_t index) {
// C needs manual sanity checks for the preconditions
if (NULL == v) return NULL;
if (v->size <= index) return NULL;
if (NULL == v->data) return NULL;
// now we can be (reasonably, as much as we can tell) sure, we did not get garbage as arguments...
return ((char*)(v->data)) + index * v->element_size;
}
我想获取void*的第i个元素。我知道它是 void 类型,我必须给它一个特定的数据类型。这背后的想法是它应该适用于不同的数据类型。如果我对这个问题的看法是正确的,我该如何实施?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX_STR_LEN 64
typedef struct Vector {
void *data;
size_t element_size;
size_t size;
size_t capacity;
} Vector;
// Allocate vector to initial capacity (block_size elements),
// Set element_size, size (to 0), capacity
void init_vector(Vector *vector, size_t block_size, size_t element_size){
vector->data = (void*) malloc(block_size * element_size); // i am questioning whether this is correct
vector->element_size = element_size;
vector->size = 0;
vector->capacity = block_size * element_size;
}
void resize(Vector *vector, size_t new_size){
void *data2 = (void*) malloc(new_size * vector->element_size);
int i=0;
memmove(data2,vector->data,new_size * vector->element_size);
vector->data = data2;
if(new_size > vector->size){
for(i=vector->size-1;i<new_size;i++){
vector->data[i]=0; // here is the problem
}
}else{
vector->size = new_size;
}
vector->capacity = new_size*vector->element_size;
}
您的矢量函数可以不能 [有意义地]使用索引或指针语法访问数组数据,例如:
vector->data[i]=0;
那是因为它是一个 void *
指针,但更重要的是,如果 element_size
是(例如)8,这是否意味着 vector->data
指向一个 double
或unsigned long long
?
只有您函数的 调用者 可以执行此操作:
Vector *vec = calloc(1,sizeof(*vec));
init_vector(vec,100,sizeof(double));
double *ptr = vec->data;
for (size_t idx = 0; idx < vec->size; ++idx)
ptr[idx] = idx;
当您扩展 resize
中的数组时,您只能 mem*
个函数。
将您的 for
循环替换为:
memset(&vector->data[vector->size * vector->element_size],0,
(new_size - vector->size) * vector->element_size);
更新:
还有一些问题。尽管您 可以 让 capacity
成为 字节 计数,但更常见的是 元素 计数(就像 size
)。
当我创建这样的动态 array/vector objects/functions 时,我通常 而不是 resize
对元素进行初始化。
那是因为它 [真的] 不知道如何初始化元素。对于 c++
向量, 构造函数 知道。
所以,如果我们希望resize
[和init_vector
]这样做,我们需要为此提供一个函数指针。
这里有一些重构代码来说明:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX_STR_LEN 64
typedef struct Vector Vector;
typedef void (*vecinit_p)(Vector *,size_t idx,size_t count);
struct Vector {
void *data; // pointer to array data
size_t element_size; // number of bytes in an array element
size_t capacity; // number of elements allocated
size_t size; // number of elements in use
vecinit_p initfnc; // pointer to init function
};
// vecptr -- get pointer to i'th element
void *
vecptr(Vector *vec,size_t idx)
// idx -- index of desired element
{
void *ptr;
idx *= vec->element_size;
ptr = vec->data;
ptr += idx;
return ptr;
}
// init_data -- initialize data elements
void
init_data(Vector *vec,size_t idx,size_t count)
// idx -- starting index
// count -- number of elements to initialize
{
void *ptr = vecptr(vec,idx + 0);
void *end = vecptr(vec,idx + count);
memset(ptr,0,end - ptr);
}
// Allocate vector to initial capacity (block_size elements),
// Set element_size, size (to 0), capacity
void
init_vector(Vector *vec, size_t block_size, size_t element_size,vecinit_p fnc)
// block_size -- number of elements
// element_size -- number of bytes in a single element
{
size_t new_len = block_size * element_size;
vec->data = calloc(1,new_len);
vec->element_size = element_size;
vec->size = 0;
vec->capacity = block_size;
// provide a "default" constructor
if (fnc == NULL)
fnc = init_data;
vec->initfnc = fnc;
fnc(vec,0,vec->capacity);
}
// resize -- resize the array
void
resize(Vector *vec, size_t new_cap)
// new_cap -- desired new capacity
{
// get byte length
size_t new_len = new_cap * vec->element_size;
void *data2 = malloc(new_len);
if (data2 == NULL) {
perror("malloc");
exit(1);
}
vec->data = data2;
// get old capacity and set new capacity
size_t old_cap = vec->capacity;
vec->capacity = new_cap;
// initialize new elements
if (new_cap > old_cap)
vec->initfnc(vec,old_cap,old_cap - new_cap);
}
// vecpush -- append element to array
// RETURNS: pointer to "pushed" element
void *
vecpush(Vector *vec)
{
// increase array capacity if needed
if (vec->size >= vec->capacity)
resize(vec,vec->capacity + 10);
// point to element
void *ptr = vecptr(vec,vec->size++);
return ptr;
}
C 是一种为肾上腺素瘾君子准备的语言。它总是类似于自由攀登、跳伞和一级方程式赛车。 防御性编程并不是针对调用者各种“破坏”的完美保护,但总比没有好。
下面的代码正是本着这种精神。它无法检测到所有可能出错的地方(比如损坏的内存或者向量中的数据指针是否只是一个随机值),但它展示了如果用该语言编写应该使用的最少防御性编程。
C 具有“指针运算”这一特性。所以,如果你有uint16_t * p = 1000;
并且您访问 p + 1
,它正在访问 1002
(即 p + sizeof(uint16_t) * 1
)。
这就是诀窍,您如何访问此类非常弱类型的向量中的元素。您将 void 指针转换为字节指针(作为示例),然后使用指针算法。
void* at(Vector* v, size_t index) {
// C needs manual sanity checks for the preconditions
if (NULL == v) return NULL;
if (v->size <= index) return NULL;
if (NULL == v->data) return NULL;
// now we can be (reasonably, as much as we can tell) sure, we did not get garbage as arguments...
return ((char*)(v->data)) + index * v->element_size;
}