IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C语言--指针之空指针(void *) -> 正文阅读

[C++知识库]C语言--指针之空指针(void *)


前言

这篇将介绍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 

实现memset

函数原型:

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++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-01 23:08:08  更:2022-04-01 23:10:22 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 2:52:17-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码