当前位置: 首页 > news >正文

指针

指针:指针本身是一个变量,他的值为另一个变量的内存地址。申明如下: int *dp; 。举个栗子来认识一下指针:

 1 #include <iostream>
 2 using namespace std;
 3 
 4 int main()
 5 {
 6     int tempone = 20;
 7     int *temptwo;
 8     
 9     temptwo = &tempone; //获取tempone的地址赋值给temptwo;
10     
11     cout << "temptwo = " << temptwo << endl;
12     printf("*temptwo = %d\n",*temptwo);
13 }

我们看到temptwo是存了tempone的内存地址,*temptwo通过地址访问到了tempone的值。

值传递、指针传递、引用传递:

  • 值传递:形参是实参的拷贝,改变形参的值并不会影响外部实参的值。从被调用函数的角度来说,值传递是单向的(实参->形参),参数的值只能传入,不能传出。当函数内部需要修改参数,并且不希望这个改变影响调用者时,采用值传递。
  • 指针传递:形参为指向实参地址的指针,当对形参的指向操作时,就相当于对实参本身进行的操作
  • 引用传递:形参相当于是实参的"别名",对形参的操作其实就是对实参的操作,在引用传递过程中,被调函数的形式参数虽然也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。

让我们举个栗子:

 1 #include <iostream>
 2 using namespace std;
 3 
 4 void one(int a){a = a + 100;}
 5 void two(int *a){*a = *a + 20;}   //*a 通过地址取到了b的值
 6 void three(int &a){a = a + 30;} //&a 通过b取到了b的地址,然后在地址处进行操作
 7 
 8 int main()
 9 {
10     int b = 10;
11     one(b); //值传递,相当于直接把值给形参了
12     printf("b = %d\n",b);
13     
14     two(&b);//指针传递,传递给形参的是实参的地址,然后根据地址对b进行操作
15     printf("b = %d\n",b);
16     
17     three(b); //引用传递,函数里取到了b的地址的位置,然后对b进行操作
18     printf("b = %d\n",b);
19 }
  • & 符号的意思是取地址,也就是返回一个对象在内存中的地址。
  • * 符号的意思是取得一个指针所指向的对象。 也就是如果一个指针保存着一个内存地址,那么它就返回在那个地址的对象。
  • 简单点就是:&:取址。* :取值。

函数指针:函数存放在内存的代码区域内,它们同样有地址.如果我们有一个函数,那么,它的地址就是函数的名字,这一点如同数组一样,数组的名字就是数组的起始地址。如: int (*dp)(int x, int y); 

举个栗子:

 1 #include <iostream>
 2 using namespace std;
 3 
 4 int temp(int a)
 5 {
 6     a++;
 7     return a;
 8 }
 9 
10 int main()
11 {
12     int ex = 0;
13     int (*dp)(int a);   //这里就定义了一个函数指针,这里要求和定义函数的函数头一致
14     dp = temp; //把temp的地址赋给dp
15     ex = dp(5);  //通过函数指针找到函数进行计算
16     printf("ex = %d", ex);
17     return 0;
18 }

结果为: ex = 6 。但我们对于函数指针通常用到把函数指针当参数传递来达到我们的目的。举个栗子:

 1 #include <iostream>
 2 using namespace std;
 3 
 4 int temp(int a)
 5 {
 6     a++;
 7     return a;
 8 }
 9 
10 int student(int (*dp)(int a))
11 {
12     int ex = 0;
13     ex = dp(5);  //通过函数指针找到函数进行计算
14     printf("ex = %d", ex);
15     return 0;
16 }
17 
18 int main()
19 {
20     int (*dp)(int a);   //这里就定义了一个函数指针,这里要求和定义函数的函数头一致
21     dp = temp; //把temp的地址赋给dp
22     student(dp);  //这里把函数指针做为参数传递
23     return 0;
24 }

结果依然为: ex = 6 

