calloc 后无法修改 C 中的数组

Unable to modify array in C after calloc'd

我对 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 在 multiply(...) 中调用 doubleStorage(...) 函数后告诉我,我收到 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 函数需要将数组大小加倍时,您将移动 want/need 的值以更改为新的 'back' 的数组。

因此,(*array)[i](或任何其他在 [] 中使用 i 值的表达式)引用的元素 将是错误的!当 i 为零并且您尝试访问 (*array)[i - 1] 时,Valgrind 会注意到这一点;但是,对于 every 引用使用 i after 这样的大小更改也是错误的。

要解决此问题,请设置一个新变量 'monitor' if/when 大小已更改。在下面的代码中(当我测试它时,它按预期工作),这被称为 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 的地方),代码可以做得更多 'efficient'(也许),但我已经尝试过保持变化清晰明了。

随时要求进一步澄清and/or解释。