欢迎光临

我们一直在努力
当前位置:首页 > 编程技术 >

C/C++指针介绍与使用详解

日期:
后台-插件-广告管理-首页/栏目/内容广告位一(PC)
后台-插件-广告管理-首页/栏目/内容广告位一(手机)
目录
  • 什么是指针
  • 定义指针变量
  • 间接引用指针
  • 常or常常
  • 指向指针的指针
  • 指针与数组
    • 指针的运算
  • 堆内存分配
    • C语言
    • C++语言
  • 指针与函数
    • 数组名作为函数的入口参数
    • 函数名作为参数传入其他函数
    • 使用指针修改函数参数
    • 变量的引用作为函数的参数
  • 两个常用的字符串函数
    • 总结

      什么是指针

      C/C++语言拥有在程序运行时获得变量的地址和操作地址的能力,这种用来操作地址的特殊类型变量被称作指针。

      翻译翻译什么tmd叫tmd指针!

      变量或常量的指针存储的数据是 :对应的变量或常量在内存中的地址。

      图解:

      此时 我们定义三个指针 p1, p2, p3 分别指向a, b, c ,那么p1中存储的数据是变量a所占用内存的首地址:0x00;

      b和c中存储的数据是什么呢? 没错,就是0x02和0x04。

      显然。若要知道变量a的值,首先读取指针p1中的数据0x00,然后读取内存0x00和0x01中的数据就可以了。这个时候,会出现一个问题:怎么才能确定究竟要读取几个单位内存中的数据呢?毕竟p1中只存储了0x00呀。这个时候 ,指针的类型就发挥了作用。举个例子:如果定义的指针是int类型的,那么读取的时候自动从指针中存储的初值向后读取4个字节;float类型的指针就是读取8个字节。这样就可以既完整又不多余的取出所需要的数据了。

      总结一下一个指针的两个要素:指针类型和指针所指变量的初地址。

      定义指针变量

      指针在定义的时候最好直接初始化,否则可能出现意想不到的结果。

      @定义一个指向变量的指针。

      /*定义一个指向int类型变量a的指针p*/
      int a = 3;
      int * p;	
      p = &a;	//把a的地址赋值给p;
      /*下面的语句最好不要用!!!!*/
      p = &28;	//这也是可以的,p指向的地址中存储的数据是28.
      /*可以用下面的语句代替上面的语句*/
      *p = 28;
      

      间接引用指针

      间接引用操作符也是 *

      *p 取出p指向的内存空间中的值。

      所以区分定义或是引用指针可能有些麻烦。

      只有同类型的指针和变量才能通过 * 和 & 互相建立关系。

      int a = 0;
      int temp;
      int * p = &a;
      /*指针的间接引用*/
      cout<< *p;	//输出结果是0
      /*以下两种表达等价*/
      *p = 3;	//把3赋值给a
      a = 3;
      /*以下两种表达效果相同。都是把变量a赋值给temp*/
      temp = a;
      temp = *p;	//temp被赋值为0
      /* 以下表达是错误的*/
      float f = 3.1;
      int * p = &f;	//error,指针类型与变量类型不匹配 

      常or常常

      这个部分本来应该在定义指针变量里,但是因为需要指针的间接引用作为铺垫,所以把它单独拿出来了

      我们先区分一组概念:常量、指向常量的指针、常指针以及指向常量的常指针。

      1.常量:顾名思义不发生改变的量,想必大家是熟悉的。

      2.指向常量的指针:只限制间接访问操作,不限制指针指向的值本身的操作规范。

      3.常指针:指http://针中存储的地址一经初始化就不能改变了,也就是说常指针只能指向一个固定的地址,但是地址中存储的数据是可以改变的哦~

      4.指向常量的常指针:根据上面三个概念大家应该可以理解了,就是指针中存储的地址和该地址中的数据皆不可更改。

      例如:

      int b = 4;
      const int a = 5;	//定义一个常量a。
      /*注意观察以下三个定义中const的位置*/
      const int *p = &a;	//定义一个指向常量的指针p,指向常量a。
      p = &b;	//这个也是没问题的哦
      *p = 6;	//error,这个间接访问操作是不可以。 
      int * const p2 = &b;//定义一个常指针p2
      *p2 = 6;	//这个是可以的,注意区分和上面的区别
      const int * const p3 = &a;	//指向常量的常指针p3
      /* emm我也不知道该注释点什么,自行体会吧~*/
      *p = 11;	//error,因为p指向的是常量,常量的值不可更改
      *p2 = 2;	//true,p2是常指针,指向的地址不变,但地址中的值可以更改
      *p3 = 4;	//error
      p3 = &b;	//error

      指向指针的指针[!--empirenews.page--]

      指针本质上也是一个变量或常量,那么指针也是有地址的,而指向这些地址的指针被称为指向指针的指针。

      int a = 25;
      int * p  = &a;
      int pp = &p;	//true,pp指向的地址中存储的是指针p的地址。 
      

      指针与数组

      一个数组的数组名就是一个常指针。

      int arr[] = {5,4,6,9,8,3};
      

      arr就是一个指针,而且指向数组的第一个元素arr[0]。

      指针数组:

      char * arr[] ={"this is", "a", "C++ !"}; 
      

      在此提及一下字符串常量:

      char * a 
      /*
      双引号的作用:
      	在字符串结尾加一个\0,并分配内存空间,返回首地址。
      */
      a = "dshfw";	
      

      指针的运算

      指针只能支持 + 和 - 的运算,但这已经足够满足大多数指针操作的需求了。

      /*接下来以数组为例,只介绍加法 ,减法同理*/
      int arr[] = {5,4,6,9,8,3};
      cout<< *p;	//输出结果为5
      cout<< *(p+1);	//输出结果为4
      /*打印整个数组*/
      for(int *p = arr; p < arr+5; ++p)
      {
      	cout<< *p<<' ';
      }
      cout<<endl;
      

      堆内存分配

      C语言

      /*函数原型*/
      void * malloc(size_t size);
      /*使用:开辟5个int类型变量的存储空间,返回首地址*/
      /**/
      int *arr;
      if(arr = (int *) malloc(5 *sizeof(int)) == NULL)
      {
      	exit(1);
      }
      /*释放堆内存*/
      free(arr);
      

      C++语言

      注意释放数组内存空间时,delete后有[] !!!

      /*申请一个5个元素的数组空间*/
      int * arr = new int[5];
      delete[] arr;
      /*申请一个变量的空间*/
      int * arr = new int;
      delete arr;
      

      指针与函数

      函数名和数组名一样都是一个指针,有时我们需要把函数名作为参数传入其他函数中。

      数组名作为函数的入口参数

      arr[] = {4,6,9,8,5,3,2,7,5};
      /*两种不同的写法均可以*/
      void Sort_Shell(int arr[], int n)
      {
      /*code*/
      }
      void Sort_Shell(int * arr, int n)
      {
      /*code*/
      }
      /*下面这种是不可以的!!!*/
      void Sort_Shell(int * arr[], int n)
      {
      /*code*/
      }
      

      举个小小的例子

      /*来个小小的希尔排序算法*/
      void Sort_Shell(int arr[], int n)
      {
      	int gap = n / 2;
      	for(; gap > 0; gap /= 2)
      	{
      		for(int i = gap; i <n; ++i)
      		{
      			int temp = a[i];
      			int j = i;
      			while(j >= gap&& temp &lphpt; arr[j -  gap])
      			{
      				a[j] = a[j - gap];
      				j -=gap;
      			}
      			a[j] = temp;
      		}
      	}
      }
      

      开了个小差,接下来回归正题,我们的指针。

      函数名作为参数传入其他函数

      static bool cmp(int a, int b)
      {
      	return a < b;
      }
      void show(bool * b)
      {
      	if( &b)
      	{
      		cout<< true;
      	}
      	else
      	{
      		cout<<false;
      	}
      }
      

      使用指针修改函数参数

      首先来看个例子:

      void swip(int a, int b)
      {
      	int c = a;
      	a = b;
      	b = c;	
      }
      int main()
      {
      	int a = 5, b = 6;
      	swip(a, b);
      	cout<<a<<' '<<b;
      }
      

      输出结果:5 6

      并未达到交换的效果,因为函数内部对形参的修改并不能反映到上层的main函数中。

      此时我们可以通过指针作为函数的入口参数来实现预期的功能。

      void swip(int * a, int* b)
      {
      	int c = *a;
      	*a = *b;
      	*b = c;	
      }
      int main()
      {
      	int a = 5, b = 6;编程
      	swip(&a, &b);
      	cout<<a<<' '<<b;
      }
      

      输出结果:6 5

      传递函数的指针虽然能达到预期效果,但是确实以破坏函数的黑盒为代价,可读性差,调试困难。

      有没有什么更好的办法呢?接下来 引用登场了。

      变量的引用作为函数的参数

      void swip(int &a, int &b)
      {
      	int c = a;
      	a = b;
      	b = c;	
      }
      int main()
      {
      	int a = 5, b = 6;
      	swip(a, b);
      	cout<<a<<' '<<b;
      }
      

      输出结果:6 5

      克服了指针作为参数的弊端。话又有点多了,哈哈,这和指针有什么关系呢······

      两个常用的字符串函数

      • strcmp() :用于比较字符串的大小。
      • strcpy() :复制字符串。
      //函数原型
      int strcmp(const char * arr1, const char * arr2);
      //使用举例:
      char arr1[] = "dfetf";
      char arr2[] = "cfefef";
      int b = strcmp(arr1, arr2);
      [!--empirenews.page--]

      输出b的值是大于0 的。

      总结

      指针强大而又危险,却也是C和C++的灵魂,由于其可以直接操作内存地址的特殊性,使得理解指针是如何工作的在C和C++中必不可少,若想成为一名优秀的C++工作者,必须要掌握指针。

      到此这篇关于C/C++指针介绍与使用详解的文章就介绍到这了,更多相关C++指针内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

      后台-插件-广告管理-首页/栏目/内容广告位二(PC)
      后台-插件-广告管理-首页/栏目/内容广告位二(手机)
      后台-插件-广告管理-内容广告位三(PC)
      后台-插件-广告管理-内容广告位三(手机)

      相关阅读

      后台-插件-广告管理-内容广告位四(PC)
      后台-插件-广告管理-内容广告位四(手机)

      热门文章

      后台-插件-广告管理-侧边广告位一(PC)
      后台-插件-广告管理-侧边广告位一(手机)
      • HTML 表单组件实例代码

      • HTML 表单用于搜集不同类型的用户输入。下文通过代码给大家分享html 表单组件实例代码,感兴趣的朋友参考下吧 废话不多说了,直接给大家贴代码了,具体代码如下所示: <!DOCTYPE
      • html2canvas 将html代码转为图片的使用方法

      • 转换代码到图片使用 html2canvas,这是一个非常著名的从浏览器网页截图的开源库,使用很方便,功能也很强大。 使用 html2canvas http:// html2canvas 的使用非常简单,简单
      • HTML网页中插入视频的方法小结

      • 现在如果要在页面中使用video标签,需要考虑三种情况,支持Ogg Theora或者VP8(如果这玩意儿没出事的话)的(Opera、Mozilla、Chrome),支持H.264的(Safari、IE 9、Chrome),都不支持的(IE6、
      • HTML实现文本框只读不能修改其中的内容

      • 废话不多说了,直接给大家贴代码了,具体代码如下所示: <!--方法1:>http:// 当鼠标放不上就离开焦点 --> <input type="text" name="input1" value=http://www.cppcns.com/web
      • 移动端专用的meta标签设置大全

      • 前言 之前学习前端中,对meta标签的了解仅仅只是这一句。 <meta charset="UTF-8"> 但是打开任意的网站,其head标签内都有一列的meta标签。比如我们我们网站,但是自己却很不熟
      后台-插件-广告管理-侧边广告位二(PC)
      后台-插件-广告管理-侧边广告位二(手机)

      最新文章

      • 在Asp.net core项目中使用WebSocket

      • 今天小试了一下在ASP.NET core中使用websocket,这里记录一下: 在 Startup 类的 Configure 方法中添加 WebSocket 中间件。 app.UseWebSockets(); 它也可以传入一些参数 app.Us
      • Vue快速理解事件绑定是什么

      • 目录一、监听事件二、事件修饰符1、stop修饰符阻止事件冒泡2、capture修饰符3、self修饰符4、prevent修饰符5、键盘事件修饰符6、鼠标事件修饰符一、监听事件 监听事件一般
      • C#实现模拟ATM自动取款机功能

      • 目录(1)关于用户帐号的类:Account(2)关于银行数据库的类:BankDatabase(3)关于ATM屏幕显示的类:Screen(4)关于ATM键盘的类:Keypad(5)关于进钞、出钞口的类:DepositSlot(6)关于ATM
      • Java设计模式之抽象工厂模式浅析讲解

      • 1.介绍 当系统准备为用户提供一系列相关对象,又不想让用户代码和这些对象形成耦合时,就可以使用抽象工厂模式。 2.如何实现 1)抽象产品--Car 2)具体产品--BYDCar、TSLCar 3)抽象
      • 如何动态替换Spring容器中的Bean

      • 目录动态替换Spring容器中的Bean原因方案实现Spring中的bean替换问题动态替换Spring容器中的Bean 原因 最近在编写单测时,发现使用 Mock 工具预定义 Service 中方法的行为特
      • C#优雅的实现INotifyPropertyChanged接口

      • INotifyPropertyChanged接口在wpF或WinFrom程序中使用还是经常用到,常用于通知界面属性变更。标准写法如下: class NotifandroidyObject : INotifyPropertyChanged {
      后台-插件-广告管理-侧边广告位三(PC)
      后台-插件-广告管理-侧边广告位三(手机)