指针的运算:指针是一个用数值表示的地址。因此,您可以对指针执行算术运算。可以对指针进行四种算术运算:++、--、+、-。‘栗子在这里:

 1 #include <iostream>
 2 using namespace std;
 3 
 4 int main()
 5 {
 6     int array[4] ={1,2,3,4};
 7     int *dp;
 8     dp = array;
 9     int i;
10     for(i=0;i<4;i++)
11     {
12         cout << "第一个数为:"
13             <<array[i]
14             <<",他的地址为:"
15             <<dp
16             <<endl;
17         dp++;
18     }
19     printf("\n");
20     dp = &array[2];
21     for(i=2;i<4;i++)
22     {
23         cout << "第一个数为:"
24             <<array[i]
25             <<",他的地址为:"
26             <<dp
27             <<endl;
28         dp--;
29     }
30 }

结果为:

第一个数为:1,他的地址为:0x7ffce6e13030
第一个数为:2,他的地址为:0x7ffce6e13034
第一个数为:3,他的地址为:0x7ffce6e13038
第一个数为:4,他的地址为:0x7ffce6e1303c

第一个数为:3,他的地址为:0x7ffce6e13038
第一个数为:4,他的地址为:0x7ffce6e13034

 数组指针和指针数组的区别:https://www.cnblogs.com/mq0036/p/3382732.html 数组指针强调的是指针,他指的是一个数组的指针;指针数组强调的是数组,他指的是一个数组里面的指针元素。

 指向指针的指针:因为指针是个变量,他自己也是有地址的,所以指向指针的指针就是把存有其他变量地址的这个指针变量的地址存到另一指针中。他的申明如下: int **pr; 。举个栗子说明:

 1 #include <iostream>
 2 using namespace std;
 3 
 4  int main()
 5  {
 6      int temp = 0;
 7      int *pr = 0;
 8      int **prr = 0;
 9      
10      cout << "pr = " <<pr <<endl;
11      cout << "prr = " <<prr <<endl <<endl;
12      
13      pr = &temp;   //得到变量temp的地址
14      prr = &pr;    //得到指针pr的地址
15      
16      cout << "pr = " <<pr <<endl;
17      cout << "prr = " <<prr <<endl <<endl;
18  }

 

 结果: pr = 0 prr = 0 pr = 0x7ffe64e6074c prr = 0x7ffe64e60740 

 指针作为参数传递给函数:我先看个例子(注意:&a 是整个数组的首地址,a是数组首元素的首地址,其值相同但意义不同。):

 1 #include <iostream>
 2 using namespace std;
 3 
 4 void test_one(int *pr)   //指针参数为单个值的时候
 5 {
 6     *pr = 5;
 7 }
 8 
 9 int test_two(int *array)  //指针参数为数组的首地址或者元素的首地址的时候
10 {
11     int temp = 0;
12     temp = array[1];
13     return temp;
14 }
15 
16 int main()
17 {
18     int array[3] = { 10,11,12 };
19     int pr = 0;
20     int getvalue = 0;
21     
22     test_one(&pr);   //取pr的地址
23     cout << "pr = " << pr << endl;  
24 
25     getvalue = test_two(array);  //取array的首个元素的地址
26     cout << "getvalue = " << getvalue << endl;
27     return 0;
28 }

 

结果为: pr = 5    getvalue = 11 

我发现当传递的参数指针所指向的地址是单个元素的时候不就是我们的指针传递吗,当指向的地址为多个元素的时候不就是数组中的把数组作为参数传递给函数(通过指针方式传递)吗?其实就是的。因为本身数组名是个内存地址,而指针的值也是内存地址。

指针作为函数的返回值:其实指针作为函数的返回值跟数组作为函数的返回值也是一致的。只不过指针作为返回值时会区分单个元素还是像数组一样的多个元素。我们还是以栗子来说明:

 1 #include <time.h>
 2 #include <iostream>
 3 using namespace std;
 4 
 5 int *temp_one(int x)  //定义一个返回值为指针的函数(单个元素)
 6 {
 7     static int *pr = 0;//c++不允许在函数外返回局部变量的地址,除非定义static变量
 8     int y = x+1;
 9     pr = &y;   //取到参数地址
10     return pr;  //返回指针
11 }
12 
13 int *temp_two(int *array)    //定义一个返回值类型为指针(多个元素)、参数为指针的函数
14 {
15     static int array_temp[10];  //C++不允许在函数外返回局部变量的地址,除非定义为static变量
16     int i;
17     srand((int)time(0));  //时间作为随机数的种子
18     for (i = 0; i<10; i++)
19     {
20         array_temp[i] = array[i];  //取到array的前五个值给array_temp
21         if ( i >= 5 )
22         {
23             array_temp[i] = rand() % 100; //把五个随机数给array_temp的后5个值
24         }
25     }
26     return array_temp;  //返回指针
27 }
28 
29 int main()
30 {
31     int one = 1;
32     int *pr;
33     int *pr_array;
34     int array[10] = { 1,2,3,4,5 };
35     pr = temp_one(one);
36     cout << "*pr = " << *pr << endl;
37     pr_array = temp_two(array);
38     for (size_t i = 0; i < 10; i++)
39     {
40         cout << "pr_array["<< i << "] = " << pr_array[i] << endl;
41     }
42     return 0;
43 }

 结果为:

