c中结构指针内的双数组

Posted

技术标签:

【中文标题】c中结构指针内的双数组【英文标题】:Double array within a struct pointer in c 【发布时间】:2022-01-06 18:12:35 【问题描述】:

为什么这个双映射数组几乎可以工作,但不能?

我的代码如下:

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

typedef struct 
    double mapping [3][3];
 CoordinateMapperStr;
typedef CoordinateMapperStr * CoordinateMapper;

CoordinateMapper CoordinateMapper_Constructor(void)

    CoordinateMapper this = (CoordinateMapper) calloc (1, sizeof(CoordinateMapper));
    //return this; // <- I was missing this return, but still the rest worked the same


void CoordinateMapper_Initialize(CoordinateMapper this, double numb)

    for (int i=0; i < 3; i=i+1) 
        for (int j=0; j < 3; j=j+1) 
            this->mapping[i][j] = numb;
            printf("mapping(%d, %d) = %f\n", i, j, this->mapping[i][j]);
        
    


void CoordinateMapper_Print(CoordinateMapper this)

    for (int i=0; i < 3; i=i+1) 
        for (int j=0; j < 3; j=j+1) 
            printf("mapping(%d, %d) = %f\n", i, j, this->mapping[i][j]);
        
    


int main()

    CoordinateMapper mapper_1 = CoordinateMapper_Constructor();
    CoordinateMapper_Initialize(mapper_1, 1);
    printf("Init 1 done\n");

    CoordinateMapper_Print(mapper_1);
    printf("Print 1 done\n");

    CoordinateMapper mapper_2 = CoordinateMapper_Constructor();
    CoordinateMapper_Initialize(mapper_2, 2);
    printf("Init 2 done\n");

    CoordinateMapper_Print(mapper_1);
    printf("Second print 1 done\n");

    CoordinateMapper_Print(mapper_2);
    printf("Print 2 done\n");


// Here is the corresponding output
user:~/path$ gcc src/test_3.c -o test_3
user:~/path$ ./test_3
mapping(0, 0) = 1.000000
mapping(0, 1) = 1.000000
mapping(0, 2) = 1.000000
mapping(1, 0) = 1.000000
mapping(1, 1) = 1.000000
mapping(1, 2) = 1.000000
mapping(2, 0) = 1.000000
mapping(2, 1) = 1.000000
mapping(2, 2) = 1.000000
Init 1 done
mapping(0, 0) = 1.000000
mapping(0, 1) = 1.000000
mapping(0, 2) = 1.000000
mapping(1, 0) = 1.000000
mapping(1, 1) = 0.000000 // This is not correct
mapping(1, 2) = 0.000000 // This is not correct
mapping(2, 0) = 0.000000 // This is not correct
mapping(2, 1) = 1.000000
mapping(2, 2) = 1.000000
Print 1 done
mapping(0, 0) = 2.000000
mapping(0, 1) = 2.000000
mapping(0, 2) = 2.000000
mapping(1, 0) = 2.000000
mapping(1, 1) = 2.000000
mapping(1, 2) = 2.000000
mapping(2, 0) = 2.000000
mapping(2, 1) = 2.000000
mapping(2, 2) = 2.000000
Init 2 done
mapping(0, 0) = 1.000000
mapping(0, 1) = 1.000000
mapping(0, 2) = 1.000000
mapping(1, 0) = 1.000000
mapping(1, 1) = 0.000000 // This is not correct
mapping(1, 2) = 0.000000 // This is not correct
mapping(2, 0) = 0.000000 // This is not correct
mapping(2, 1) = 1.000000
mapping(2, 2) = 1.000000
Second print 1 done
mapping(0, 0) = 2.000000
mapping(0, 1) = 2.000000
mapping(0, 2) = 2.000000
mapping(1, 0) = 2.000000
mapping(1, 1) = 2.000000
mapping(1, 2) = 2.000000
mapping(2, 0) = 2.000000
mapping(2, 1) = 2.000000
mapping(2, 2) = 2.000000
Print 2 done
    在结构指针中设置双精度数组的正确方法是什么? 为什么每个 struct 指针似乎都创建了自己的新数组,但它们仍然有点不稳定? 我可以使用哪些gcc 编译器标志来帮助我查看此类错误以及构造函数中缺少的return this;

【问题讨论】:

我可以使用'双*映射 [3];'然后遍历 'this->mapping[i] = (double*)malloc(c * sizeof(double));'在构造函数中。但这是必要的,也是最简单的解决方案吗? typedef CoordinateMapperStr * CoordinateMapper; 将指针 s 隐藏在 typedef 后面是一个非常非常非常糟糕的做法。 永远不要这样做。 CoordinateMapper this = (CoordinateMapper) calloc (1, sizeof(CoordinateMapper)); --> CoordinateMapper this = (CoordinateMapper) calloc (1, sizeof(*this));CoordinateMapper 是一个指针,您没有为您的结构分配适当的空间量(在这种情况下要少得多)。 为什么说它“非常、非常、非常....糟糕”?你能给我指点关于 C 面向对象编程实践的书或阅读材料吗?例如这里link 他们为指针上的 typedef 提供了一个引人注目的参数。 @ThorTomasarson 这是不好的做法,因为它更容易犯像你这样的错误。 【参考方案1】:

问题在于,无论您是否return this,在任何一种情况下都会出现未定义的行为。

当您不return this 时,您的非 void 函数不会返回值 - 因此您的代码使用了一些垃圾值(可能恰好是来自 calloc 的返回值)。

如果你return this -- 你返回sizeof(CoordinateMapper) 的分配,这只是单个指针的大小。这小于您的结构sizeof(CoordinateMapperStr),并且您的其他代码读取/写入超出分配的内存。这又是一种未定义的行为。

【讨论】:

当我出现这些明显的错误时,是否有任何 gcc 编译器参数或类似的东西可以给我警告? @ThorTomasarson -Wall 将警告您丢失的return。我认为没有任何 GCC 标志会警告错误的sizeof。不过,您可以使用valgrind 或一些静态分析工具来检测。 @ThorTomasarson 如果您使用我评论中的编码样式范例,那么您至少始终拥有正确的基本对象大小(要为其分配空间的对象中有多少仍然必须是正确的)。如果您有兴趣,我上周写了an answer 关于这个的更多细节,我相信可以在 SO 上找到更多示例/讨论。实际上,有图片的答案可能是最好的。【参考方案2】:

@YakovGalka 发现了我的错误。我想在这里补充一点,valgrind 确实是一个可以检测这类编程错误的工具。 通过将-Wall-g 添加到gcc 作为编译器标志并使用valgrind ./compiled_app 运行应用程序,就可以轻松检测到此类错误。

【讨论】:

以上是关于c中结构指针内的双数组的主要内容,如果未能解决你的问题,请参考以下文章

访问结构中的双指针

如何使用结构构造函数初始化结构内的指针数组?

为具有双指针的结构内的动态结构数组分配内存**

数组中的双指针

堆内存指针从结构内的指针字段中丢失

C语言 利用“指向指针数据的指针变量”将数组内的数据依次输出