void指针小结
C语言中void有什么作用

C语言中void有什么作用void的字面意思是“无类型”,void *则为“无类型指针”,void *可以指向任何类型的数据。
那么C语言中void具体有什么作用呢?一起来学习下吧:1.概述许多初学者对C/C++语言中的void及void指针类型不甚理解,因此在使用上出现了一些错误。
本文将对void关键字的深刻含义进行解说,并详述void及void指针类型的使用方法与技巧。
2.void的含义void的字面意思是“无类型”,void *则为“无类型指针”,void *可以指向任何类型的数据。
void几乎只有“注释”和限制程序的作用,因为从来没有人会定义一个void变量,让我们试着来定义:void a;这行语句编译时会出错,提示“illegal use of type 'void'”。
不过,即使void a的编译不会出错,它也没有任何实际意义。
void真正发挥的作用在于:(1) 对函数返回的限定;(2) 对函数参数的限定。
我们将在第三节对以上二点进行具体说明。
众所周知,如果指针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 *p1;int *p2;p1 = p2;但这并不意味着,void *也可以无需强制类型转换地赋给其它类型的指针。
因为“无类型”可以包容“有类型”,而“有类型”则不能包容“无类型”。
转载:C语言指针使用的注意事项

转载:C语⾔指针使⽤的注意事项相信⼤家对指针的⽤法已经很熟了,这⾥也不多说些定义性的东西了,只说⼀下指针使⽤中的注意事项吧。
⼀.在定义指针的时候注意连续声明多个指针时容易犯的错误,例如int * a,b;这种声明是声明了⼀个指向int类型变量的指针a和⼀个int型的变量b,这时候要清醒的记着,⽽不要混淆成是声明了两个int型指针。
⼆.要避免使⽤未初始化的指针。
很多运⾏时错误都是由未初始化的指针导致的,⽽且这种错误⼜不能被编译器检查所以很难被发现。
这时的解决办法就是尽量在使⽤指针的时候定义它,如果早定义的化⼀定要记得初始化,当然初始化时可以直接使⽤cstdlib中定义的NULL也可以直接赋值为0,这是很好的编程习惯。
三.指针赋值时⼀定要保证类型匹配,由于指针类型确定指针所指向对象的类型,因此初始化或赋值时必须保证类型匹配,这样才能在指针上执⾏相应的操作。
四.void * 类型的指针,其实这种形式只是记录了⼀个地址罢了,如上所说,由于不知道所指向的数据类型是什么所以不能进⾏相应的操作。
其实void * 指针仅仅⽀持⼏种有限的操作:1.与另外的指针进⾏⽐较,因为void *类型⾥⾯就是存的⼀个地址,所以这点很好理解;2.向函数传递void *指针或从函数返回void *指针,举个例⼦吧,我们平时常⽤的库函数qsort中的⽐较函数cmp(个⼈习惯于⽤这个名字)中传递的两个参数就是const void *类型的,⽤过的应该很熟了;3.给另⼀个void * 类型的指针赋值。
还是强调⼀下不能使⽤void * 指针操纵它所指向的对象。
五.不要将两个指针变量指向同⼀块动态内存。
这个容易引起很严重的问题。
如果将两个指针变量指向同⼀块动态内存,⽽其中⼀个⽣命期结束释放了该动态内存,这个时候就会出现问题,另⼀个指针所指向的地址虽然被释放了但该指针并不等于NULL,这就是所谓的悬垂指针错误,这种错误很难被察觉,⽽且⾮常严重,因为这时该指针的值是随机的,可能指向⼀个系统内存⽽导致程序崩溃。
void指针的转换(2)

