void和万能指针void*

void的相关概念

void 在英文中作为名词的解释为 “空虚、空间、空隙”,而在 C 语言中,void 被翻译为**“无类型”,相应的void *** 为**“无类型指针”**。

void 似乎只有"注释"和限制程序的作用,当然,这里的"注释"不是为我们人提供注释,而是为编译器提供一种所谓的注释。


void 的作用

1.对函数返回的限定,这种情况我们比较常见。

2.对函数参数的限定,这种情况也是比较常见的。

一般我们常见的就是这两种情况:

  • 当函数不需要返回值值时,必须使用void限定,这就是我们所说的第一种情况。例如:void func(int a,char *b)。
  • 当函数不允许接受参数时,必须使用void限定,这就是我们所说的第二种情况。例如:int func(void)。

void 类型指定没有可用的值。它通常用于以下三种情况下:

序号类型与描述
1函数返回为空 C 中有各种函数都不返回值,或者您可以说它们返回空。不返回值的函数的返回类型为空。例如 void exit (int status);
2函数参数为空 C 中有各种函数不接受任何参数。不带参数的函数可以接受一个 void。例如 int rand(void);
3指针指向 void 类型为 void * 的指针代表对象的地址,而不是类型。例如,内存分配函数 void *malloc( size_t size ); 返回指向 void 的指针,可以转换为任何数据类型。

void 指针的使用规则

  1. void 指针是一种特殊的指针,表示为“无类型指针”。void 指针可以指向任意类型的数据,就是说可以用任意类型的指针对 void 指针对 void 指针赋值。例如:
int *a;
void *p;int main(){
	char c = 'a';
	char *pc = &c;

	//void a;
	void *p = &c;//万能指针  可以存储任何类型的地址
	pc = p;
	
	int i = 1;
	int *pi = &i;
	

	p = &i;
	pi = p;

	double d = 3.14;
	double *pd = &d;

	p = &d;
	pd = p;
	return 0;	
}	
p=a;

void * 则不同,任何类型的指针都可以直接赋值给它,无需进行强制类型转换。

void *p1;
int *p2;
p1 = p2;

​ 虽然如此,但这并不意味着可以无需任何强制类型转换就将 void 指针直接赋给其他类型的指针,因为“空类型”可以包容“有类型”,而“有类型”则不能包容“空类型”。例如:猫是动物,狗也是动物。但我们不能说,动物是猫,也不能说动物是狗。

void *p1;
int *p2;
p2 = p1;//错误

​ 因此如果要将 void 指针 p 赋给其他类型的指针,则需要强制类型转换,就本例而言:p2=(int *)p1

​ 在内存的分配中我们可以见到 void 指针使用:内存分配函数 malloc 函数返回的指针就是 void * 型,用户在使用这个指针的时候,要进行强制类型转换,也就是显式说明该指针指向的内存中是存放的什么类型的数据 (int *)malloc(1024) 表示强制规定 malloc 返回的 void* 指针指向的内存中存放的是一个个的 int 型数据。

  1. 在 ANSI C 标准中,进行算法操作的指针必须确定知道其指向数据类型大小,也就是说必须知道内存目的地址的确切值。
    2.1.不允许对 void 指针进行一些算术运算如 p++ 或 p+=1 等,因为既然 void 是无类型,那么每次算术运算我们就不知道该操作几个字节。

    据资料的例子: char 型操作把指针的值加上了 sizeof(char) 字节,而 int 则是sizeof(int) 字节。

    char a[20]="hello world";
    int *p=(int *)a;
    p++;
    printf("%s", p);
    

    所以语句“printf("%s",p)”将输出 “o world”。

    而对于 void 指针,编译器并不知道所指对象的大小,所以对 void 指针进行算术操作都是不合法的

在这里插入图片描述

2.2但是在Ubuntu中在GCC中执行对void指针的自增操作:
#include <stdio.h>
int main(void)
{
    void * p="HelloC";
    p++;
    printf("%s\n", p);
}

在这里插入图片描述

运行结果为:
elloC

void 几乎只有"注释"和限制程序的作用,因为从来没有人会定义一个 void 变量,让我们试着来定义:

void a;

这行语句编译时会出错。即使 void a 的编译不会出错,它也没有任何实际意义。
在这里插入图片描述
众所周知,如果指针 p1 和 p2 的类型相同,那么我们可以直接在 p1 和 p2 间互相赋值;如果 p1 和 p2 指向不同的数据类型,则必须使用强制类型转换运算符把赋值运算符右边的指针类型转换为左边指针的类型。

float *p1;
int *p2;
p1 = p2;
//其中p1 = p2语句会编译出错,
//提示“'=' : cannot convert from 'int *' to 'float *'”,必须改为:
p1 = (float *)p2;

小心使用 void 指针类型:

如果函数的参数可以是任意类型指针,那么应声明其参数为void *

**注:**void 指针可以任意类型的数据,可以在程序中给我们带来一些好处,函数中形为指针类型时,我们可以将其定义为 void 指针,这样函数就可以接受任意类型的指针。如:

典型的如内存操作函数 memcpy 和 memset 的函数原型分别为:

void * memcpy(void *dest, const void *src, size_t len);
void * memset ( void * buffer, int c, size_t num );

这样,任何类型的指针都可以传入 memcpy 和 memset 中,这也真实地体现了内存操作函数的意义,因为它操作的对象仅仅是一片内存,而不论这片内存是什么类型(参见 C 语言实现泛型编程)。如果memcpy 函数的参数类型不是 void*,而是 char*.

在这里插入图片描述

原文参考:https://www.cnblogs.com/wuyudong/p/c-void-point.html

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小城微雨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值