为什么尝试解引用空指针不起作用?

3
int main()
{
    int b = 12;
    void *ptr = &b;
    printf("%d", *ptr);
    return 0;
}

我期望这段代码会打印出12,但是它没有。 如果我们定义一个int指针而不是void指针,它就可以工作了。 我想知道如何使用void指针并打印分配给它的地址和其中保存的量?


4
因为对 void* 进行解引用会得到 void,它是一个“不完整”的类型。也就是说,编译器不知道如何处理它。 - Eugene Sh.
那么,空指针的用途是什么?因为我们永远无法访问它的引用。 - sajjad eshghi
非常感谢。如果我将void指针引用到另一种数据类型,那么我可以打印内容。如何实现? - sajjad eshghi
1
@EugeneSh。资格:因为作为指针,它与任何其他对象类型兼容,而不是任何其他指针类型。通过函数指针往返传递void*未被指定为有效操作。 - chux - Reinstate Monica
通过将指针转换为 void *,原始指针中“保存的数量”将会丢失,您可以使用 void 指针并打印其分配的地址以及其中保存的数量。 - chux - Reinstate Monica
显示剩余4条评论
4个回答

6

void * 进行解引用是没有意义的,因为它无法知道指向内存的类型。

您需要将其转换为指向 int * 的指针,然后才能对其进行解引用。

printf("%d", *((int *)ptr));

“因为它无法知道指向的内存类型。” 你所说的“它”是指编译器吗? - Mehdi Charife
1
@MehdiCharife 是的,编译器没有关于 void * 指向什么类型数据的信息。 - dbush

2

空指针不能被解引用。这会导致以下警告:

编译器错误:'void' 不是一个对象指针类型*

因此,你需要像这样操作。

#include<stdio.h>
int main()
{
    int b = 12;
    void *ptr = &b;
    printf("%d", *(int *)ptr);
    return 0;
}

2
一个使用void指针非常有用的教科书例子是qsort
这是它的签名:
void qsort(void *base, 
           size_t nitems, 
           size_t size, 
           int (*compar)(const void *, const void*)
          ); 
base只是第一个元素的指针。它是void指针的原因是,无论类型如何,qsort都可以用于任何列表。 nitems是列表中项目的数量,size是每个元素的大小。到目前为止都还好理解。
但是它还需要一个第四个参数,这是一个函数指针。您应该编写一个自定义比较函数并传递指向该函数的指针。这就使 qsort 能够对任何列表进行排序。但由于它应该是通用的,所以它采用两个void指针作为参数。这是一个比较庞大的示例比较函数,仅供参考:
int cmpfloat(const void *a, const void *b) {
    const float *aa = (float*) a;
    const float *bb = (float*) b;

    if(*aa == *bb) {
        return 0;
    } else if(*aa > *bb)  {
        return 1;
    } else {
        return -1;
    }
}

很清楚正在发生什么。如果a>b,它返回正数,如果它们相等,则返回零;如果b>a,则返回负数,这是要求。实际上,我只会写成这样:

int cmpfloat(const void *a, const void *b) {
    return *(float*)a - *(float*)b;
}

你可以将其用于以下操作:

float arr[5] = {5.1, 3.4, 8.9, 3.4, 1.3};
qsort(arr, 5, sizeof *arr, cmpfloat);

也许说使用空指针代替模板、通用函数、重载函数等并不完全准确,但它们有相似之处。

2
如果 p 的类型为 void *,那么表达式 *p 的类型为 void,表示“没有值”。你不能将 void 表达式传递给 printf%d 转换说明符(或任何其他转换说明符)。
为了解引用 void *,必须先将其转换为适当类型的指针。您可以使用强制转换来完成:
printf( "%d\n", *(int *) ptr );

或将其分配给适当类型的指针:
int *p = ptr;
printf( "%d\n", *p );

void指针的规则很特殊,它们可以被分配给其他指针类型而不需要显式转换 - 这使它们可以用作“通用”指针类型。但是,您不能直接查看void指针指向的内容。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接