A C(***void类型)走,为什么地址不相等

问题描述 投票:0回答:1

我做了一个测试: 首先我有一个 C 函数 变量初始化: numRows、numCols 和 numDeps 分别初始化为值 3、5 和 2。 这些变量表示 3D 数组的维度。 内存分配: 内存被分配给代表行的指针(特征)数组。 对于每一行,都会为指针数组 (features[i]) 分配内存。 对于 2D 数组中的每个元素,都会为双精度数组 (features[i][j]) 分配内存。 3D 数组 (features[i][j][k]) 中每个双精度型的内存均使用 k 值进行初始化。 打印地址: 嵌套循环迭代 3D 数组中的每个元素。 每个元素的地址 (features[i][j][k]) 使用 %p 格式说明符打印。 返回结果: 打印整个 3D 数组(特征)的地址。 3D 数组被转换为 void*** 并返回。

void*** data13feature() {
    int numRows = 3;  // Number of rows
    int numCols = 5;  // Number of columns
    int numDeps = 2;

    // Allocate memory for the array of pointers (rows)
    double*** features = (double***)malloc(numRows * sizeof(double**));

    // Allocate memory for each row (array of doubles)
    for (int i = 0; i < numRows; ++i) {
        features[i] = (double**)malloc(numCols * sizeof(double*));
        for (int j = 0; j < numCols; ++j) {
            features[i][j] = (double*)malloc(numDeps * sizeof(double));
            for (int k = 0; k < numDeps; ++k) {
                features[i][j][k] = k;
            }
        }
    }

    // Print the addresses of the array elements
    for (int i = 0; i < numRows; ++i) {
        for (int j = 0; j < numCols; ++j) {
            for (int k = 0; k < numDeps; ++k) {
                printf("%p ", (void*)&features[i][j][k]);
            }
            printf("\n");
        }
        printf("\n");
    }
    return (void***)features;
}

然后我使用cgo来运行func

func Data2featureWrapper4() {
    result := C.data13feature()
    typeOfMyVar := reflect.TypeOf(result)
    fmt.Printf("typeOfMyVar: %v\n", typeOfMyVar)
    fmt.Printf("%p\n", *result)
}

结果是

0x33289c0 0x33289c8 
0x33289e0 0x33289e8 
0x3328a00 0x3328a08 
0x3328a20 0x3328a28 
0x3328a40 0x3328a48 

0x3328a90 0x3328a98 
0x3328ab0 0x3328ab8 
0x3328ad0 0x3328ad8 
0x3328af0 0x3328af8 
0x3328b10 0x3328b18 

0x3328b60 0x3328b68 
0x3328b80 0x3328b88 
0x3328ba0 0x3328ba8 
0x3328bc0 0x3328bc8 
0x3328be0 0x3328be8 

typeOfMyVar: **unsafe.Pointer
0x3328990

为什么features[0][0][0]的开头不等于0x3328990

我测试了 **void 和 *void 我发现它是相等的。哪里错了? 3D指针的起始位置不应该是[0][0][0]元素的地址吗?如果我想使用 go 反向解析这个 3D 数组,我该怎么办?

go pointers cgo
1个回答
0
投票

问题是你只取消引用结果一次,而你应该取消引用它两次。通过查看我们正在比较的两个事物的类型,我们可以发现这是一个问题:

&features[i][j][k]

以上是

double*
。在你的 go 代码中:

*result

这是一个

*unsafe.Pointer
(从技术上讲是一个双指针,不安全。指针算作指针!)。如果您考虑一下要分配的内容的结构,就会发现这是有道理的:

[行] => [列] => [深度]

当您取消引用 result 一次时,您得到的是指向列数据的指针。如果您再次取消引用它,您将得到您想要的,数组数据。

PS,分配形状保持不变的大内存块的一种更有效的方法是在一个大块中完成所有操作。我可以将你的 C 代码重写为:


void* data13feature() {
    int numRows = 3;  // Number of rows
    int numCols = 5;  // Number of columns
    int numDeps = 2;

    // Allocate memory for the array of pointers (rows)
    double* features = (double*)malloc(numRows * numCols * numDeps * sizeof(double));

    // Print the addresses of the array elements
    for (int i = 0; i < numRows; ++i) {
        for (int j = 0; j < numCols; ++j) {
            for (int k = 0; k < numDeps; ++k) {
                printf("%p ", (void*)&features[(i*numCols) + (j * numDeps) + k]);
            }
            printf("\n");
        }
        printf("\n");
    }

    return (void*)features;
}

现在您还会注意到,数据在内存中都是连续的,使其易于缓存(特别是对于大尺寸),并且只需要一次 malloc/free。

© www.soinside.com 2019 - 2024. All rights reserved.