c - calloc'd后无法修改C中的数组
问题描述
我对 C 编程还是很陌生。这是一个程序,它接收一个由指针(int * 而不是 int[])组成的 int 数组,并将其中的每个 int 乘以 2。
任何大于 10 的 int 都会结转附加值,并且如果需要,数组的大小将加倍。所以,如果我输入
{9, 0, 4, 8},
它应该产生
{0, 0, 0, 1, 8, 0, 9, 6}
但是这个程序产生了 {0, 0, 0, 0, 9, 0, 4, 8}。
Valgrind 在调用doubleStorage(...)
函数后告诉我multiply(...)
,我收到一个 InvalidRead 和 InvalidWrite 警告,我认为这是问题所在,在我调用数组以调整它的大小之后停止。但我不知道如何解决它。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int * doubleStorage(int ** array, int initialBlocks);
void printArray(int ** array, int blocks);
int * multiply(int ** array, int multiplier, int blocks);
int main() {
int sizeOfArr = 4 * sizeof(int);
int * arr = malloc(sizeOfArr);
arr[0] = 9;
arr[1] = 0;
arr[2] = 4;
arr[3] = 8;
arr = multiply(&arr, 2, 4);
printArray(&arr, 8);
free(arr);
return 0;
}
// multiplies each int in array by 2
// has a doubleStorage function to double array size if any multiplied int exceeds 10
int * multiply(int ** array, int multiplier, int blocks) {
int currentBlocks = blocks;
for (int i = 0; i < blocks; i++) {
if ((*array)[i] * multiplier > 10) {
if (i == 0) {
*array = doubleStorage(array, currentBlocks);
currentBlocks *= 2;
}
(*array)[i - 1] += 1; /* <-- Valgrind reports InvalidRead and InvalidWrite here*/
}
(*array)[i] = (*array)[i] * multiplier % 10;
}
return *array;
}
// doubles storage of array and relocates the original ints to the back
// doubleStorage({9, 0, 4, 8}, 4) => {0, 0, 0, 0, 9, 0, 4, 8}
int * doubleStorage(int ** array, int initialBlocks) {
int * more = realloc(*array, 2 * initialBlocks * sizeof(int));
if (more == NULL) {
free(*array);
} else {
*array = more;
for (int i = 0; i < initialBlocks; i++) {
int num = (*array)[i];
(*array)[i + initialBlocks] = num;
(*array)[i] = 0;
}
}
return *array;
}
// prints Array
void printArray(int ** array, int blocks) {
printf("Array: ");
for (int i = 0; i < blocks; i++) {
printf("%d ", (*array)[i]);
}
printf("\n");
}
解决方案
问题是,当(或如果)您的multiply
函数需要将数组大小加倍时,您会将想要/需要更改的值移动到数组的新“后部”。
(*array)[i]
因此,像这样的表达式(或任何其他使用i
内的值[]
)引用的元素将是错误的!当i
值为零并且您尝试访问时,Valgrind 会注意到这一点(*array)[i - 1]
;但是,在这种大小更改后使用的每个参考也是错误的。i
为了解决这个问题,如果/当大小发生变化时,设置一个新变量来“监控”。在下面的代码中(当我测试它时,它按预期工作),这被称为offset
:
int* multiply(int** array, int multiplier, int blocks)
{
int currentBlocks = blocks;
int offset = 0; // This will need to change if we double our array size.
for (int i = 0; i < blocks; i++) {
if ((*array)[i + offset] * multiplier > 10) {
if (i == 0) {
*array = doubleStorage(array, currentBlocks);
offset += currentBlocks; // Need to adjust offset following array doubling!
currentBlocks *= 2;
}
(*array)[i - 1 + offset] += 1; // Always add the offset to our "i" value...
}
(*array)[i + offset] = (*array)[i + offset] * multiplier % 10; // ...and here, also!
}
return *array;
}
通过使用第三个变量(例如,p
您设置的位置),可以使代码更“高效”(也许),p = i + offset
但我试图使更改保持清晰和明显。
随时要求进一步澄清和/或解释。
推荐阅读
- python-3.x - 未能构建解释器 TensorflowLite
- android - 如何通过单击 ImageView 在 MaterialCardView 顶部带来/设计导航抽屉布局
- javascript - 从 Mongoose 获取填充数据到客户端
- python - 对不同列之间的最高值输出进行分类
- jenkins - 通过命令提示符执行时,py.test' 不被识别为内部或外部命令、可运行程序或批处理文件
- loops - 如何在 Ansible uri 模块中使用正确的循环
- flutter - 当我多次访问屏幕时出现“状态不佳:流已被收听”
- android - 将 OSS Licenses Gradle Plugin 的主页指示器替换为关闭图标
- c++ - 根据 C++ 中同一列中 2 行的比较,删除 2D std::vector 中的列
- oracle - ORA-29283: invalid file operation: unexpected "LFI" error