c++的指针学习(长期更新,诚求指点)
1.第一部分,关于指针的基础
指针的定义语法
int * a=a;
(int*是一种数据类型)
指针内部储存着的是一块地址
可以借用指针的解引用操作,通过指针直接去访问一个变量
指针指向变量(存入地址)的时候,要在前面加入& 表示这个变量的地址,不加则代表直接对对应地址所在的变量进行修改(通过指针访问地址空间)
指针在输出的时候,*p代表解引用,直接代表那个被指向的空间
而单纯输出名字,只是输出指针下面储存的十六进制数字(地址字符串)
//1,关于指针的基础typedef int* pointNeedle;//pointNeedle a = &2;指针类型存的是地址,你不能拿没有开辟空间的东西来调戏他..int a = 12;pointNeedle a1 = &a;//往指针类型里面存入数据的时候,注意村也是只能存地址//在变量前面加上一个&就代表这个玩应的地址//而输出的时候有两种情况//第一个,就是单纯输出指针里面的数值,也就是存在的地址// //第二个,前面加上指针进行解引用,输出会直接按着地址导向指针指着的东西//其中第一个应该叫做解引用操作,*p直接导向p中所储存的地址,操作*p就可以顺着地址操作a;//(指针解引用对于地址对应空间的数据的修改)cout << "a=" << a << endl;*a1 = 123;cout << "a=" << a << endl;cout << "*ai=" << *a1 << endl;
2.关于空指针和野指针
//2.关于空指针//空指针指的是仅仅初始化没有赋值,null的指针//实际上底层指向的是为0的空间,但是无权进行访问,必须再付给指针名称一个可以操控的地址int* assss;//3.关于野指针//野指针指的是指向了一块非程序员申请的,而且无权操控的空间//语法是不会出任何问题的,但是就不行.....int* asssss = (int*)0x1234;
(对了强调一个事情,包括空指针指向的0地址,0-255地址中都代表系统的空间,除非砸开硬盘,无权修改)
空指针和野指针的共同特点就素,都不是程序员申请的空间,无法调用,因此尽量不要出现这东西
另外,如果是new创建出来的堆空间元素,必须进行手动删除,在Java里面可以使用jvm自动删除,但是cpp不行,所以程序员必须手动删除,另外新建出来的对象可以使用指针进行接收,释放的时候不需要解引用
int * arr=new int(6);
delete arr;
另外注意一点,删除的时候如果是数组,那么一定要全部删除!\
比如这种方式 ---delete p[];
不然只会删除首地址
3.关于指针和数组;
指针可以用来遍历数组,其中指针每次自增(++操作),都是偏移和数据类型一致的字节,宏观来看,无论是啥数据类型都是跳一个位置;
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int* point = arr;//数组名其实就是第一个的地址for (int i = 1; i <= 10; i++) {cout << *point << endl;//因为这里是整形,所以指针自动移动四个字节//和迭代器Iteritor还不一样point++;}
(1)关于这里和迭代器的区别,迭代器是插在两个数据中间的,判断方法是hasnext.
而指针在这里直接锁定再地址上,可以理解为直接定位再数据自己的头上
(2)关于遍历数组的时候发生越界,不会报错但是会输出这个数字
//-858993460//这个其实不是地址,也不是null,是被自动填充成的数字
(3)指针指向数组的时候有个建议就是,要么直接指向数组的第一个元素,要摸作为参数的时候直接传入地址名字(因为多维数组是不能与int*这种指针类型相互匹配的)
4.关于指针/地址作为参数传入,然后再方法体内部操控数据
void swap(int* p, int* b) {int temp = *p;*p = *b;*b = temp;
}
int a2 = 12;int b2 = 13;swap(&a2, &b2);cout << "a=" << a2 << endl;cout << "b=" << b2 << endl;
//输出为13和12,顺序已经颠倒了
方法传入的是指针/地址,把ab两个数据的地址传入进去,就可以在sawp内部修改数值了
在swap方法内,对两个传入的地址进行解引用,就可以操作数值了
将变量的地址传入方法,让方法中和外面共用一个地址进行数据操作.java中只能通过封装,这里可以用指针调用基本数据类型,java基本做不到这一点.
(深刻理解一下解引用)!!!!!!
5.关于const修饰指针的几种情况
//1.先构建一个常量指针//常量指针的特点,可以修改指向,但是不能修改指向的数值//记忆方法:const修饰的是*,对于解引用进行限制,地址可以随意更换//但是无法利用例如"*a=12"的解引用操作进行修改const int* p1 = &a;//2.再构建出一个指针常量//指针常量的特点是,可以对于数值进行修改,但是不能修改这个指针的指向//记忆方法为:const修饰的是p2,直接限制了里面储存的十六位地址不能动,但是可以按照这个死路进行修改int* const p2 = &a;//第三种,同时对解引用和内部地址进行限制的方法//现在好了,指向和地址都不能修改了const int* const p3 = &a;
(一个使用示例:利用指针传输数组头位的地址,在方法中对数组进行修改)
(注:只要得到数组头位置的地址,就可以对数组整体进行修改,数组名其实就是数组第零位的地址,所以这里传入的只是数组名,方法里面使用的时候也是直接用名字,无需解引用即可需改)
void bub(int * arr) {//整个好像是做不到的 int arr2[] = * arr;//这里好像传入首位的地址就能使用整个数组//大概是数组的特性?只要得到第一位的地址就可以改动整个数组//而且我是试了一下,做不到打开整个数组指针类型好像........for (int i = 0; i < 9; i++) {for (int j = 0; j< 10 - 1 - i; j++) {if (arr[j] >= arr[j + 1]) {int temp = arr[j];arr[j] = arr[j+1];arr[j+1] = temp;}}}
int arr2[10] = {2,3,4,5,6,7,8,9,10,1};bub(arr2);//在传入地址的时候直接传入数组第一位的地址就行//不用传入整个数组的地址...............................int* point2 = arr2;for (int i = 1; i <= 10; i++) {cout <<* point2 << endl;//这里记得要在读入数据的时候进行解引用point2++;}
6.关于结构体指针;
利用结构体指针访问结构体中的某个属性的时候,可以不解引用,直接用指针名字->属性名字
就可以调用了.(->,,,,貌似vs里面会自己跳出来,作用类似.)
struct student {string name;};struct student arry[3] = {{"dijia"},{"daina"},{"gaiya"}};student* point12 = arry;
------------------------------------------------------------
- //cpp没有提供查询数组长度的方法,所以我们应该是用的是 |
- int longlonglong = sizeof(arry) / sizeof(arry[0]); |
------------------------------------------------------------for (int i = 1; i <= longlonglong; i++) {//使用 指针名字->属性名字 就可以利用指针调用相应的属性了cout << point12->name << endl;point12++;}
(其中这里还有一个查询数组的方法,总字节数除以每个元素的字节数,不过对于太复杂的数组不一定管用)
7.关于指针类型的强制转化
空类型指针void*,可以指向任何的数据类型
void* s;//但是使用并不是无限制的s = (int*) & a;//这个让指针可以理解整数,这里要强转,不然s作为void指针是无法识别地址的
(类型 *)起到的是对地址/指针进行类型强转的作用
----------------------------------------------------------------------------
比较常用的就是"(void *)"代表转化成一个纯地址的类型
效果类似取地址符号(&);
--------------------------------------------------------------------------
再举个例子,野指针进行赋值的时候
int* s=(int*)0x22 ;//野指针也要指明是地址,不能用数值赋值
不能给指针输入一个野地址,这里一开始会默认是一个十六进制数字,必须指明这是一个int*类型的指针
8.关于解引用和自增运算符号的先后和连用
(1)先说结论,运算顺序为"前后分开看"
(一) (前自增/解引用)
前自增和解引用,谁先接触point谁先起作用,依次向外发挥作用
如果没有解引用,那么效果就是地址偏移,如果解引用已经发生,那么效果就是数值变化
(二)关于(后自增)
如果没有括号保护,都是对地址进行偏移
(2)
//其实一共只有这三种情况-------------------------------------------------
// =*p++ 赋值,然后地址发生偏移,
// =++*p 先解引用,再进行自增(数值)
// =*++p 先自增(地址),再进行解引用
// =(++p)* =p++*没有这种乱七八糟的东西orz;
(3)关于多重连用的一个举例
int a1[] = {3,4};int* ass = &a1[0];int bb = *ass++;//举个例子这样的,输出结果应该是五//先进行地址自增,然后解引用,再对对应地址的数值进行自增//先偏移到4,然后4自增输出5cout << "结果就是" <<bb << endl;
9.关于三种特殊的指针迭代方式
char arr[] = {'1','2'};char* pp= arr;
(1)关于*(p+i)的形式
for (int i = 0; i <= 1; i++) {cout << *(pp + i) << endl;}
(2)关于指针直接自增p++
for (int i = 0; i <= 1;i++ ) {cout << *(pp ) << endl;pp++;}
另一种友好写法*p++(先输出数值,再地址偏移)(实用)
for (int i = 0; i <= 1;i++ ) {cout << *pp++ << endl;}
(3)使用指针作为角标,这个
for (int i = 0; i <= 1;i++ ) {cout << pp[i] << endl;}
这里要注意一件事情,指针作为角标的时候
例如arr= 1 2 3 4 5 6 7
*point=arr[1]
则point[1]其实就是arr[2];
结构如下
----------------------------------------------------
arr[0] |
1 2 3 4 5
point point[1] |
(point[0])
---------------------------------------------------|
10,关于字符串使用指针
字符串使用指针的方法为,直接指向字符串的第一个字符
char* point = &str[0];//好家伙能用这种方法进行指向一个字符串
至少我的编译器做不到直接指向字符串名字,一般直接指向首地址
另外补充一个重点,一旦输出的是数组首地址的解引用,那么就会输出整体的字符串/数组全部元素
11.关于指向指针的指针
定义方式
//指向指针的指针int a = 1;//int** p = && a;这种操作是错的,不能连续取地址int* i =&a;//只能接受一个指针的地址,也要加上 &int** p = &i;//p--->i--->a
储存的是另一个指针所占用的地址
通过连续解引用,可以访问最下面的东西
举个例子,访问指针数组的时候
*(* (point + 1) + 2)--------其实就是point[1][2]
文字解读:首先point偏移一位,再解引用,就是第一行的首地址
第一行的首地址再偏移两位,再解引用,就是第一行第二个的东西
13.关于数组和指针有四种形式
int point[2][3];//单纯的,长度为12的一个连续的数组int(*point)[3];//为指向数组的指针,n行3列的数组,内存必然连续int* point [3];//为存了地址的数组,3行n列的数组,内存可以不连续int **point;//指向指针的的指针,完全可以不连续,
阅读方法为*(*(point+1)+2) 其实就是point[1][2]
前面两个是内存连续的,但是后面两个是内存连续的
关于
int(*point)[3];//为指向数组的指针,n行3列的数组,内存必然连续
int* point [3];//为存了地址的数组,3行n列的数组,内存可以不连续
看似效果差不多但本质上完全不一样
前者是指向数组首地址的指针,
比如指向一个数组{123456}的时候,指针一开始指向的是1,但是一旦偏移一下指针,就指向4了
而后者则是一个储存地址的数组
见下表就算两者的区别
指针指针常见用法是这样的
string a1 = "jdjd";string a2 = "jdjd";string a3 = "jdjd";char * ass[] = { &a1[0],&a2[0],&a3[0]};char** as = ass;//这样存入的就是a1[0]这个地址
输出就是j
c++的指针学习(长期更新,诚求指点)相关推荐
- tikz绘图学习(长期更新)
tikz基于latex tikz生成的图片只能是嵌入在pdf中的,要想转换成其他格式还需要额外的处理,例如使用imagegick. tikz right of的用法 见上图,使用right of可以精 ...
- (*长期更新)软考网络工程师学习笔记——Section 6 网络层上篇
目录 一.网络层的定义 二.IPv4数据报 三.IPv4 (一)分类依据 (二)IP地址分类 (三)网络.主机号位数 (四)特殊IP地址 四.划分子网 五.子网掩码 (一)默认子网掩码 (二)VLSM ...
- (*长期更新)软考网络工程师学习笔记——Section 2 数字传输系统
目录 前言 一.PCM体制 (一)E1 (二)T1 (三)复用 二.SONET(同步光纤网) 三.SDH(同步数字系列) 前言 本系列属于全国计算机技术与软件专业技术资格考试(软考)中级网络工程师的长 ...
- python爬虫文件代码大全-Python网络爬虫实战项目代码大全(长期更新,欢迎补充)...
WechatSogou[1]- 微信公众号爬虫.基于搜狗微信搜索的微信公众号爬虫接口,可以扩展成基于搜狗搜索的爬虫,返回结果是列表,每一项均是公众号具体信息字典.[1]: https://github ...
- python代码大全p-Python网络爬虫实战项目代码大全(长期更新,欢迎补充)
WechatSogou[1]- 微信公众号爬虫.基于搜狗微信搜索的微信公众号爬虫接口,可以扩展成基于搜狗搜索的爬虫,返回结果是列表,每一项均是公众号具体信息字典.[1]: https://github ...
- Java代码优化(长期更新)
前言 2016年3月修改,结合自己的工作和平时学习的体验重新谈一下为什么要进行代码优化.在修改之前,我的说法是这样的: 就像鲸鱼吃虾米一样,也许吃一个两个虾米对于鲸鱼来说作用不大,但是吃的虾米多了,鲸 ...
- python 微信支付接口 详解_Python支付接口汇总大全(包含微信、支付宝等,长期更新、欢迎补充)...
wzhifuSDK- 由微信支付SDK 官方PHP Demo移植而来,v3.37下载地址 学习Python中有不明白推荐加入交流群 号:864573496 群里有志同道合的小伙伴,互帮互助, 群里有不 ...
- python基础代码大全-Python网络爬虫实战项目代码大全(长期更新,欢迎补充)
WechatSogou[1]- 微信公众号爬虫.基于搜狗微信搜索的微信公众号爬虫接口,可以扩展成基于搜狗搜索的爬虫,返回结果是列表,每一项均是公众号具体信息字典.[1]: https://github ...
- Python网络爬虫实战项目代码大全(长期更新,欢迎补充)
Python网络爬虫实战项目代码大全(长期更新,欢迎补充) 阿橙 · 1 个月内 WechatSogou [1]- 微信公众号爬虫.基于搜狗微信搜索的微信公众号爬虫接口,可以扩展成基于搜狗搜索的爬虫, ...
最新文章
- 硬盘格式化与快速格式化的区别
- 一文带你全面了解电商在线支付
- java高效遍历匹配,使用cypher或遍历api仅匹配路径极端的单个节点
- ServletUriComponentsBuilder遇到Nginx反向代理时,无法识别HTTPS
- “老师,我写着写着就 强制交卷了……”
- 互联网传真 传真指令_传真的完整形式是什么?
- (2)MyBatis简介
- 「Mac新手必备」解决 Mac 无法启动、开机的问题
- android color属性黑色,android – 未找到样式属性attr / colorSecondary
- 阿里是怎么做全链路压测的?
- 新颖的基于物联网毕业设计题目50例
- iso硬盘安装 凤凰os_凤凰系统安装教程-凤凰虚拟机2.0(Phoenix OS)下载v3.6.1可重启版-西西软件下载...
- Python学习[4]:urllib库-爬虫的第三步之代理IP
- 知乎上 40 个有趣回复,很精辟很提神
- 逃避追债?贾跃亭把法拉第未来股权转给了外甥,但他还有5套豪宅! | 焦点
- 在Mac上模拟IE浏览器
- 怎样删除*.sys文件
- SUSE配置zypper
- PATINDEX 的纯 T-SQL 全部替换函数
- 【看表情包学Linux】了解操作系统 | 目录内容的显示 | 目录跳转 | 基本创建与删除操作