使用指针指向指针处理 C 中的结构数组

Working with array of structures in C using pointer to pointer

本文关键字:指针 结构 数组 处理      更新时间:2023-10-16

我试图更好地了解指针在 C 中的工作原理,以及指向结构的指针让我心碎。在这里,我有3个问题:

  1. 如果我有一个结构和一个指向指针的指针 **测试到这个结构(所以这类似于数组),如何使用 p 访问数组成员(最好的方法)? 测试[i]->id 失败(源示例如下)
  2. 在代码中使用带有指针的那一行可怕的行是不好的,但我也想使用它。我想我弄错了它的模板,每个下一个结构地址的输出看起来像向前跳了 32 个字节,而结构的大小只有 4 个字节。因此,在这一行中,我想 (1) 获取测试顶部指针的初始地址,(2) 将结构 TestCase 的大小乘以 i 添加到它,以便它指向正确的数组元素和 (3) 添加结构的 id 字段的偏移量。之后,我将获得可以在内存中写入id值的地址,对吧?我这样做对吗?
  3. 为什么*测试值被更改了?缓冲区溢出?

    struct TestCase{
        int id;
    };
    int main()
    {
        TestCase ** tests;
        cout << "Size of TestCase: " << sizeof(TestCase) << endl;
        *tests = (TestCase*)malloc(sizeof(TestCase*)*5);
        cout << "*tests = " << *tests << endl;
        for(int i = 0; i < 5; i++)
        {
            //*(int*)(tests+sizeof(TestCase)*i+(int)&(((struct TestCase*)NULL)->id)) = i;
            int addr = tests; // address of structures array in memmory;
            addr += sizeof(TestCase)*i; //address of current structure;
            addr += (int)&(((struct TestCase*)NULL)->id); // Adding id parameter offset in memory to current address
            *(int*)addr = i; // setting id for current structure equal to i
            cout << (int*)(tests+sizeof(TestCase)*i+(int)&(((struct TestCase*)NULL)->id)) << endl;
        }
        cout << "*tests = " << *tests << endl;
        return 0;
    }
    

    输出为:

    Size of TestCase: 4
    *tests = 0x600048600
    0x23ab90
    0x23abb0
    0x23abd0
    0x23abf0
    0x23ac10
    *tests = 0x600000000
    

PS:将循环代码从一行更新为分步操作。

假设您希望tests成为具有 5 个指向 5 个结构的array-of-pointers-to-struct-TestCase,那么您需要

  • 分配一个包含 5 个指针的数组,以及
  • 通过为结构分配内存来初始化每个指针

喜欢这个:

#include <stdio.h>
#include <stdlib.h>
struct TestCase
{
    int id;
};
int main( void )
{
    int i;
    struct TestCase **tests;
    // allocate memory for an array of 5 pointers
    tests = malloc( 5 * sizeof(struct TestCase *) );
    if ( tests == NULL )
        exit( 1 );
    // allocate memory for 5 structures (and save each pointer in the array)
    for ( i = 0; i < 5; i++ )
    {
        tests[i] = malloc( sizeof(struct TestCase) );
        if ( tests[i] == NULL )
            exit( 1 );
    }
    // initialize the id in each struct
    for ( i = 0; i < 5; i++ )
        tests[i]->id = i;
    // print the id in each struct
    for ( i = 0; i < 5; i++ )
        printf( "%dn", tests[i]->id );
    // free memory
    for ( i = 0; i < 5; i++ )
        free( tests[i] );
    free( tests );
    return 0;
}

我无法重现第 2 点中描述的问题。 这是我尝试的代码(我将其放在释放内存的代码之前)

printf( "%pn", tests );
for ( i = 0; i < 5; i++ )
{
    intptr_t addr = (intptr_t)tests;
    addr += sizeof(struct TestCase)*i;
    addr += (int)&(((struct TestCase*)NULL)->id);
    printf( "%pn", (void *)addr );
}

代码的输出为

0xc03950
0xc03950
0xc03954
0xc03958
0xc0395c
0xc03960

地址按预期前进 4 个字节。 请注意,我将addr类型更改为intptr_t,以保证指针可以正确转换,但这不会影响后续两行中的数学运算。

  1. 在你的代码中,测试是三重 *,从 malloc 行中删除额外的 *,test[0]->id 赋值将起作用。

  2. 如果需要对偏移量进行高级访问,请按照问题 1 中最初想要的方式分配值。IE - tests[0]->id = 0x3834 ,或用于动态赋值的 memcpy。不需要所有这些参考和演员表。

  3. 因为测试在迭代器的第一行中得到了重新确认。

多亏了@user3386109我终于能够做我想做的一切。好吧,我现在不是使用令人毛骨悚然的公式来写地址,而是使用相同的令人毛骨悚然的公式从地址中读取:

    #include <stdio.h>
    #include <iostream>
    #include <string.h>
    #include <stdlib.h>
    using namespace std;
    struct TestCase{
        int ida;
        int idb;
    };
    int main()
    {
        TestCase ** tests; //create pointer to pointer
        cout << "Size of TestCase: " << sizeof(TestCase) << endl;
        tests = malloc(sizeof(TestCase*)*5);
        if(tests == NULL)
            exit(1);
        for(int i=0; i< 5; i++)
        {
            tests[i] = malloc(sizeof(struct TestCase));
            if(tests[i] == NULL)
                exit(1);
        }
        cout << "*tests = " << *tests << endl;
        for(int i = 0; i < 5; i++)
        {
            tests[i]->ida = i;
            tests[i]->idb = i+6;
            cout << std::hex << &(tests[i]->idb) << ": " << *(long*)((long)(long*)(tests[i])+(long)&(((TestCase *)NULL)->idb)) << endl;
        }
        for(int i=0; i<5; i++)
        {
            free(tests[i]);
        }
        cout << "*tests = " << *tests << endl;
        free(tests);
        return 0;
    }

输出:

    $ ./a.exe
    Size of TestCase: 8
    *tests = 0x600048630
    0x600048634: 6
    0x600048654: 7
    0x600048674: 8
    0x600048694: 9
    0x6000486b4: a
    *tests = 0x600048630