详解C语言的void*空指针

目录
  • void的应用
  • 空指针类型(void*)
  • 总结

在C语言中,void称为无类型,相应的void*称为无类型指针或者空指针类型。

void的应用

对函数返回值的限定。

例如void func(int);该函数没有返回值。对函数参数类型的限定。

例如int func(void);该函数没有参数,不允许接收参数。

空指针类型(void*)

空指针类型的变量void* pvoid;可以指向任意类型的数据,任何类型的指针也可以直接赋值给空指针类型的变量。

#include <stdio.h>

int main()
{
    char c, *pc;
    int i, *pi;
    double d, *pd;
    void *pvoid;

    pc = &c;
    pvoid = pc;
    printf("pvoid = %p  &c = %p\n", pvoid, &c);
    pi = &i;
    pvoid = pi;
    printf("pvoid = %p  &i = %p\n", pvoid, &i);
    pd = &d;
    pvoid = pd;
    printf("pvoid = %p  &d = %p\n", pvoid, &d);

}

/*
输出结果
pvoid = 000000000061FDFF  &c = 000000000061FDFF
pvoid = 000000000061FDF8  &i = 000000000061FDF8
pvoid = 000000000061FDF0  &d = 000000000061FDF0
*/

但是如果空指针类型的变量赋值给任意指针类型的变量,就需要强制转换;也就是显式说明该指针指向的内存中是存放的什么类型的数据。

void *pvoid;
int *pi;
char *pc;
double *pd;

pi = (int*)pvoid;
pc = (char*)pvoid;
pd = (double*)pd;

另外,以下有些需要注意的地方。

在 ANSI C 标准中,不允许对 void 指针进行一些算术运算如 p++ 或 p+=1 等。因为既然 void 是无类型,那么每次算术运算我们就不知道该操作几个字节,例如 char 型操作 sizeof(char) 字节,而 int 则要操作 sizeof(int) 字节。而在 GNU 中则允许,因为在默认情况下,GNU 认为 void * 和 char * 一样,既然是确定的,当然可以进行一些算术操作,在这里sizeof(*p)==sizeof(char)

int i;
void *pvoid;
pvoid = &i;
printf("%p\n", pvoid);
pvoid++;//ANSI:错误;GNU:正确
pvoid += 1;//ANSI:错误;GNU:正确
printf("%p\n", pvoid);

在实际的程序设计中,为迎合 ANSI 标准,并提高程序的可移植性,我们可以这样编写实现同样功能的代码:

