文章目录

  • 前言
  • 一、void *指针是什么?
    • void*指针简单使用
  • 二、指针内存大小
    • 指针所占大小
    • void *类型指针与其他类型指针区别
    • 基本区别
    • 取值操作与地址增长操作
  • 三、void *指针作为函数传参
    • 实现memset
    • 实现memcpy
  • 总结

前言

这篇将介绍C语言令人头疼的知识点–指针。介绍void *这个特别的指针,介绍指针内存分配、指针作为函数传参改怎么使用以及为什么不能直接对void *指针做一些操作。


一、void *指针是什么?

C语言中,一共有几种指针类型,其中最特别的就是void *指针。void *指针就是指向任何类型的指针,在编译的时候不会确定其指向的类型,是在程序中进行指向的。

void*指针简单使用

上面说了,void *指针是可以指向任何类型的指针,那让我们看看具体改怎么使用叭。

int main()
{ int i_t[2]={0,1};void *v_t=i_t;/*void *可以获得指向任何地址,但不知道指向地址的类型大小*//*普通指针使用,获得void *指针指向的地址并强制转换为int *类型,使之有知道指向类型的大小*/int * p_t=(int *)v_t;printf("Get int * i_t[0] = %d i_t[1] = %d \n",*p_t,*(p_t+1));/*void指针使用,可以直接给void *指针赋值,让它指向的类型改为int*的地址*/  v_t=p_t;printf("Get void * i_t[0] = %d i_t[1] = %d \n",*(int *)v_t,* (int *)(v_t+4));/*printf("Get void * i_t[0] = %d i_t[1] = %d \n",*(int *)v_t,* (char *)(v_t+4));*/ //这两条printf输出效果一样,/*第二条printf输出警告,对void * 进行 +操作的警告,在GNU标准,对void *取加操作是仅仅类似char *的取加操作*/system("pause");return 0;
}

运行结果

Get int * i_t[0] = 0 i_t[1] = 1
Get void * i_t[0] = 0 i_t[1] = 1

注意,void *在使用的时候,对void *进行地址的+或者-操作,一定要进行操作需要进行强制类型转换来进行操作,不是所有编译器都支持GNU标准的。

二、指针内存大小

指针所占大小

指针大小其实是由编译器和操作系统共同决定的,一般规律如下。

  • 32位操作系统,32位编译器,指针大小是32位
  • 64位操作系统,32位编译器,指针大小是32位
  • 64位操作系统,64位编译器,指针大小是64位

32位指针大小,能够寻址的空间是4G,62位指针大小能够寻址1800T的地址,这个仅作为了解即可。

void *类型指针与其他类型指针区别

基本区别

区别可以看下图,指针所在的内存都是一样的,但是void *指针与其他指针不一样的就是,它包含所指向类型的信息。这个特性就意味着,它可以指向任何类型的变量,void *类型指针只是指向了这个变量的地址而已。

取值操作与地址增长操作

在ANSI的标准下,在void *类型如果不强制类型转换是不能够进行取值与地址的增长的操作。

为什么呢?我们先看一下int *类型的指针是怎么进行取值的操作的。

取值操作

int *是取得值的范围是(当前首地址+int类型偏移大小)。double *则是当前首地址+double类型偏移大小。这里的偏移大小就是所占的字节数,也就是sizeof(int)或者sizeof(double)。

void *指针是没有包含其指向类型的信息,也就是在不使用强制类型转换下,编译器不知道void *的取多少偏移地址的范围才是所指向的值所在地址范围。也就是void *仅仅具有当前指向目标的首地址,并不知道取首地址之后多少字节合适,这样来取直,究竟是4字节还是8字节,编译器它不知道。它不够智能,得需要告诉这个蠢货,使用强制类型告诉它。

地址增长

地址增长和取值是类似的,void *不知道++改移动多少字节合适,就不具体论述了,聪明的你心中一定有答案了。

三、void *指针作为函数传参

这里我们将使用void *指针作为传参,使得程序的泛用性更强。这里我们就实现两个个C库中的memsetmemcpy,边实现边回顾上面的知识点,就知道为什么传入参数是void *类型以及为什么需要指定长度。

实现memset

函数原型:返回首地址,传入需要指定需要指向初始化的地址以及想要初始化的值和长度。

void * memset(void *s,int c,size_t n)

函数功能:初始化函数,将某一块内存中的全部设置为指定的值。

请看下面的代码和测试函数:

void * my_memset(void *s,int c,size_t n)
{char *c_s=(char *)s;while(n--) *c_s++=c;return s;
}int main()
{ int i_t[2]={1,1};my_memset(i_t,0,sizeof(i_t));for(int i=0;i<(sizeof(i_t)/sizeof(int));i++)printf(" %d ",i_t[i]);system("pause");return 0;
}

运行结果:

 0  0

实现memcpy

函数原型:

void *memcpy(void *dest, void *src, unsigned int count);

函数功能:由src所指内存区域复制count个字节到dest所指内存区域

代码以及测试函数:

void * my_memcpy(void *dest,void *src,unsigned int size)
{char *b_dest=(char *)dest,*b_src=(char *)src;unsigned int len;for(len=size;len>0;len--){*b_dest++=*b_src++;}return dest;
}int main()
{ int i_t[2]={1,1};int i_f[2]={0,0};my_memcpy(i_f,i_t,sizeof(i_t));for(int i=0;i<(sizeof(i_t)/sizeof(int));i++)printf(" %d ",i_f[i]);system("pause");return 0;
}