void指针的转换(2)void类型指针能够通过显式转换为具有更⼩或同样存储对齐限制的指针。
但数据可能失真。
所谓“同样存储对齐限制”是指void类型指针所指的数据在内存中所占的长度与显式转换后的指针所指的数据在内存中所占的长度相等,⽐⽅以上程序中的p1所指的原数据在内存中占2个字节,p2所指的数据在内存中也是占两个数据。
但应注意的是。
仅仅有上⾯的这样的转换前后指针所指数据类型⼀致的转换才保持数据不失真,假设类型不⼀致,即使具有同样存储对齐限制,也有可能失真,⽐⽅由short转向unsigned short,请看下⾯程序:#include<stdio.h>int main(void){short a=-5,*p1=&a;unsigned short *p2;void *p3;p3=(void *)p1;p2=(unsigned short *)p3;printf("%d\n",*p2);return 0;}其输出结果就不再是-5了。
由于在指针转换时,short类型的数据也经过转换变成了unsigned short类型的数据,详细的转换过程请參考数据类型转换。
只是,也有数值不变的情况,如把a值变为5。
同理,假设是将void类型转换为具有更⼩存储对齐限制的指针时,也可能引起数值的改变。
请看下⾯程序:#include<stdio.h>int main(void){short a=720;char *p1;void *p2;p2=(void *)&a;p1=(char *)p2;printf("%d\n",*p1);return 0;}p1所指向的数据不再是720,⽽是-48。
由于a的值720在内存中的表⽰形式为D0 02(⼗六进制表⽰,共两块,即两个字节),当中D0的地址即a的地址:0x0012ff7c。
p2仅仅保存0x0012ff7c,不知道它占有两字节内存空间。
C++中的void类型

C++中的void类型Technorati 标签: ,1.1. void类型void类型其实是⼀种⽤于语法性的类型,⽽不是数据类型,主要⽤于作为函数的参数或返回值,或者定义void指针,表⽰⼀种未知类型。
1.1.1. 作为函数参数与返回值void func( void );void func( );例如上⾯两例,其实两种声明⽅式是等效的,在C++中如果参数列表为空,默认的参数类型即为void,但建议没有参数时使⽤void以提⾼程序的可读性。
因为C++在定义函数时不允许返回值类型为空,在C++98之前,是允许定义函数时不定义返回值的,默认的返回值是int类型。
其实默认int类型并不是好事,如果函数有返回值在函数返回时是需要消耗CPU传递返回值的,也或许也是C++98标准将默认返回值类型改为void的原因。
因为C++不允许默认返回值,所以当函数不需要返回值是,需要将返回值类型声明为int类型。
当调⽤返回值类型为void类型的函数时,在⼯程上有很多实际代码在前⾯加上(void)类型转换,以提⾼代码的可读性。
如调⽤上⾯定义的 func函数。
(void)func( );从另⼀个⾓度讲,这样严谨的⽅式是可以提⾼软件的健壮性的,调⽤函数时可以明确地看出是没有返回值的,如果调⽤⼀个返回值不是int类型的函数时最好判断其返回值,以检查函数调⽤是否成功,如:#includechar buff[5];func( );snprintf(buff, sizeof(buff), “%d”, “10240”);显然这段代码是有问题的,当然func没有返回值,这样调⽤是没有问题,但snprintf的调⽤会有问题因为缓冲区有可能太⼩⽽不能容纳结果字符串,上⾯的代码就有这个问题。
假设我们不知道snprintf有没有返回值,可能这个BUG我们不会发现,直到有⼀天出现了我们不期望的结果。
如果我们严格要求调⽤每个函数时必须判断函数的返回值,按照以下⾯的代码编码,就不会出给我们的程序造成隐患。
浅谈void及void指针

