终于来到第三天,今天我们来聊聊其他类型的指针,我尝试使用章节来叙述,增强可读性.

目录

const 型指针

1、const 型指针

2、指针常量

3、指向常量的指针常量

指针与函数

1、传递数组的指针性质

3、指针函数

4、void 指针

字符指针

1.字符串的表示

2、字符指针

3、字符串赋值


const 型指针

1、const 型指针

聊到指针,我们下意识的认为指针所指向的数据是“变量”,这是因为我们常常会混淆“指针变量”和“指针所指的数据”这两个概念。指针大多数时刻指向的是变量,但有时指针也会指向常量,定义指向常量的指针需要在定义语句的指针类型前加上 const,表示指向的对象是常量。

const int a=78;
const int b=28;

下面有两种常见错误,分别对应着一种概念难点:

const int a=78;
const int b=28;
int c=23;//定义一个常量
const int*p1=&a;//一个指向常量 a 的常量指针
*pi=58;//error:不可以修改常量指针指向的常量![1]
pi=&b;//correct:常量指针可以修改[2]

[1]:为什么不可以修改常量指针指向的常量?常量,字如其名,在本次运算里是不变的值,这就意味着无法通过间接引用来修改该值

[2]:为什么常数指针却又可以修改,指向不同的常量呢?那是因为指针本身是变量,允许修改变量的值(也有例外)

const 指针也被称为“只读”指针,因为定义指向常量的常量指针只限定指针的间接访问(引用)只能读而不能写,却没有对指针值的读写进行限制。

举一个例子,在 C 的学习里我们遇到过将一个数组值赋予另一个数组的任务,显然不能通过一个=来解决,在 c 中我们常用 for 循环来解决,这里有一个更加简洁的方法:

//test pointer const mode 2021-7-20-16:33
#include <iostream>
using namespace std;void mystrcpy(char*atg, const char*temp)
{while(*atg++=*temp++);//temp 指针得到了多次调用!因为其值可写
}int main()
{char a[20]="You look beautiful!";char b[20];mystrcpy(b,a);cout<<b<<endl;return 0;
}

result:

"/Users/yuwenao/C++ Learning/cmake-build-debug/untitled5"
You look beautiful!进程已结束,退出代码为 0

2、指针常量

顾名思义啦,指针本身就是常量!

在指针定义语句的指针名前加 const,表示指针本身是常量。

char*const pc="good";    //定义方法
pc="a girl";             //error:指针常量!无法改变指针值
*pc="b";                 //correct:可以改变指针所指量之值
*(pc+1)="c";             //correct
*pc++="d";               //error:常量无法自增自减!!
const int*b=28;
int*const pi=&b;         //error:无法将(int*)型指针转换为(int*const)型!

上面是一些使用警示!其实这两种指针都可以从字面上理解他们的本质,理解了本质,属性和性质自然不难。

定义指针常量必须初始化,否则无法确定地址

3、指向常量的指针常量

是不是很绕?一步一步理解:“指向常量”如字面意思,所指的数据是常量,这意味着这个指针对这个数据只有“读”的属性,不能“写”;“指针常量“,如上文所述,指针是常量,所指的地址是一定且确定的。两者结合,证明这个数据类型十分多限制,而由于它有指针常量的属性,定义指针常量必须初始化,否则无法确定地址。

const int ci=7;//定义一个常量
int ai;
const int* const cpc=&ci;//指向常量的常量指针
const int* const cp1=&ai;
cpi=&ci;//error:指针值无法修改
*cpi=39;//error:所指对象无法修改
ai=39;//correct!!!

指针与函数

1、传递数组的指针性质

一旦将数组作为参数传递到函数,则在栈上定义了指针,且可以对该指针进行加减操作。数组名和指针是等价的。

通过指针,我们可以实现一个函数”返回“多个值。这里牵涉到传值和传址的问题。例如:

