【问题标题】:Problem mallocing a 2d array分配二维数组的问题
【发布时间】:2011-02-03 01:22:08
【问题描述】:

我还是 C、malloc 和所有爵士乐的新手,所以我决定写这篇文章来学习更多技能。这个想法是,我正在从文件中读取一堆整数并将它们放入矩阵(二维数组)中。文件的开头说明有多少行和列,因此它会读取这些数字并使用 malloc 设置二维数组。

int read_matrix(FILE *mat, int ***Z, int *x, int *y) 
{
    int i = 0;
    int x_temp = 0;
    int y_temp = 0;

    if (fscanf(mat, "%d %d", &(*x), &(*y)) == EOF){
        printf("File is not big enough to contain a matrix\n");
        return -1;
    }

    printf("About to malloc %d\n", *x);

    *Z = (int**) malloc(*x * sizeof(int*));
    while (i < *x) {
        printf("mallocing %d\n", i);
        *Z[i] = (int*) malloc(*y * sizeof(int));
        printf("malloced\n");
        ++i;
    }

    printf("Malloc complete\n");

    /*Other unimportant code*/
}

输出如下:

About to malloc 3 
mallocing 0 
malloced 
mallocing 1
Segmentation fault

所以它在 Z 中除了一个 int** 之外没有分配任何东西。我认为?

我对 C 很陌生,所以我不确定我是否犯了一些小错误,或者我是否真的把整个事情都搞错了。有什么想法吗?谢谢!

【问题讨论】:

  • &amp;(*x)x 相同。
  • 啊啊啊是啊,忽略 &(*x) 因为我是个白痴哈哈

标签: c pointers malloc


【解决方案1】:

[] 运算符比一元 * 运算符绑定得更紧密。尝试将 *Z[i] 更改为 (*Z)[i] 并查看您的代码是否正常运行。

附带说明一下,在 C 中,将 (sizex*sizey) 大小的单个数组 malloc 用于矩阵然后将其索引为 arr[x*sizey + y] 或 arr[y*sizex + X]。这更接近于模仿语言对静态数组所做的事情(例如,如果您声明 int foo[10][10],则所有 100 个 int 在内存中都是连续的,并且没有存储 10 个 int* 的列表。

【讨论】:

  • Woot,做到了,malloc 完成了(新的,之后有一个新的 seg 错误)。谢谢!时间到了,我会把你标记为答案
  • 请注意,您可以 malloc 一个单一的二维数组,并且仍然保持与 int foo[10][10] 相同的语法,只要除了第一个维度之外的所有维度都是整数常量:int (*foo)[10] = malloc(10 * sizeof foo[0]);
  • @cost (& @caf):如果你有一个符合 C99 的编译器,则没有一个维度必须是编译时间常数,这被称为可变长度数组,VLA,指针分别是这样称为可变修改型(VM)。这在堆栈上分配时有时会令人不悦,但如果您像在堆上使用 malloc 那样分配它,这是处理动态大小的最简单解决方案。
【解决方案2】:

我同意 Walter 和 AndreyT 的观点。这只是一些附加信息。

请注意,您可以只使用两个 malloc() 调用,而不是 *x + 1 - 一个大块用于 ints 本身,一个用于行索引。

*Z = malloc(*x * sizeof (*Z)[0]);
(*Z)[0] = malloc(*x * *y * sizeof (*Z)[0][0]);
for (i = 1; i < *x; i++) {
    (*Z)[i] = (*Z)[0] + i * *y;
}

【讨论】:

  • 好收获!请注意,这会更改合同,因为调用者必须知道只调用两个 free
【解决方案3】:

正如沃尔特在他的回答中正确指出的那样,它应该是 (*Z)[i] = ...,而不是 *Z[i] = ...

最重要的是,我建议摆脱源代码中存在的取消引用/类型转换地狱。不要转换malloc 的结果。不要在sizeof 下使用类型名称。表示如下

 *Z = malloc(*x * sizeof **Z);
 ...
 (*Z)[i] = malloc(*y * sizeof *(*Z)[i]);

将使您的代码与类型无关并且更具可读性。

另一个问题是到底是什么让你在fscanf 中使用&amp;(*x)。这是某种奇怪的编码标准吗?

【讨论】:

  • 它也会让你的代码变成not compile as C++所以我不推荐这个。
  • 你的意思是如果我转换 malloc 的结果它不会在 C++ 上编译?
  • &(*x) 是你在编码的时候没有好好思考的时候正在做的那种编码,呵呵...
  • 其他方式。要在 C++ 上编译,您必须强制转换 malloc 的结果,因为void* 只能隐式转换为纯 C 中的其他指针。
  • @Walter Mundt:首先,这是一个 C 问题。 C++ 与它有关。其次,C-C++ 可交叉编译的问题主要与头文件内容有关,这意味着它对函数体(除了内联函数)很少有影响。基本上,除了宏之外,不封装 malloc 的问题永远不会作为 C-C++ 交叉编译问题出现。
猜你喜欢
  • 2021-01-02
  • 2011-05-22
  • 1970-01-01
  • 1970-01-01
  • 2020-01-14
  • 2020-09-05
  • 2012-09-13
相关资源
最近更新 更多