为什么 C 在指针运算期间抽象掉 sizeof?
Why does C abstract away sizeof during pointer arithmetic?
我在 C 中从头开始重新创建一个数组,实现了追加、插入等常用功能。我完成了大部分工作,但是当我尝试 运行 我的“插入”功能时索引 1(而不是 0),我在访问最后一个元素的“for 循环”输出打印期间开始出现段错误。我只使用循环进行打印,否则为了调整大小和移动我使用内存管理函数,如 memmove 和 strdup 和 realloc。我还注意到它覆盖了索引 1,而不是像我从 memmove 期望的那样滑动数组。
我发现我在做指针运算时出错了,每次都使用 sizeof 运算符,但这让我开始思考,为什么 C 在 malloc() 之外将它从我们那里抽象出来?如果我们想用小于一个整数的单位进行算术运算,我们该怎么做?我们会将该值复制到另一个变量并在那里执行吗,会有这样的用例吗?
有趣的是,我已经这样做了几个月,没有遇到任何问题,事实上我曾发誓这是必要的,但也许我没有想清楚。也许那是 malloc 或 realloc 或其他东西,或者也许我只是运气好。
这是我正在谈论的一些代码(运行良好):
void arr_insert(Array *arr, char *element, int index)
{
// Throw an error if the index is greater than the current count
if (index > arr->count)
{
fprintf(stderr, "Index out of range");
printf("Index out of range in arr_insert\n");
return;
}
// Resize the array if the number of elements is over capacity
if (arr->count == arr->capacity) resize_array(arr);
// Move every element after the insert index to the right one position
memmove(arr->elements + ((index + 1)), arr->elements + ( index), (arr->count - index) * sizeof(char *));
// Copy the element (hint: use `strdup()`) and add it to the array
*(arr->elements + (index)) = strdup(element);
// Increment count by 1
arr->count++;
这是我之前失败的那一行
memmove(arr->elements + (sizeof(char *) * (index + 1)), arr->elements + (sizeof(char *) * index), (arr->count - index) * sizeof(char *));
- 因为它使数组索引起作用(请记住,
a[i]
只是 *(a+i)
。)
- 因为它确保指针运算的结果始终是针对该类型正确对齐的指针。
- 如果您想直接将其作为一系列字节进行操作,您可以将指针转换为指向
void *
(这就是 memcpy
和 write
等函数的工作方式),并且你可以把它投回去(malloc
,realloc
)。但是做类似 (int *)((void *)x + 1)
(其中 sizeof(int) != 1
)的事情 不 保证做任何有用的事情甚至表现一致。
不要使用这些怪物,而是使用一些临时变量来使代码更具可读性。
字节级的指针运算:
char *dest = (char *)arr->elements + sizeof(char *) * (index + 1);
char *src = (char *)arr->elements + sizeof(char *) * index;
memmove(dest, src, (arr->count - index) * sizeof(char *));
我在 C 中从头开始重新创建一个数组,实现了追加、插入等常用功能。我完成了大部分工作,但是当我尝试 运行 我的“插入”功能时索引 1(而不是 0),我在访问最后一个元素的“for 循环”输出打印期间开始出现段错误。我只使用循环进行打印,否则为了调整大小和移动我使用内存管理函数,如 memmove 和 strdup 和 realloc。我还注意到它覆盖了索引 1,而不是像我从 memmove 期望的那样滑动数组。
我发现我在做指针运算时出错了,每次都使用 sizeof 运算符,但这让我开始思考,为什么 C 在 malloc() 之外将它从我们那里抽象出来?如果我们想用小于一个整数的单位进行算术运算,我们该怎么做?我们会将该值复制到另一个变量并在那里执行吗,会有这样的用例吗?
有趣的是,我已经这样做了几个月,没有遇到任何问题,事实上我曾发誓这是必要的,但也许我没有想清楚。也许那是 malloc 或 realloc 或其他东西,或者也许我只是运气好。
这是我正在谈论的一些代码(运行良好):
void arr_insert(Array *arr, char *element, int index)
{
// Throw an error if the index is greater than the current count
if (index > arr->count)
{
fprintf(stderr, "Index out of range");
printf("Index out of range in arr_insert\n");
return;
}
// Resize the array if the number of elements is over capacity
if (arr->count == arr->capacity) resize_array(arr);
// Move every element after the insert index to the right one position
memmove(arr->elements + ((index + 1)), arr->elements + ( index), (arr->count - index) * sizeof(char *));
// Copy the element (hint: use `strdup()`) and add it to the array
*(arr->elements + (index)) = strdup(element);
// Increment count by 1
arr->count++;
这是我之前失败的那一行
memmove(arr->elements + (sizeof(char *) * (index + 1)), arr->elements + (sizeof(char *) * index), (arr->count - index) * sizeof(char *));
- 因为它使数组索引起作用(请记住,
a[i]
只是*(a+i)
。) - 因为它确保指针运算的结果始终是针对该类型正确对齐的指针。
- 如果您想直接将其作为一系列字节进行操作,您可以将指针转换为指向
void *
(这就是memcpy
和write
等函数的工作方式),并且你可以把它投回去(malloc
,realloc
)。但是做类似(int *)((void *)x + 1)
(其中sizeof(int) != 1
)的事情 不 保证做任何有用的事情甚至表现一致。
不要使用这些怪物,而是使用一些临时变量来使代码更具可读性。
字节级的指针运算:
char *dest = (char *)arr->elements + sizeof(char *) * (index + 1);
char *src = (char *)arr->elements + sizeof(char *) * index;
memmove(dest, src, (arr->count - index) * sizeof(char *));