*pr = 2
pr_array[0] = 1
pr_array[1] = 2
pr_array[2] = 3
pr_array[3] = 4
pr_array[4] = 5
pr_array[5] = 48
pr_array[6] = 38
pr_array[7] = 13
pr_array[8] = 80
pr_array[9] = 92

 

转载于:https://www.cnblogs.com/xiaodangxiansheng/p/10908246.html

相关文章:

  • 第二周 词频统计
  • java之struts2的action的创建方式
  • linux安装openssl、swoole等扩展的具体步骤
  • CSS 分享
  • VS2017 常用快捷键
  • Vue.js源码(2):初探List Rendering
  • 如何把文字转换成语音,文字转语音转换器能帮你
  • 面试官:你接受免费加班吗?程序员这样怼回去,网友:老铁没毛病
  • fseek的使用
  • assert()函数用法
  • Python Day29
  • java socket之多人聊天室Demo
  • NCRE考试感想 四级嵌入式(下)
  • ps调整图层
  • 使用zabbix系统批量监控Url返回码
  • (十五)java多线程之并发集合ArrayBlockingQueue
  • 「面试题」如何实现一个圣杯布局?
  • 5分钟即可掌握的前端高效利器:JavaScript 策略模式
  • ES6系统学习----从Apollo Client看解构赋值
  • HTTP传输编码增加了传输量,只为解决这一个问题 | 实用 HTTP
  • iOS动画编程-View动画[ 1 ] 基础View动画
  • JavaScript实现分页效果
  • Perseus-BERT——业内性能极致优化的BERT训练方案
  • 从tcpdump抓包看TCP/IP协议
  • 关于springcloud Gateway中的限流
  • 缓存与缓冲
  • 基于 Babel 的 npm 包最小化设置
  • 紧急通知:《观止-微软》请在经管柜购买!
  • 看图轻松理解数据结构与算法系列(基于数组的栈)
  • 聊聊hikari连接池的leakDetectionThreshold
  • 前端自动化解决方案
  • 文本多行溢出显示...之最后一行不到行尾的解决
  • 我的面试准备过程--容器(更新中)
  • LIGO、Virgo第三轮探测告捷,同时探测到一对黑洞合并产生的引力波事件 ...
  • 哈罗单车融资几十亿元,蚂蚁金服与春华资本加持 ...
  • ​ssh-keyscan命令--Linux命令应用大词典729个命令解读
  • #LLM入门|Prompt#2.3_对查询任务进行分类|意图分析_Classification
  • (6)设计一个TimeMap
  • (C++)八皇后问题
  • (Redis使用系列) Springboot 使用redis实现接口幂等性拦截 十一
  • (七)微服务分布式云架构spring cloud - common-service 项目构建过程
  • .NET 2.0中新增的一些TryGet,TryParse等方法
  • .net core IResultFilter 的 OnResultExecuted和OnResultExecuting的区别
  • .NET 中选择合适的文件打开模式(CreateNew, Create, Open, OpenOrCreate, Truncate, Append)
  • .NET/MSBuild 中的发布路径在哪里呢?如何在扩展编译的时候修改发布路径中的文件呢?
  • .project文件
  • [.net] 如何在mail的加入正文显示图片
  • [20171113]修改表结构删除列相关问题4.txt
  • [Android Pro] android 混淆文件project.properties和proguard-project.txt
  • [Android]Android P(9) WIFI学习笔记 - 扫描 (1)
  • [c]统计数字
  • [C++]——带你学习类和对象
  • [C++]模板与STL简介
  • [codeforces]Checkpoints
  • [error] 17755#0: *58522 readv() failed (104: Connection reset by peer) while reading upstream