代码思路简单分析:
复制和清零的思路都是对传入的地址,进行一位一位的操作。

上面说了,void *不包含类型,所以可以作为任意类型进行传入,这样就达到可以操作任意类型。传入的仅仅是没有类型的地址信息而已。在C中由于指针本身并不包含需要操作长度的信息,因此必须传入需要操作的长度信息。不然仅仅传入指针编译器并不会知道究竟操作的范围。

总结

使用void *指针能够加强函数的适用性,但是操作void *指针需要非常的注意,不然容易导致指针操作越界,导致一些其他不可知的程序错误。

C语言--指针之空指针(void *)相关推荐

  1. C语言指针高级部分:void指针和数据指针

    概念 void指针     数据指针 void指针 void指针的基本概念 void的意思就是"无类型",void指针则为"无类型指针",void指针可以指向任 ...

  2. 逍遥自在学C语言 | 指针陷阱-空指针与野指针

    前言 在C语言中,指针是一种非常强大和灵活的工具,但同时也容易引发一些问题,其中包括空指针和野指针. 本文将带你了解这两个概念的含义.产生原因以及如何避免它们所导致的问题. 一.人物简介 第一位闪亮登 ...

  3. C语言double指针如何初始化,C语言指针的初始化以及什么是空指针和void指针

    指针(pointer)是对数据对象或函数的一种引用.指针有多种用途,例如定义"传址调用"函数,它还可以实现动态数据结构,例如链表和树.接下来我们来介绍如何初始化一个指针. 指针初始 ...

  4. c语言野指针和空指针,C++中的空指针和野指针

    空指针常量 一个表示0值的整数常量,叫做空指针常量.例如:0.0L.1-1(它们都是值为0的整数常量表达式)以及(void*)0.void* NULL 都是空指针常量,空指针常量可以赋值给任何指针类型 ...

  5. 都有数据一直报空指针_C语言指针难吗?纸老虎而已,纯干货讲解(附代码)...

    作者:21IC网络整理,排版:晓宇 微信公众号:芯片之家(ID:chiphome-dy) 指针对于C来说太重要.然而,想要全面理解指针,除了要对C语言有熟练的掌握外,还要有计算机硬件以及操作系统等方方 ...

  6. c语言 万能函数指针,C/C++编程笔记:C语言精华解析之void *指针,指针中的万能指针...

    什么是万能指针? 万能指针其实就是void *类型的指针,而void *指针一般被称为通用指针或叫泛指针.它是C语言关于纯粹地址的一种约定.当某个指针是void型指针时,所指向的对象不属于任何类型. ...

  7. 【C语言基础】野指针与空指针

    全网最接地气的C语言野指针介绍,此处对于野指针与空指针知识点做一些简要的介绍,作者实属初学,写博客也是作者学习的一个过程,难免文章中有内容理解不到位或者有不当之处,还请朋友们不吝指正,希望大家多多给予 ...

  8. 【C/C++】指针的思考与注意:空指针,指针赋值,void*指针,二级指针,结构体指针,指向同一地址的多个指针释放问题

    部分参考自:https://blog.csdn.net/u012351051/article/details/96753703 1. 啥是指针 指针是地址,而不是具体的标量值,这是指针的精髓,不管是一 ...

  9. 指针的使用注意事项:空指针、指针赋值、void *指针

    前面的文章,分析了指针的一些概念,可以说指针是C的灵魂,看起来简单,但是想要理解透彻却是相当难,需要大量的练习,不断的巩固,不断的重复才能尽可能的理解指针,这里做一个简单的阶段总结. 1.指针是地址, ...

最新文章

  1. 基于SRCNN的表情包超分辨率(附tensorflow实现)
  2. [转]C# WinForm 关于窗体最大化时的是否全屏效果与是否遮盖任务栏
  3. 剑桥管理学老哥的研究生申请和人生道路规划观念
  4. word List20
  5. android 多线程类,Android 多线程处理之多线程用法大集合
  6. 类的静态成员函数带来了什么好处,应该在什么时候使用?
  7. gdb调试程序函数名为问号,什么原因?step by step解决方案
  8. Objective-C入门教程(摘录)
  9. SolrJ 查询数据
  10. OpenCV概述及安装配置教程
  11. 如何利用视频做动图?视频转gif动图
  12. 程序员到高级程序员,只需要10个步骤!
  13. 2021-11-09水洗碳带有什么特点
  14. 修改weblogic服务器ip地址,修改weblogic服务器ip地址
  15. Java语言概述以及环境搭建
  16. net::ERR_FILE_NOT_FOUND报错
  17. android 推流方案,Android 推流-录屏状态时获取推流信息
  18. python 列表嵌套字典 添加修改删除_python3--字典,字典的嵌套,概念:分别赋值
  19. String 判断纯数字 正则式
  20. 计算机二级选择题笔记百度云,计算机二级题库及计算机二级ms office 复习笔记.doc...

热门文章

  1. RT-Thread实战笔记|MPU6050使用详解及DMP姿态解算
  2. python3跑通smpl模型_SMPL模型学习
  3. 录屏储存失败因为5823_为什么屏幕录制失败因为5823
  4. ARM 2022.10.18
  5. 事务(Transaction)的简单理解
  6. 如何使用Redis缓存 ?
  7. iOS设备、Icon、LaunchImage、图片分辨率
  8. ScriptManager和ClientScript的区别
  9. nlp--常用分词方法
  10. dozer的使用总结