【问题标题】:Accessing arrays in a pointer to a struct在指向结构的指针中访问数组
【发布时间】:2011-08-10 17:22:51
【问题描述】:

我有一个简单的结构:

typedef struct {
    void *things;
    int sizeOfThings;
} Demo;

things 旨在包含一个单独的“事物”数组,例如字符串或整数。 我创建了一个指向它的指针:

Demo * Create(int value) {
    Demo *d = malloc(sizeof(Demo));
    if (d != NULL) {
        d->sizeOfThings = value;
        d->things = malloc(20 * value); // We'll have a max of 20 things
    }
}

例如,value 是整数数组的 sizeof(int)。

如果在另一个函数中我想在 d->things 中插入一些东西(至少假设不是我只是将它添加到第一个插槽,位置管理在别处完成):

char * thing = "Me!";
strncpy(d->things[0], &thing, d->sizeOfThings);

我绕过了 strncpy 区域

test.c:10: warning: pointer of type ‘void *’ used in arithmetic
test.c:10: warning: dereferencing ‘void *’ pointer
test.c:10: error: invalid use of void expression

我只是想了解使用 void* 作为概括我的功能的一种方式。我怀疑d->things[0] 有问题。

【问题讨论】:

    标签: c pointers c99 struct dereference


    【解决方案1】:
    Demo *d = malloc(sizeof(Demo));
    if (d != NULL) {
        d->things = malloc(20 * sizeOfThings); // We'll have a max of 20 things
    }
    

    sizeOfThings 初始化为什么?可能它可能有垃圾并导致错误。即使默认初始化为 0malloc 也会返回 NULL(malloc( 20 * 0 ) ;)。所以,我怀疑-

    strncpy(d->things[0], &thing, d->sizeOfThings);
          // ^^^^^^^^^^ causing the error.
    

    【讨论】:

    • @Rio - 警告清楚地说明了这一点 - test.c:10: warning: dereferencing ‘void *’ pointer
    • sizeOfThings 对于字符串设置为 sizeof(char *),对于整数设置为 sizeof(int)。
    • @Rio - 您正在请求大小为 20*sizeOfThings 的内存。但是在执行malloc 语句时,sizeOfThings 的值是多少?同样正如@shinkou 所建议的,第二个参数应该是thing
    • 现在我正在处理一个整数数组。 gdb 告诉我 sizeOfThings 是 4。
    • @Rio - 您在哪里将sizeOfThings 初始化为 4,而您在发布的问题部分中没有显示?我怀疑您看到的是sizeof(sizeOfThings),无论如何它是 4 个字节。
    【解决方案2】:

    尝试看看这是否能解决您的问题:

    char *thing = "Me!";
    strncpy(&d->things[0], thing, d->sizeOfThings);
    

    然后,投射指针以消除警告,但你必须确定你要做什么

    char *thing = "Me!";
    strncpy((char *) &d->things[0], (const char *) thing, d->sizeOfThings);
    

    【讨论】:

      【解决方案3】:

      根据 C 标准,void 没有大小—— sizeof(void) 是未定义的。 (一些实现使其 sizeof(int) 但这不符合要求。)

      当你有一个 foo 类型的数组时,这个表达式:

      array[3]
      

      将 3*sizeof(foo) 添加到存储在数组中的地址,然后引用它。那是因为这些值都打包在内存中。由于 sizeof(void) 是未定义的,你不能对 void 数组这样做(事实上你甚至不能 拥有 void 数组,只有 void 指针。)

      在将任何 void 指针视为数组之前,您必须将其转换为另一种指针类型:

      d->things = malloc(20 * sizeof(int));
      (int *)(d->things)[0] = 12;
      

      但是,请记住,您甚至不必这样做就可以在其上使用 strncpy。 Strncpy 可以接受一个 void 指针就好了。但是您错误地使用了 strncpy 。您的 strncpy 调用应如下所示:

      strncpy(d->things, thing, d->sizeOfThings);
      

      您的版本会尝试将 d->things 的第一个数组成员视为不是指针,并且会将 &thing(它是一个 char **)当作只是一个 char * .

      【讨论】:

      • 这很有帮助。我会使用指针算法来 strncpy 未来的项目吗?
      • 你是对的。但在这种情况下,它是“sizeof(void *)”,而不是“sizeof(void)”。
      • 我不确定你的意思。 strncpy 将复制一个字符串(它只是一个字符数组。)如果你想在一个大缓冲区中连接多个字符串,你可以在偏移指针上使用 strncpy,但使用 strncat 更容易。
      • 理想情况下,事物是一组 void *?
      • 在这种情况下,您应该将结构中的声明更改为 void **things。然后是的,您使用 d->things[0] (包括在分配 malloc 的结果时!)
      【解决方案4】:

      两件事:

      首先,使用 d->things[0] 肯定有问题。 d->things 实际上是一个指针,约定是指针和数组基本上是可以互换的(除了少数例外),数组名总是指向数组的第一个元素。

      其次,strncpy的函数签名是char* strncpy(char* destination, const char* source, size_t num);。因此,为了完成这项工作,我们必须将 d->thing 从 void* 转换为 char* 并确保我们将 thing 作为 char*(只是东西)与 char**(即 thing&)传递。

      所以我们想要这个语句:

      strncpy((char*)d->things, thing, d->sizeOfThings);

      一旦更改到位,其余代码将按预期编译和运行。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-01-04
        • 1970-01-01
        • 2017-06-03
        • 2020-04-07
        • 2014-04-29
        • 2022-07-22
        相关资源
        最近更新 更多