【问题标题】:Able to Print Expected Results From Uninitialized Array of Pointers to Structures - Confused能够从指向结构的未初始化的指针数组打印预期结果 - 困惑
【发布时间】:2016-08-04 04:55:45
【问题描述】:

我的问题是 nums3 数组以及为什么最后一个 for 循环实际上会打印预期结果。据我了解, nums3 数组包含指向结构的指针数组,但这些指针尚未初始化为结构的任何特定实例。但是在这个 for 循环中,我可以分配值并查看预期的结果显示。

另外,我已经阅读了 malloc 返回的指针,我可以在指针之后使用 [index] 并遍历分配的内存。我假设这个特性使用了一个事实,它有一个类型乘以某个值,它会自动进行除法以了解这个内存块是如何分割的,因此可以推进到下一个索引的距离。但是当我没有初始化或将这些指针指向任何特定的东西时,我仍然对为什么在最后一个 for 循环中得到预期的结果感到困惑。

我知道如果我要添加 ** 并将 更改为 -> 然后 我可以直接对这些指针进行操作,但是现在有了代码,我可以使用 .操作员访问结构成员。那么,如果没有 nums3 malloc 行中的 **,从 malloc 返回的指针究竟返回了什么?

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

#define ARRAY_MAX 5

int main(void)
{
    struct number {
        int num1;
        int num2;
        int num3;
    };

    struct number n;
    n.num1 = 5;
    printf("n.num1: %d\n", n.num1);
    n.num2 = 6;
    printf("n.num2: %d\n", n.num2);
    n.num3 = 7;
    printf("n.num3: %d\n", n.num3);

    struct number nums1[5];

    struct number* nums2 = malloc(sizeof(struct number) * ARRAY_MAX);
    struct number* nums3 = malloc(sizeof(struct number*) * ARRAY_MAX);

    int x;
    for(x = 0; x <= 5; x++) {
        nums1[x].num1 = x;
        nums1[x].num2 = x;
        nums1[x].num3 = x;
    }

    int y;
    for(y = 0; y <= ARRAY_MAX; y++) {
        nums2[y].num1 = x;
        nums2[y].num2 = x;
        nums2[y].num3 = x;
    }

    for(y=0; y<=ARRAY_MAX; y++) {
        nums3[y].num1 = y;
        nums3[y].num2 = y;
        nums3[y].num3 = y;
        printf("%d ", nums3[y].num1);
        printf("%d ", nums3[y].num2);
        printf("%d \n", nums3[y].num3);
    }

这是我的问题的一个更简单的测试用例:

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

#define MAX 5

int main(void)
{
    struct number {
        int num1;
    };

    struct number* n = malloc(sizeof(struct number*) * MAX);

    int i;
    for(i=0; i<MAX; i++) {
        n[i].num1 = i;
        printf("%d\n", n[i]);
    }

    free(n);

}

运行此代码的结果:

杰森·史密斯@jasonS-pc ~/src/c $ ./a.exe 0 1 2 3 4

杰森·史密斯@jasonS-pc ~/src/c $

问题:

  1. n[i] 如何与 n 作为 malloc 返回的指针一起工作? C 如何知道如何处理 n[i]? C 如何知道如何到达 n[i+1]?它是否查看正在调用的 sizeof() 并除以它乘以多少次并使用该结果来知道下一个单元格从哪里开始?

  2. 为什么 n[i].num1 = i;甚至编译?如果我所做的只是指定一个内存块,其中包含 x 个指向结构的指针的大小(指针将小于结构本身的大小),并且肯定没有初始化任何内容以指向该结构的实际实例.为什么这不是语法或其他编译器生成的错误? .nu​​m1 正在处理的单元格 n[i] 中存在什么? n[i] 现在不是只包含一个没有有效地址的指针,因为它尚未初始化吗?我们如何从那个到 n[i].num1 = i?执行“some memory address”.num1 = “some value”是否有效?

我知道这不是正确的方法,而且你们都提供了很好的信息,但我仍然对为什么这段代码可以编译感到困惑。这对我来说没有意义。

【问题讨论】:

  • 你期待什么样的结果?你知道什么是“未定义的行为”吗?
  • jasmith@lab:~/src/c$ ./a.out 第 1 行:0 0 0 第 2 行:1 1 1 第 3 行:2 2 2 第 4 行:3 3 3 第 5 行:4 4 4 第 6 行: 5 5 5 jasmith@lab:~/src/c$ 这些显示的值对应于最后一个 for 循环中的 y 值。我确实知道意外行为,但这对我来说看起来像是预期的行为。我看不出我怎么能做 nums3[y].num1 这就是为什么我问我实际上从那个 malloc 的内存块指针中得到了什么而不做 **。
  • 你说“我的问题是......实际上打印了预期的结果”。如果这是一个问题,那么您真的希望它打印其他内容。你期待什么样的意想不到的结果?
  • 我不确定我会在这里期待什么意外结果。我想除了我所看到的以外的任何东西。
  • 因此,如果预期结果是 1,2,3,那么 预期的意外结果将是 1,2,4 或 1,2,5 或 2,1, 3 或...但不是 1,2,3?为什么? 1、2、3有什么特别之处?

标签: c arrays pointers struct malloc


【解决方案1】:

一般来说,如果您不正确地访问内存,您将无法期待任何事情。你不能期望得到正确的答案,也不能期望得到错误的答案。你不能指望你的程序崩溃,也不能指望它运行。同样,它可以做任何事情。

这里的错误是你分配了一个指针数组,然后选择了错误的类型来保存结果。

// This is wrong!
struct number* nums3 = malloc(sizeof(struct number*) * ARRAY_MAX);

你想要这个:

struct number **nums3 = malloc(sizeof(struct number*) * ARRAY_MAX);
//            ^^

或者说真的,这种方式更好:

struct number **nums3 = malloc(sizeof(*nums3) * ARRAY_MAX);

然后你有一个(未初始化的)指针数组可以使用。例如,

for (int i = 0; i < ARRAY_MAX; i++) {
    nums3[i] = malloc(sizeof(*nums3[i]));
    nums3[i]->num1 = i;
    nums3[i]->num2 = i;
    nums3[i]->num3 = i;
}

或者...

for (int i = 0; i < ARRAY_MAX; i++) {
    nums3[i] = &nums2[i];
}

随心所欲。

(我们在这里假装malloc() 不会返回NULL,这是无法保证的。)

【讨论】:

  • 我知道使用双指针是去这里的方式。我只是想学习/理解为什么代码是错误的,以及发生了什么来得到我看到的结果。
  • 代码错误,因为您为指针数组分配了内存,但分配给了错误的类型。 malloc() 返回一个void *,所以它不会检查你是否犯了错误。
  • 好吧...我仍然不明白为什么我能够在最后一个 for 循环中执行 nums3[y].num1 = y。如果 nums3 的分配是错误的,那么 for 循环中的 .num1 怎么存在一个结构来作用呢?
  • 当你在 C 语言中出错时,最好的结果是程序退出或崩溃。在这种情况下,错误并没有发生导致崩溃。如果您在许多不同的计算机和编译器上尝试相同的程序,有时它可能会崩溃,有时它可能会工作。这就是 C 语言的危险,即使你的程序是错误的,它也可能看起来可以工作。
  • 可以这样想:你向malloc()要了一张纸,但你要的纸太小了。由于您认为纸张更大,因此您最终在桌子上写字。没有人阻止你在桌子上写字。如果你一直写下去,最终你的铅笔会掉到桌子的边缘,你会摔倒(摔倒)。然而,你很不幸,这并没有发生。
【解决方案2】:

你说你没有分配足够的空间是正确的sizeof(struct number) = 12 而sizeof(struct number*) = 8

Malloc 根据您询问的大小找到空闲内存,并且(如果成功)返回指向第一个地址的指针(这是虚拟内存)。如果您超过了创建的大小,您将进入意外行为的领域。这意味着您要么能够从内存中写入和读取数据,要么不能,即使您设法做到这一点,您也可能会意外覆盖内存中存储其他数据的区域。

在这种情况下,尽管打印通过并没有特殊行为,但当您尝试free(nums3) 时,您会收到错误。

此外,如果您将 nums2 和 nums3 声明的顺序颠倒并在 nums3 循环后打印 nums2,您可能会看到这种数据损坏。

希望对你有帮助

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-10-19
    • 2010-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多