c-能够打印从未初始化的指针数组到结构的预期结果-混乱



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

此外,我已经读到,使用malloc返回的指针,我可以在指针后面使用[index],并在分配的内存上迭代。我假设这个功能是利用它的类型乘以某个值的事实,它会自动进行除法,以知道这个内存块是如何分割的,从而知道前进到下一个索引的距离。但我仍然很困惑,为什么我在最后一个for循环中得到了预期的结果,而我还没有初始化或将这些指针指向任何特定的东西。

我知道,如果我添加**并将更改为->,那么我可以直接对这些指针进行操作,但现在有了代码,我可以使用。操作员访问结构成员。那么,如果nums3malloc行中没有**,那么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: %dn", n.num1);
    n.num2 = 6;
    printf("n.num2: %dn", n.num2);
    n.num3 = 7;
    printf("n.num3: %dn", 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("%dn", n[i]);
    }
    free(n);
}

运行此代码的结果:

杰森smith@jasonS-pc~/src/c$/a.exe01.2.3.4

杰森smith@jasonS-pc~/src/c$

问题:

  1. 当n是malloc返回的指针时,n[i]是如何工作的?C如何知道如何处理n[i]?C如何知道如何到达n[i+1]?它是否查看被调用的sizeof(),并除以它被相乘的次数,然后使用该结果来知道下一个单元格从哪里开始?

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

我知道这不是正确的方法,你们都提供了很好的信息,但我仍然困惑于为什么要编译这些代码。这对我来说毫无意义。

通常,如果您访问内存不正确,您就不能期望任何东西。你不能指望得到正确的答案,也不能指望得到错误的答案。你不能指望你的程序崩溃,也不能指望它运行。再说一遍,它可以做任何事情。

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

// 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,这是不可保证的。)

您说您没有分配足够的空间,因为sizeof(struct number)=12而sizeof(struct number*)=8

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

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

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

希望这对有帮助

最新更新