c - 动态分配多维浮点数组的正确方法是什么? Valgrind 错误

c - Which is the correct way to dynamically allocate multidimensional float arrays? Valgrind error

我正在用 C 实现一个 K-means 算法。它在大多数情况下都运行良好,但是使用 Valgrind 调试它告诉我我正在做一个 "Invalid read of size 8 - Invalid write of size 8 - Invalid read of size 8" 使用 '''memcpy''' 开头。我认为问题不在那里,但我为多维浮点数组元素分配了一个值,该内存在某些时候使用带有 for 循环的“'malloc'”动态分配。因为 Valgrind 也告诉 "Address 0x572c380 is 0 bytes after a block of size 80 alloc'd".

我尝试将我分配的字节数加 1,因为我认为可能“'malloc'”"needed" 更多内存来完成它的工作,但没有任何改变.我知道这可能是一个基本错误,但我对这门语言还很陌生,在我的课程中它没有解释任何东西,所以 "technical"。我试图搜索错误的答案和解释,但我只发现了“'char'”数组的问题,而那些我理解的函数“'strcpy'”可以解决问题。浮点数组呢?这是第一次使用'''memcpy'''。

以下是引发这些 Valgrind 消息的代码片段。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void main(){
    FILE* fp; //used to open a .txt file to read
    char buf[100];
    float ** a;
    char * s;
    int i;
    int j;
    int rows = 10;
    fp = fopen("data.txt", "r");
    if(fp==NULL){
        perror("Error at open file.");
        exit(1);
    }

    a = (float**) malloc(rows*sizeof(float*));
    for(i=0; i<rows; i++){
        s = fgets(buf, 100, fp); //reading .txt file
        if (s==NULL){
            break;
        }
        a[i] = malloc(dim*sizeof(float));
        a[i][0] = atof(strtok(s, ","));
        for(j=1; j<dim; j++){
            a[i][j] = atof(strtok(NULL,","));  //save as float value the                token read from a line in file, for example, from line "1.0,2.0,3.0" as first line -> get a[0][1] = 2.0
        }
    }
    fclose(fp);

    m = (float**) malloc(rows*sizeof(float*));
    for (i=0; i<rows; i++){
        m[i]=malloc(dim*sizeof(float)); //not initialized
    }

    memcpy(m, a, rows*dim*sizeof(float));
}

有人能帮我理解为什么它有效但 Valgrind 会引发这些错误消息吗?

您首先分配了一个 float* 数组, 然后 分配了多个 float 数组,因此您的最后一个 memcpy(m, a, rows*dim*sizeof(float)) 复制了一个数组float*(指向 float 的指针)指向另一个,但使用 rows * dim 浮点数,@SomeProgrammerDude 正确地指出了这一点。那会复制 pointers,而不是 values.

此外,正如@xing 所指出的,您正在分配 rows 但使用 righe (您没有显示)。这可能是问题的原因。

我建议在第一行立即分配整个数组,然后让所有其他行指向足够的行:

a = malloc(rows * sizeof(float*));
a[0] = malloc(dim * rows * sizeof(float)); // Allocate the whole matrix on row #0
for (i = 1; i < rows; i++) {
    a[i] = a[0] + i * dim; // sizeof(float) automatically taken into account as float* pointer arithmetics
}
...
m = malloc(rows * sizeof(float*));
m[0] = malloc(dim * rows * sizeof(float));
memcpy(m[0], a[0], dim * rows * sizeof(float));

(当然添加 NULL 检查)