深入理解指针(2)
1.const修饰指针
加上const后就修改不了了
const 使得a具有了常属性,所以a就不能被修改了
但是注意a本质上还是变量,不是常量,是常变量。
但在C++中const修饰的变量就是常量
但是如果我们绕过a,使⽤a的地址,去修改a就能做到了,虽然这样做是在打破语法规则。
我们可以看到这⾥⼀个确实修改了,但是我们还是要思考⼀下,为什么n要被const修饰呢?就是为了 不能被修改,如果p拿到n的地址就能修改n,这样就打破了const的限制,这是不合理的,所以应该让 p拿到n的地址也不能修改n,那接下来怎么做呢?
//const修饰指针变量时放在*的右侧。其限制的是指针变量p本身,指针变量不可以再指向其他变量,但是可以通过指针变量,修改指针变量所指向的内容。
对于这段代码
由此我们可以得到以下信息:
1.p中可以存放一个地址
2.*p—>a—>10
3.&p—>0x0012ff48
我们继续运行代码:
由此可见:
const修饰指针变量时,放在*左边,限制的是:指针指向的内容,不能通过指针来修改所指向的内容。但是可以修改指针变量本身的值(修改的指针变量的指向)
结论:const修饰指针变量的时候
• const如果放在*的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变。 但是指针变量本⾝的内容可变。
• const如果放在*的右边,修饰的是指针变量本⾝,保证了指针变量的内容不能修改,但是指针指 向的内容,可以通过指针改变。
2.指针运算
(指针的作用就是访问内存的!)
1.指针+-整数
指针+1
int a = 10;
int* p = &a;
p + 1 --->跳过4个字节
--->1*sizeof(int)
____________________________
type* p = &a;
p + 1 --->跳过4个字节
--->1*sizeof(type)
_____________________________
type* p = &a;
p + n --->跳过4个字节
--->n*sizeof(type)
因为数组在内存中是连续存放的,只要知道第⼀个元素的地址,顺藤摸⽠就能找到后⾯的所有元素。
用指针方式打印:
//p+i 这⾥就是指针+整数
2.指针-指针
日期+天数
日期-天数
指针+整数
——————————————————
日期-日期 —— 中间的天数
指针-指针 —— 得到的是两个指针的元素个数
——————————————————
日期 + 日期 = ???没有这个操作
指针 + 指针 = ???也没有该操作
——————————————————
指针 - 指针计算的前提条件是:两个指针指向了同一块空间!
所以:
|指针 - 指针| = 两个指针之间元素的个数
将代码进行改写:
再继续改写:
3.指针的关系运算
指针和指针比较大小
地址和地址比较大小
3.野指针
野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)。
野指针成因:
1.指针未初始化
2.指针越界访问
3. 指针指向的空间释放
4.如何规避野指针
1.指针初始化
明确知道指针应该指向哪里,就给初始化一个明确的地址
如果现在还不知道应该指向哪里,那就初始化NULL
上图中可以看出:
在C语言内存中只有一部分是给用户程序的
2.小心指针越界
⼀个程序向内存申请了哪些空间,通过指针也就只能访问哪些空间,不能超出范围访问,超出了就是 越界访问。
3.指针变量不再使⽤时,及时置NULL,指针使⽤之前检查有效性
当指针变量指向⼀块区域的时候,我们可以通过指针访问该区域,后期不再使⽤这个指针访问空间的 时候,我们可以把该指针置为NULL。因为约定俗成的⼀个规则就是:只要是NULL指针就不去访问, 同时使⽤指针之前可以判断指针是否为NULL。
我们可以把野指针想象成野狗,野狗放任不管是⾮常危险的,所以我们可以找⼀棵树把野狗拴起来, 就相对安全了,给指针变量及时赋值为NULL,其实就类似把野狗栓前来,就是把野指针暂时管理起来。
不过野狗即使拴起来我们也要绕着⾛,不能去挑逗野狗,有点危险;对于指针也是,在使⽤之前,我 们也要判断是否为NULL,看看是不是被拴起来起来的野狗,如果是不能直接使⽤,如果不是我们再去使⽤。
4.避免返回局部变量的地址
如造成野指针的第3个例⼦,不要返回局部变量的地址。
5.assert断⾔
上⾯代码在程序运⾏到这⼀⾏语句时,验证变量p 是否等于 NULL 。如果确实不等于 NULL ,程序继续运⾏,否则就会终⽌运⾏,并且给出报错信息提⽰。
assert() 宏接受⼀个表达式作为参数。如果该表达式为真(返回值⾮零),assert() 不会产⽣任何作⽤,程序继续运⾏。如果该表达式为假(返回值为零),assert() 就会报错,在标准错误流 stderr 中写⼊⼀条错误信息,显⽰没有通过的表达式,以及包含这个表达式的⽂件名和⾏号。
1.assert出现错误的时候会报错,指明在什么文件,哪一行
2. 如下图所示