【问题标题】:c - Which is the correct way to dynamically allocate multidimensional float arrays? Valgrind errorc - 动态分配多维浮点数组的正确方法是什么? Valgrind 错误
【发布时间】:2019-06-08 18:46:27
【问题描述】:

我在 C 中实现了一个 K-means 算法。它在大多数情况下运行良好,但使用 Valgrind 调试它告诉我我正在执行“8 大小的无效读取 - 8 大小的无效写入 - 无效在开头使用 '''memcpy''' 读取大小为 8"。我认为问题不存在,但是我为多维浮点数组元素分配了一个值,该内存是使用 '''malloc''' 动态分配的,并在某些时候使用 for 循环。因为 Valgrind 还告诉“地址 0x572c380 在分配大小为 80 的块后为 0 个字节”。

我尝试将分配的字节数加 1,因为我认为可能“需要”更多内存来完成其工作,但没有任何改变。我知道这可能是一个基本错误,但我对这门语言还是很陌生,而且在我的课程中,它并没有解释任何如此“技术性”的东西。我试图搜索错误的答案和解释,但我只发现了 '''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 会引发这些错误消息吗?

【问题讨论】:

  • 请逐字逐句显示 valgrinds,并以文本形式完整显示。
  • 另外请提供minimal reproducible example
  • memcpy 调用确实没有做你显然认为它做的事情。它从源进行逐字节复制,这是一个 shallow 复制。
  • 对不起,我已经编辑了:没有righe变量,只有rows
  • @Someprogrammerdude 你能解释一下memcpy的正确用法吗,在这种情况下?我应该在m[i][j] 中使用for 循环来memcpy a[i][j] 中的每个浮点数还是同样的问题?

标签: c pointers malloc valgrind


【解决方案1】:

您首先分配float* 的数组,然后分配float 的几个数组,因此您的最后一个memcpy(m, a, rows*dim*sizeof(float)) 复制float* 的数组(指向float 的指针)到另一个,但使用@SomeProgrammerDude 正确指出的rows * dim floats。这将复制指针,而不是

另外,正如@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检查)

【讨论】:

  • 正如我在之前的评论中所说,没有righe 变量,只有rows(它只是变量名称的翻译,更容易理解!啊哈)。无论如何,谢谢,因为这个解决方案也解决了代码其他点的问题!一开始没看懂其中的区别,可能是对指针的理论没理解好。谢谢!
  • @erika 我猜你在编辑中错过了一个righe(它仍然显示在for 循环中)。我还翻译了我的代码,然后将其粘贴到这里,这样我就明白了:p 指针是我喜欢 C 的 特性,所以真的值得花一些时间来完全理解它,因为它是 真的 功能强大(也容易出错。但正如他们所说的“具有强大的能力......”;))
  • 哦,你是对的!谢谢@Matthieu!我肯定会花更多的时间在他们身上......因为我相信有一天我会承担“重大责任”;)
猜你喜欢
  • 2011-07-19
  • 2013-10-14
  • 2011-02-26
  • 2013-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-07
  • 1970-01-01
相关资源
最近更新 更多