浅谈void及void指针在编程的过程中,大家都很熟悉void,但是对于void指针恐怕就没有那么熟悉吧,今天我在这里进行一些浅谈,希望对各位朋友有一定的帮助。
首先我们要知道数据类型,什么是数据类型,可以理解为一种数据的结构,每种数据类型都有相应的数据结构,既然是结构那么就有相应的结构信息,包括在内存中占有多少字节等等的东西。
内存是连续的,我们通常都说电脑的内存是2G,那么内存是在电脑出厂或者内存条出厂的时候就制定了每一个内存单元的标识的,内存是由内存单元组成的,一个内存单元我们通常是用一个字节来描述的,内存单元是由电荷位组成的,也就是说一个内存单元是由8个电位组成的,不要问我为什么是8个,我也不知道,呵呵。
好了,知道了内存单元,那么我们就能够知道数据类型的具体东西了,通常我们说一个int类型的变量占有4个字节,也就是说我们定义了一个变量那么它在内存里面是占有连续的4个字节。
好了,终于到了主题,那么void是什么数据类型呢,我的理解为未知的数据类型,这里的未知是指不知道在内存中占有多少字节,因此编译器在编译的过程中也就不能为其分配内存,所以我们就不能定义void类型的变量,那么void 指针又是怎么回事呢?首先明白,指针是存放对象地址(当对象占有多个字节的时候,存放的是第一个字节的地址)对象,而CPU就根据这个指针对象所存放的地址去进行一些操作,由于CPU是32位的,也就是我们通常说的32位机,那么CPU的寻址范围就是2的32次方,也就是4G的地址空间,而内存又只有2G,所以为了不浪费CPU的寻址能力,操作系统就提供了一种虚拟内存。
(扯远了)好了,CPU能够寻找2的32次方的地址空间,而一个字节只有8位,那么4个字节刚好能够把CPU所有的寻址空间都能够表述出来,因此所有的指针都是4个字节。
那么为什么我们平时还在定义不同数据类型的指针呢,可以直接定义一个数据指针就解决了我所有问题啊!你很聪明,不过设计C++语言的人比我们更聪明,如果我们都用一种数据类型来表示我们的地址,那么当一个int类型的变量的第一个字节的地址被保存到指针变量中的时候和一个char类型的变量的地址被保存到指针变量中的时候我们怎么知道是char类型的地址还是int类型的地址呢,因此指针变量包含了一个信息就是这个变量描述的地址应该是几个字节连续的,比如说我们定义了一个int类型的指针,那么指针变量知道这个地址是后面三个字节都是连续的,因此不能分开,是一个整体。
void指针的背后藏着什么?