//locationan & swap 2021-7-20 20-20-#include<iostream>
using namespace std;void swap(int,int);int main() {int a = 3, b = 8;cout<<"a="<<a<<",b=" << b << endl;swap(a, b);cout << "after swapping...\n";cout <<"a=" <<a << ",b=" << b << endl;
}void swap(int x,int y) {//交换两个形参int temp = x;x= y;y = temp;}

要实现的是两个数据的交换,我们看看结果:

"/Users/yuwenao/C++ Learning/cmake-build-debug/untitled5"
a=3,b=8
after swapping...
a=3,b=8进程已结束,退出代码为 0

整了张内存图

可以看到,两个数据没有成功交换。因为函数参数值的传递是实参到形参的复制,被调函数内部对形参的修改并不反映到调用函数的实参中,致使swap()中x和y作了交换,而main()中a和b并没有交换。传递指针可以使函数“返回”更多的值。这里的“返回”不是函数返回类型描述返回值的返回,而是反映了调用函数中的变量给被调函数修改了。例如,上面程序的完成版:

//locationan & swap 2021-7-20 20-31-correct#include<iostream>
using namespace std;void swap(int*,int*);int main() {int a = 3, b = 8;cout<<"a="<<a<<",b=" << b << endl;int*p1=&a,*p2=&b;swap(p1, p2);cout << "after swapping...\n";cout <<"a=" <<a<< ",b=" <<b<< endl;
}void swap(int*x,int*y) {//交换两个形参int temp = *x;*x= *y;*y = temp;}

结果是:

"/Users/yuwenao/C++ Learning/cmake-build-debug/untitled5"
a=3,b=8
after swapping...
a=8,b=3进程已结束,退出代码为 0

成功了,这就是传址,只有传址可以把函数值返回到原来变量处(可能从栈到全局变量区、堆区等)当然,处理好的数据(传址)是先从部分函数的栈出,到主函数的栈处储存,等待下一步操作。

我们再一次见识到了指针的强大——对硬件的绝对调控。但是仔细读读我们的标题:强大而危险的灵魂,你是不是在想,如此强大的伟力会带来怎么样的隐患?

没有错,指针的灵活是以破坏函数的黑盒特性为代价的,好了,有点兄弟会问,什么是黑盒啊?所谓“黑盒”,是指从用户的角度来看一个程序时,并不关心其内部构造和实现原理,而只关心程序的功能及如何使用这个程序,运用这些功能。它使函数可以访问本函数的栈空间以外的内存区域(函数的副作用初露端倪),以致引起了以下问题:
(1)可读性差:因为间接访问比直接访问相对难理解,函数声明与定义也相对比较复杂。
(2)重用性低:函数调用依赖于调用函数或整个外部内存空间的环境,丧失了黑盒的特性,所以无法作为公共的函数模块来使用。
(3)调试复杂:跟踪错误的区域从函数的局部栈空间扩大到整个内存空间。不但要跟踪变量,还要跟踪地址。错误现象从简单的不能得到相应的返回结果,扩展到系统环境遭破坏甚至死机。

3、指针函数

返回指针的函数。注意:指针函数不能将其内部说明的具有局部作用域的数据地址作为返回值,为什么?例如:

// pointer function 2021-7-20-21-51
#include<iostream>
using namespace std;int*getInt(char*str)//指针函数
{int value=20;cout<<str<<endl;return &value; //warning
}
void smoefn(char*str)
{int a=40;cout<<str<<endl;
}int main()
{int*pr=getInt("input a value:");cout<<*pr<<endl;smoefn("It is uncertain.");cout<<*pr<<endl;return 0;
}

该程序 getInt()函数返回一个局部作用域变量地址是不妥当的,因为该函数结束时,其栈内的变量 value 随之消失!在编译时,编译器给出了 warning。

很多同学问:诶,为什么在使用了 smoefn()函数后,指针间接引用的值改变了,明明主函数没有相关对该指针所指的变量重新赋值的操作啊?这里同学忽略了一个点,那就是两个函数的参数——指针是一样的,还原一下工作过程:在 main 中,指针 pr 得到了一个局部变量的地址且输出该地址之内容为“20”,随后调用了 smoefn()函数,该函数将前一个函数之栈空间作为自己工作的栈空间,因此函数返回后,是返回到这个曾经存储了“20”的栈空间里。

注意:可以返回堆地址、全局数据、静态变量数据地址,切勿返回局部变量地址!

4、void 指针

void 指针不指向任何类型,仅仅是一个地址(或者说储存一个地址),不能进行指针运算、间接引用。但空指针在两个指针交换数据时尤为关键,类似于 temp,但记得赋值给空指针时要强制类型转换!!!

字符指针

1.字符串的表示

在C++中,字符串是用双引号括起来的字符序列,简称字串,又称字符串字面值。当字符串用于字符数组初始化时,其在完成将内容填写到所创建的字符数组中之后,随即消失,不再另辟存储空间;而当字符串用于表达式,或输出,或赋值,或作参数传递,则其在运行中有它自己的存储空间,可以寻址访问。例如:

char buffer[] = "hello";//字符数组初始化
cout <<"good" <<endl;//字符串用于输出

在上面,"hello"用来给字符数组初始化,"good"字符串用来输出。

字符串的类型是指向字符的指针(字符指针char*),它与字符数组名同属于一种类型。字符串在内存中以'\0'结尾。这种类型的字符串称为C字符串,或ASCIIZ字符串(ASCII序列后跟Zero之意)。

2、字符指针

字符串、字符数组名、字符指针都是同一种数据类型。

输出字符指针就是输出字符串

输出字符指针的间接引用就是输出单个字符!

关于字符串的比较,我想先聊聊字符串的属性:我找了一张描述内存的绝世好图

字符串存放在 data 区的 const 小区里,若为全局变量,则存放于 globel 区(全局区)或者 Common 区(静态区),当编译器遇到一串字符串时,就将之存放于 const区且以‘\0’结尾,这样字符串就变成了“地址”,因为她有地址这一属性,所以同样的两个字符串“加拿大电鳗”在内存中地址不一,因此两个字符串比较其实就是地址比较,同理,也是数组名地址的比较,那有同学想,诶,我要的不是这种奇奇怪怪的比较啊,我是想逐个字符的比较啊,我该怎么做?
字符串比较应该是逐个字符一一比较,通常使用标准库函数 strcmp(),它在 string.h或cstring头文件中声明,其原型为:

int strcmp(const char* strl,const char* str2);

其返回值如下:
(1)当strl串等于str2串时,返回值0;
(2)当strl串大于str2串时,返回一个正值;
(3)当strl串小于str2串时,返回一个负值。

3、字符串赋值

C++中可以使用字符串对一个字符数组初始化,但是却不能对一个已存在,初始化成功的字符数组赋值,因为数组名是常量,无法充当左值。

可以用 strcpy()对字符数组赋值,它包含在 string.h 中。原型为:

char *strcpy(char *dest, const char *src) //把 src 所指向的字符串复制到 dest。

需要注意的是如果目标数组 dest 不够大,而源字符串的长度又太长,可能会造成缓冲溢出的情况。如何应用?情况实例:

#include <stdio.h>
#include <string.h>int main ()
{char str1[]="Sample string";char str2[40];char str3[40];strcpy (str2,str1);strcpy (str3,"copy successful");printf ("str1: %s\nstr2: %s\nstr3: %s\n",str1,str2,str3);return 0;
}

result:

str1: Sample string
str2: Sample string
str3: copy successful

完成于 2021-7-20-22:45 致理楼 L1

2021-7-20 指针:强大而危险的灵魂【C++指针的应用---中下】(炉边小坐)相关推荐

  1. 市面上主流编辑器介绍(2021/05/20)

    市面上主流编辑器介绍(2021/05/20) 背景 Markdown是一种有用的轻量级标记语言,后续Markdown简写为md. 富文本编辑器(Rich Text Editor,RTE)是一种可内嵌于 ...

  2. 20个强大的jQuery翻书插件【 jQuery flipbook】

    ​ 许多网站使用jQuery翻书插件来展示产品目录和销售广告册子.jQuery翻页书解决方案给访客提供了方便而有效的浏览一套东西的体验.如果做得好,就如同手头有一本印刷版的册子.通过翻页书插件,你可以 ...

  3. 【不忘初心】Win10_LTSC2021_19044.1381_X64_可更新[纯净精简版][2.52G](2021.11.20)

    此版可正常更新补丁,母版来自UUP WIN10_LTSC2021 19044.1288集成补丁到19044.1381为了保证稳定初心的系统全部都是离线精简和优化,非二次封装.系统纯净.流畅.进程少无任 ...

  4. PowerBI视觉对象共计271组,2021.01.20日更新

    PowerBI视觉对象共计271组,2021.01.20日更新 内容包含导入文件和图标.预览图.文件名一致,在预览图内找到合适的可以直接在视觉对象文件夹搜索 下载地址:点击下载 超便宜 或者复制链接打 ...

  5. 2021.05.20最少数量的箭引爆气球

    2021.05.20最少数量的箭引爆气球 题目描述 在二维空间中有许多球形的气球.对于每个气球,提供的输入是水平方向上,气球直径的开始和结束坐标.由于它是水平的,所以纵坐标并不重要,因此只要知道开始和 ...

  6. 普转题比赛2021/7/20

    普转题比赛2021/7/20 射命丸文 考试ing 正解 帕秋莉·诺蕾姬 考试ing 雾雨魔理沙 考试ing 正解 伊吹萃香 考试ing 正解 知道这次是老刘出题就有一种不祥的预感,毕竟之前他出题的时 ...

  7. GMOJ - 2021.07.20【普及组】模拟赛C组 - 排座椅(seat)、传球游戏(ball)、立体图(drawing)、间谍派遣、seek

    文章目录 luogu博客链接 GMOJ - 2021.07.20[普及组]模拟赛C组 - 排座椅(seat).传球游戏(ball).立体图(drawing).间谍派遣.seek T1 排座椅(seat ...

  8. 记第一次Python数据分析练习——2018年“泰迪杯”数据分析职业技能大赛B题(2021/5/20)

    文章目的 本人目前是应用统计专业大二(2021/5/20)的本科生,上学期上过Python课,但说实话讲的不深,过了一个学期也基本上忘光了. 最近深刻地觉得计算机专业真是好啊,以后我也要当程序员.JP ...

  9. [Acmer日志]2021/3/20星期六,天气多云,小冷

    [Acmer日志]2021/3/20星期六,天气多云,小冷 今日算法 树状数组 差分树状数组 双重树状数组--区间修改区间查询 今日AC数: 1 今日总结: 明天目标 今日鸡汤 今日bgm 今日算法 ...

  10. 尚硅谷——谷粒商城项目开发记录——2021.11.20

    尚硅谷--谷粒商城项目开发记录--2021.11.20 概念: 1.SpringCloud Alibaba: 简介: Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案.此 ...

最新文章

  1. 2019年,我终于知道86版西游记到底好在哪里了
  2. springboot集成mybatis-generator时候遇到的问题
  3. DevExpress的下拉框控件ComboBoxEdit控件的使用
  4. 通过过滤器防止用户通过url访问不在权限内的菜单
  5. koa连接mysql怎么做_koa-连接mysql数据库
  6. PCL的学习必要性、重要性、意义及最初——持续修改中
  7. orcale的rank(排名函数)实例
  8. Oracle一定有sqlplus吗,oracle sqlplus执行sql文件
  9. 关于jstl.jar引用问题及解决方法
  10. c语言实参和形参占用存储单元_C语言判断题题库
  11. linux 关闭自动升级,开启关闭Centos的自动更新(转)
  12. Particle Filter Tutorial 粒子滤波:从推导到应用(四)
  13. Vnc-server——linux远程桌面配置
  14. 精华阅读第7期|程序员职业人生规划的三点建议
  15. Next主题美化博客
  16. Python脚本自动化运维网络设备
  17. sh计算机c盘如何管理,c盘瘦身三种方法详解
  18. Ubuntu20.04系统联网
  19. 北京邮电大学计算机网络教材,北京邮电大学《计算机网络》4.pdf
  20. 计算器存储功能怎么用_数控车床加工刀具补偿功能怎么用?

热门文章

  1. 新装MySql后登录出现root帐号提示mysql ERROR 1045 (28000): Access denied for use的解决办法
  2. 修改计算机照片格式怎么修,电脑上如何修改照片文件大小?2种免费方法简单解决...
  3. Unity Line接入
  4. MP4提取音频文件,并且转换为16KHz采样率 16 bit
  5. python 实验七 字典与集合 (下)
  6. C# 报错 provisional headers are shown learn more
  7. Faraway(枚举 去绝对值)
  8. 本地 Git 文件夹显示绿色标识
  9. ubuntu 多声卡设置 默认声卡 systemd自启动声卡设置
  10. HTML5期末大作业:餐饮文化网站设计——餐饮文化(8页) HTML+CSS+JavaScript 学生DW网页设计美食文化