【问题标题】:Using void pointer to an array使用指向数组的 void 指针
【发布时间】:2012-02-07 10:05:27
【问题描述】:

我只是尝试使用指向整数数组的 void 指针,我试图通过将数组转换回 int 来查看是否可以将数组打印回来。但它给了我一些随机价值。你能告诉我哪里出错了吗?

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

int main(){
    int a[5];
    int x;
    int j;

    a[0]=1;
    a[1]=2;
    a[2]=3;
    a[3]=4;

    void *arr=a;

    for(j=0;j<4;j++){
        x = *(int *)(arr+j);
        printf("%d",x);
    }
    return 0;
}

输出是这样的:

133554432131072512

为什么它不打印数组 a[] 的元素,即 1,2,3,4 ?

【问题讨论】:

  • 您可以通过将换行符放入打印数字的格式字符串中来改进输出:printf("%d\n", x);
  • 是的。我没有专注于格式化,因为我写这个是为了帮助自己测试另一个程序的这个功能。

标签: c pointers void-pointers pointer-arithmetic


【解决方案1】:

你需要在添加j之前添加arr 之前。这是一个最小的修复:

x = *(((int *)arr)+j);

但我认为写起来更清楚:

x = ((int *)arr)[j];

【讨论】:

  • 工作就像一个魅力。非常感谢。
  • 我想知道为什么 *(int *)(arr+j) 是错误的?你能解释一下吗?
  • @AnushaPachunuri:请看我的回答,但总结一下,这是错误的,因为你不能将数字添加到void *,你需要转换void * 首先 然后添加数字。
【解决方案2】:

您不应该将数字添加到 void 指针。之前投。 (x = *((int *)arr+j);)

当你把数字加到一个指针上时,编译器把这个数字乘以所指向的类型的大小,所以如果你把数字加到一个指向错误类型的指针上,你会得到错误的结果。

如果我没记错的话,添加到 void* 是非法的,但是一些编译器会添加以字节为单位的确切数字(就像它是 char*)。 `

【讨论】:

    【解决方案3】:

    您正在对 void * 进行指针运算,这在 C 中无效。

    在 GNU C(带有 gcc 扩展的 C)中,实际上是允许的,sizeof (void) 被认为是 1。

    http://gcc.gnu.org/onlinedocs/gcc/Pointer-Arith.html

    "指向void的指针支持加减运算 以及指向函数的指针。这是通过处理 void 或作为 1 的函数。”

    【讨论】:

    • +1:指出 void * 上的算术是 GCC 扩展。
    【解决方案4】:

    C 标准没有定义 void * 的算术行为,因此您需要将 void * 转换为另一个指针类型首先,然后再对其进行算术运算。

    一些编译器 [作为扩展] 将 void * 的指针运算视为与 char * 相同,因此每个“+1”只会将地址增加 1,而不是增加指向对象的大小。虽然这不是标准化的,所以你不能依赖这种行为。

    【讨论】:

    • 哦,你的意思是指针算法不适用于 void * 指针。嗯,我明白了。感谢您的精彩解释。
    • ISO/IEC 9899:1999。 §6.2.5 ¶19 void 类型包含一组空值;它是一个无法完成的不完整类型。 然后在 ¶20 中它添加了 指针类型可以派生自函数类型、对象类型或不完整类型...其中不完整的类型显然不是对象类型,因此您不能将void * 视为指向对象类型的指针。 §6.5.2 加法运算符说 对于加法,两个操作数都应具有算术类型,或者一个操作数应是指向对象类型的指针,而另一个应具有整数类型。 所以你不能做算术在void *.
    • @JonathanLeffler:C 标准没有定义该行为,但也没有明确地未定义,通常是在这些区域中,C 实现将这种行为放入并称之为扩展。
    • @JonathanLeffler 提到的 @dreamlax 将整数和 void * 类型的操作数相加显然违反了加法运算符 (6.5.6p3) 的约束。所以它需要一个诊断,并且实现是免费的,不翻译程序。
    • @ouah:我没有在这里争论什么,如果有什么我同意你的话;我说过一些编译器将其视为扩展。我的意思是在算术中使用void * 不是未定义的行为,我是说它根本没有定义(即标准没有定义任何涉及算术的行为void *)。未定义的行为与 C 标准未定义的行为之间存在巨大差异。
    猜你喜欢
    • 2012-03-25
    • 2011-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-21
    • 2019-08-24
    • 2018-04-19
    相关资源
    最近更新 更多