首页 > 编程笔记 > C++笔记 阅读:25

C++ void指针的用法(非常详细)

C++ 是一种强类型语言,其中的变量都有自己的数据类型,用于保存相应类型的数据。

例如,一个 int 类型的变量可以保存数值 1,而不能保存数值 1.1,后者需要一个 double 类型的变量来保存。

虽然相应数据类型的变量保存相应的数据本来是相安无事的,但在 C++ 中却出现了一个异类,那就是 void 类型。

从本质上讲,void 类型并不是一个真正的数据类型,我们不能定义一个 void 类型的变量。void 更多的是一种抽象和占位符号。在程序中,void 类型主要用于“修饰”和“限制”一个函数。

例如,如果一个函数没有返回值,则可用 void 作为这个函数的返回值类型;如果一个函数没有形式参数列表,也可用 void 作为其形式参数,表示该函数不需要任何参数。

与 void 类型对函数的“修饰”作用不同,void 类型指针作为指向抽象数据的指针,可以成为不同类型指针之间转换的桥梁。

众所周知,把一个指针赋值给另一个指针时,如果两个指针的类型相同,那么可以直接在这两个指针之间进行赋值;如果指针的类型不同,则必须使用强制类型转换,把赋值操作符右边的指针类型转换为左边的指针类型,然后才能进行赋值。

例如:
int* pInt;      // 指向整数的指针
float* pFloat;  // 指向浮点数的指针
pInt = pFloat;  // 直接赋值会产生编译错误
pInt = (int*)pFloat;  // 强制类型转换后进行赋值

但是,当使用 void 类型的指针时,就不需要进行类型转换了。void 类型的指针具有很大的灵活性,任何其他类型的指针都可以直接赋值给 void 类型的指针,例如:
void* pVoid;     // void类型的指针
pVoid = pInt;    // 任何其他类型的指针都可以直接赋值给void类型的指针
pVoid = pFloat;

虽然任何类型的指针都可以直接赋值给 void 类型的指针,但这并不意味着 void 类型的指针可以直接赋值给其他类型的指针。要完成这个赋值,必须经过强制类型转换,把“无类型”转换为“有类型”。例如:
pInt = (int*)pVoid;      // 通过强制类型转换,将void类型的指针转换成int类型的指针
pFloat = (float*)pVoid;  // 通过强制类型转换,将void类型的指针转换成float类型的指针
虽然通过强制类型转换,void 类型的指针可以在其他类型的指针之间自由转换,但这种转换应当遵循一定的规则,void 类型的指针所转换成的其他类型的指针,必须与它所指向的数据类型相符。

例如,把 int 类型的指针赋值给 void 类型的指针,那么这个 void 类型的指针指向的就是 int 类型的数据。如果随后再把这个 void 类型的指针强制转换成 double 类型的指针并尝试通过它访问所指向的数据,就很可能得到错误的结果。因为 void 类型的指针不要求指向特定的数据类型,所以它可以用来代表任何类型的指针,如果函数可以接受任何类型的指针,那么应该将其参数声明为 void 类型的指针。

例如,以下是一个内存复制函数的声明:
void* memcpy(void* dest, const void* src, size_t len);
在这里,任何类型的指针都可以作为参数传入 memcpy() 函数中。这真实地体现了内存操作函数的意义,因为它操作的对象仅仅是一块内存,而不关心这块内存中存储的数据是什么数据类型。

如果 memcpy() 函数的参数类型不是 void 类型的指针,而是 char 类型的指针或者其他类型的指针,那么在使用其他类型的指针作为参数调用 memcpy() 函数时,就需要进行指针类型的转换以匹配其参数类型的要求,以符合具体数据的数据类型,这样一来,memcpy() 函数就不能视为一个“纯粹的、脱离低级趣味的”内存复制函数。

相关文章