void指针的背后藏着什么?1. 不能动的“地址”之 void指针1.1 void指针初探void *表示一个“不知道类型”的指针,也就不知道从这个指针地址开始多少字节为一个数据。
和用int表示指针异曲同工,只是更明确是“指针”。
因此void *只能表示一个地址,不能用来&取值,也不能++和--移动指针,因此不知道多少字节是一个数据单位。
int nums[] = {3,5,6,7,9};void* ptr1 = nums;//int i = *ptr1; // 对于void指针没法直接取值int* ptr2 = (int*)nums;printf('%d,%d\n',ptr1,ptr2);int i = *ptr2;printf('%d\n',i);从输出结果可以看出,无论是无类型的void指针还是int类型指针,指向的地址都是一样的:PS:void *就是一个不能动的“地址”,在进行&、移动指针之前必须转型为类型指针。
1.2 void指针的用途这里我们看一下我们之前了解的memset函数,其第一个参数就是一个void指针,它可以帮我们屏蔽各种不同类型指针的差异。
如下面代码所示,我们既可以传入一个int类型数组的指针,也可以传入一个char类型数组的指针:int nums[20];memset(nums,0,sizeof(nums));char chs[2];memset(chs,0,sizeof(chs));那么,我们也可以试着自己动手模拟一下这个memset函数,暂且命名为mymemset吧:void mymemset(void *data,int num,int byteSize){// char就是一个字节,而计算机中是以字节为单位存储的char *ptr = (char*)data;int i;for(i=0;i<byteSize;i++){*ptr=num;ptr++;}}int main(int argc, char *argv[]){int nums[20];mymemset(nums,0,sizeof(nums));int i,len=sizeof(nums)/sizeof(int);for(i=0;i<len;i++){printf('%d ',nums[i]);}printf('\n');return 0;}在这个mymemset函数中,我们利用void指针接收不同类型的指针,利用char类型(一个字节)逐个字节读取内存中的每一个字节,最后依次填充指定的数字。
void指针的用法

void指针的用法
Void指针是一种特殊类型的指针,它可以指向任何数据类
型的地址,包括基本数据类型、自定义类型和函数。
由于
void指针并不知道它所指向的数据的具体类型,所以在使用void指针前,必须将其转换为适当的类型。
在C语言中,使用void指针可以实现灵活的内存分配和动
态类型检查。
一种常见的用法是将void指针作为函数参数,
使函数能够处理不同类型的数据。
例如,可以使用void指针来实现通用的动态数组。
通过将
数据的地址存储在void指针中,可以在运行时根据需要分配
和释放内存。
当需要访问存储在动态数组中的数据时,可以通过将void指针转换为正确的指针类型来实现。
另一个常见的用法是在需要传递复杂数据结构的函数之间
传递指针。
使用void指针作为参数类型可以使函数具有更大
的灵活性,因为它可以接受任何类型的指针。
在函数中,可以将void指针转换为适当的指针类型,以便对数据进行操作。
需要注意的是,由于void指针的特殊性,使用时需要谨慎。
在转换void指针为其他类型指针之前,必须确保这个转换是
类型安全的。
否则,可能会导致内存错误或未定义的行为。
void指针在C语言中具有重要的用途,它可以用于实现灵
活的内存管理和处理不同类型的数据。
通过正确地使用和转换void指针,我们能够编写出更加通用和灵活的代码。
void指针传递参数

void指针传递参数
在C和C++中,void指针可以用来传递参数,以实现更加灵活和动态的数据处理。
使用void指针传递参数时,可以传递任意类型的数据,包括基本数据类型、结构体、数组等。
下面是一个使用void指针传递参数的示例:
c
#include<stdio.h>
void process(void* data) {
int* intData = (int*)data;
printf("Processing integer: %d\n",
*intData);
}
int main() {
int number = 42;
process(&number);
return0;
}
在上面的示例中,process函数接受一个void指针作为参数。
在函数内部,我们将void指针转换为指向整数的指针,并使用它来访问和打印整数值。
在主函数中,我们传递整数的地址给process函数,并调用该函数来处理整数。
需要注意的是,使用void指针传递参数时,我们需要显式地将void指针转换为正确的类型,以便正确地访问和操作数据。
同时,为了避免类型错误和内存访问问题,我们应该确保传入的参数是正确的类型,并且在处理数据时进行适当的类型转换和检查。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
C/C++语言void及void指针深层探索
1.概述
许多初学者对C/C++语言中的void及void指针类型不甚理解,因此在使用上出现了一些错误。
本文将对void关键字的深刻含义进行解说,并详述void及void指针类型的使用方法与技巧。
2.void的含义
void的字面意思是“无类型”,void *则为“无类型指针”,void *可以指向任何类型的数据。
void几乎只有“注释”和限制程序的作用,因为从来没有人会定义一个void变量,让我们试着来定义:
这行语句编译时会出错,提示“illegal use of type 'void'”。
不过,即使void a的编译不会出错,它也没有任何实际意义。
void真正发挥的作用在于:
(1)对函数返回的限定;
(2)对函数参数的限定。
我们将在第三节对以上二点进行具体说明。
众所周知,如果指针p1和p2的类型相同,那么我们可以直接在p1和p2间互相赋值;如果p1和p2指向不同的数据类型,则必须使用强制类型转换运算符把赋值运算符右边的指针类型转换为左边指针的类型。
例如:
其中p1 = p2语句会编译出错,提示“'=' : cannot convert from 'int *' to 'float *'”,必须改为:
而void *则不同,任何类型的指针都可以直接赋值给它,无需进行强制类型转换:
但这并不意味着,void *也可以无需强制类型转换地赋给其它类型的指针。
因为“无类型”可以包容“有类型”,而“有类型”则不能包容“无类型”。
道理很简单,我们可以说“男人和女人都是人”,但不能说“人是男人”或者“人是女人”。
下面的语句编译出错:
提示“'=' : cannot convert from 'void *' to 'int *'”。
3.void的使用
下面给出void关键字的使用规则:
规则一如果函数没有返回值,那么应声明为void类型
在C语言中,凡不加返回值类型限定的函数,就会被编译器作为返回整型值处理。
但是许多程序员却误以为其为void类型。
例如:
程序运行的结果为输出:
2 +
3 = 5
这说明不加返回值说明的函数的确为int函数。
林锐博士《高质量C/C++编程》中提到:“C++语言有很严格的类型安全检查,不允许上述情况(指函数不加类型声明)发生”。
可是编译器并不一定这么认定,譬如在Visual C++6.0中上述add函数的编译无错也无警告且运行正确,所以不能寄希望于编译器会做严格的类型检查。
因此,为了避免混乱,我们在编写C/C++程序时,对于任何函数都必须一个不漏地指定其类型。
如果函数没有返回值,一定要声明为void类型。
这既是程序良好可读性的需要,也是编程规范性的要求。
另外,加上void类型声明后,也可以发挥代码的“自注释”作用。
代码的“自注释”即代码能自己注释自己。
规则二如果函数无参数,那么应声明其参数为void
在C++语言中声明一个这样的函数:
则进行下面的调用是不合法的:
因为在C++中,函数参数为void的意思是这个函数不接受任何参数。
我们在Turbo C 2.0中编译:
编译正确且输出1,这说明,在C语言中,可以给无参数的函数传送任意类型的参数,但是在C++编译器中编译同样的代码则会出错。
在C++中,不能向无参数的函数传送任何参数,出错提示“'fun' : function does not take 1 parameters”。
所以,无论在C还是C++中,若函数不接受任何参数,一定要指明参数为void。
规则三小心使用void指针类型
按照ANSI(American National Standards Institute)标准,不能对void指针进行算法操作,即下列操作都是不合法的:
pint++的结果是使其增大sizeof(int)。
但是大名鼎鼎的GNU(GNU's Not Unix的缩写)则不这么认定,它指定void *的算法操作与char *一致。
因此下列语句在GNU编译器中皆正确:
pvoid++的执行结果是其增大了1。
在实际的程序设计中,为迎合ANSI标准,并提高程序的可移植性,我们可以这样编写实现同样功能的代码:
GNU和ANSI还有一些区别,总体而言,GNU较ANSI更“开放”,提供了对更多语法的支持。
但是我们在真实设计时,还是应该尽可能地迎合ANSI标准。
规则四如果函数的参数可以是任意类型指针,那么应声明其参数为void *
典型的如内存操作函数memcpy和memset的函数原型分别为:
这样,任何类型的指针都可以传入memcpy和memset中,这也真实地体现了内存操作函数的意义,因为它操作的对象仅仅是一片内存,而不论这片内存是什么类型。
如果memcpy和memset的参数类型不是void *,而是char *,那才叫真的奇怪了!这样的memcpy和memset明显不是一个“纯粹的,脱离低级趣味的”函数!
下面的代码执行正确:
有趣的是,memcpy和memset函数返回的也是void *类型,标准库函数的编写者是多么地富有学问啊!
规则五void不能代表一个真实的变量
下面代码都企图让void代表一个真实的变量,因此都是错误的代码:
void体现了一种抽象,这个世界上的变量都是“有类型”的,譬如一个人不是男人就是女人(还有人妖?)。
void的出现只是为了一种抽象的需要,如果你正确地理解了面向对象中“抽象基类”的概念,也很容易理解void数据类型。
正如不能给抽象基类定义一个实例,我们也不能定义一个void(让我们类比的称void为“抽象数据类型”)变量。
4.总结
小小的void蕴藏着很丰富的设计哲学,作为一名程序设计人员,对问题进行深一个层次的思考必然使我们受益匪浅。