((int*)pvoid)++;
(int*)pvoid += 1;

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • C语言详细分析讲解关键字goto与void的作用

    目录 一.关于goto 二.void 的意义 三.小结 一.关于goto 高手潜规则:禁用 goto 项目经验:程序质量与 goto 的出现次数成反比 最后的判决:将 goto 打入冷宫 下面看一段 goto 副作用分析的代码: #include <stdio.h> #include <malloc.h> void func(int n) { int* p = NULL; if( n < 0 ) { goto STATUS; } p = (int*)malloc(sizeof

  • C语言goto语句简单使用详解

    简单介绍 C语言中提供了可以随意滥用的 goto语句和标记跳转的标号.从理论上 goto语句是没有必要的,实践中没有goto语句也可以很容易的写出代码.但是某些场合下goto语句还是用得着的,最常见的用法就是终止程序在某些深度嵌套的结构的处理过程,例如一次跳出两层或多层循环.这种情况使用break是达不到目的的.它只能从最内层循环退出到上一层的循环. 语法 C 语言中 goto 语句的语法: goto label; .. . label: statement; 示例对比 #include<std

  • 详解C语言的void*空指针

    目录 void的应用 空指针类型(void*) 总结 在C语言中,void称为无类型,相应的void*称为无类型指针或者空指针类型. void的应用 对函数返回值的限定. 例如void func(int);该函数没有返回值.对函数参数类型的限定. 例如int func(void);该函数没有参数,不允许接收参数. 空指针类型(void*) 空指针类型的变量void* pvoid;可以指向任意类型的数据,任何类型的指针也可以直接赋值给空指针类型的变量. #include <stdio.h> in

  • 详解C语言之缓冲区溢出

    一.缓冲区溢出原理 栈帧结构的引入为高级语言中实现函数或过程调用提供直接的硬件支持,但由于将函数返回地址这样的重要数据保存在程序员可见的堆栈中,因此也给系统安全带来隐患.若将函数返回地址修改为指向一段精心安排的恶意代码,则可达到危害系统安全的目的.此外,堆栈的正确恢复依赖于压栈的EBP值的正确性,但EBP域邻近局部变量,若编程中有意无意地通过局部变量的地址偏移窜改EBP值,则程序的行为将变得非常危险. 由于C/C++语言没有数组越界检查机制,当向局部数组缓冲区里写入的数据超过为其分配的大小时,就

  • 详解C语言中双向循环链表的实现

    目录 实现细节 辅助理解图 具体实现代码 1.对链表进行初始化 2.任意位置前的插入 3.任意位置的删除 4.头插和尾删 完整代码 头文件 具体函数 测试 实现细节 1.带一个哨兵位(哨兵节点,初始节点,不存储有效数据,用来方便后期数据的存储与查找) 2.与单向链表不同的是,双向链表中每个数据节点包含两个指针,分别指向前后两个节点 3.双向链表是循环的,其尾节点后不是空指针,而是与头部的哨兵节点通过指针相连 辅助理解图 具体实现代码 1.对链表进行初始化 初始化:哨兵位的前后指针均指向哨兵节点本

  • 详解C语言中动态内存管理及柔性数组的使用

    目录 一.malloc 二.free 三.calloc 四.realloc 1.realloc在扩容时的情况 2.realloc也能实现malloc功能 五.使用动态内存的常见错误 1.free空指针 2.对动态开辟的空间越界访问 3.对非动态开辟内容free 4.只free动态开辟空间的一部分 5.对同一块内存多次free 6.动态内存空间忘记释放(内存泄漏) 六.柔性数组 1.柔性数组的概念 2.柔性数组的特点 3.柔性数组的使用场景 4.柔性数组的优点 一.malloc 这个函数向堆区申请

  • 一文详解C语言中文件相关函数的使用

    目录 一.文件和流 1.程序文件 2.数据文件 3.流 二.文件组成 三.文件的打开和关闭 1.文件的打开fopen 2.文件关闭fclose 四.文件的顺序读写 1.使用fputc和fgetc写入/读取单个字符 2.使用fputs和fgets写入/读取一串字符 3.使用fprintf和fscanf按照指定的格式写入/读取 4.使用fwrite和fread按照二进制的方式写入/读取 5.使用sprintf和sscanf将格式化数据和字符串互相转换(文件无关) 五.文件的随机读写 1.fseek(

  • 详解C语言中的动态内存管理

    目录 一.动态内存管理 1.1为什么要有动态内存管理 1.2动态内存介绍 1.3常见的动态内存错误 一.动态内存管理 1.1为什么要有动态内存管理 1.1.1  在c语言中我们普通的内存开辟是直接在栈上进行开辟的 int i = 20;//在栈空间上开辟四个字节 int arr[10]={0}; //在栈中连续开辟四十个字节 这样开辟的特点是: (1)他所开辟的空间是固定的 (2)数组在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配 但对于空间的需求,我们有的时候并不知道,有可能空间

  • 详解C语言函数返回值解析

    详解C语言函数返回值解析 程序一: int main() { int *p; int i; int*fun(void); p=fun(); for(i=0;i<3;i++) { printf("%d\n",*p); p++; } return 0; }; int* fun(void) { static int str[]={1,2,3,4,5}; int*q=str; return q; } //不能正确返回 虽然str是在动态变量区,而该动态变量是局部的,函数结束时不保留的.

  • 详解C 语言项目中.h文件和.c文件的关系

    详解C 语言项目中.h文件和.c文件的关系 在编译器只认识.c(.cpp))文件,而不知道.h是何物的年代,那时的人们写了很多的.c(.cpp)文件,渐渐地,人们发现在很多.c(.cpp)文件中的声明语句就是相同的,但他们却不得不一个字一个字地重复地将这些内容敲入每个.c(.cpp)文件.但更为恐怖的是,当其中一个声明有变更时,就需要检查所有的.c(.cpp)文件. 于是人们将重复的部分提取出来,放在一个新文件里,然后在需要的.c(.cpp)文件中敲入#include XXXX这样的语句.这样即

  • 详解C语言-二级指针三种内存模型

    二级指针相对于一级指针,显得更难,难在于指针和数组的混合,定义不同类型的二级指针,在使用的时候有着很大的区别 第一种内存模型char *arr[] 若有如下定义 char *arr[] = {"abc", "def", "ghi"}; 这种模型为二级指针的第一种内存模型,在理解的时候应该这样理解:定义了一个指针数组(char * []),数组的每个元素都是一个地址. 在使用的时候,若要使用中间量操作元素,那么此时中间量应该定义为 char *tm

  • 详解C语言进程同步机制

    本文是对进程同步机制的一个大总结(9000+字吐血总结),涵盖面非常的全,包括了进程同步的一些概念.软件同步机制.硬件同步机制.信号量机制和管程机制,对每种机制结合代码做了详细的介绍,并且对琐碎的知识点和概念解释的非常清晰. ​ 在前面的博客中讲述了进程的状态及其状态的转换,每种状态的含义和转换的原因.同样我们也知道,在OS引入了进程后,可以使系统中的多道程序可以并发的执行,进程的并发执行一方面极大的提高了系统的资源利用率和吞吐量,但是另一方面却使系统变得更加复杂,如果不能采取有效的措施,对多个

随机推荐