一,内存和地址
计算器处理数据需要cpu(中央处理器),当处理数据时需要从内存中读取,处理后也会放回内存中。
计算机常见的单位:
指针类型和指针变量:
二,指针变量大小
由此代码我们可以算出指针变量的大小,
结论:
1.32位平台下地址是32个bite位,指针变量的大小为4个字节。
2,64位平台下地址是64个bite位,指针的变量的大小为8个字节。
3,注意指针的大小是与类型无关的,只要指针的类型变量在同一平台,大小都一样。
三,指针类型的意义
指针类型+1,-1,决定了指针一次能走多远。
int* + 1 ——> 走4个字节(整形的大小)
char* + 1 ——> 走1个字节(字符的大小)
总结:当它访问地址时是访问几个字节。
四,void* 指针
在指针类型中有一种特殊的类型是void*类型,可以理解为一种无具体类型的指针(泛型指针),这种指针可以接受任意类型的指针,但是也有局限性,void* 类型的指针不能直接进行指针的+,-整数和解引用的运算。
用法:可以在函数调用复杂指针时,用空指针或者你具体不知道指针的类型也可以用空指针。
五,const 修饰指针
变量是可以修改的,如果把变量的地址交给一个指针变量,通过指针变量的也可以修改这个变量。但是如果我们不希望这个变量被修改,我们家需要用 const。
如果强行修改会直接报错误
但是可以通过指针取出地址来修改
eg:
结果为
其中const可以放在 * 前面或者后面
当const放在 * 的右边
看图,当被const修饰的 “p”,通过指针也不能修改,因为const是接修饰“p”,所以,p里面只能是&a。
但是可以改变指针变量指向的内容
意义:const 限制的是指针变量本身,指针变量不能再指向其他变量,但是可以通过指针变量,修改指针变量的内容(不能改变地址,可以改变地址上的内容)
当const放在‘*’的左边
意义:const 修饰指针变量时,放在 * 的左边,限制的是:指针指向的内容,不能通过指针修改指针内容。但是可以修改指针变量本身的值(修改指针变量的指向)
总结:在 “*”的右侧,指针变量不能改变,反之解引用后不能改变。(本人总结,可忽略)
六,指针的运算
指针的基本运算有三种:
(1),指针 + - 整数
(2),指针 - 指针
(3),指针关系的运算
(1),指针 +- 整数
因为数组是连续存放,只要知道第一个元素的地址,就可以顺藤摸瓜找到后面的所有元素。
另一种
(2),指针 - 指针
前提条件:两个指针必须指向同一个空间
(3)指针的的关系运算(指针和指针比较大小)
七,野指针
指针指向位置不可知(随机的,不确定的,没有明确的限制)
未初始化指针;越界访问;
指向空间释放
如何规避野指针
(1)初始化指针
如果明确知道指针指向哪里直接赋值地址,如果不知道指向那,就可以给指针赋值NULL(它是C语言中定义的一个标识符常量,值是0,0也是一个地址,这地址无法使用,读取时会报错)
(2)小心指针越界
一个程序向内存申请了那些空间,通过指针也只能访问那些空间,不能超出范围访问,超出就是越界访问。
(3)assert断言
assert.h头文件定义的宏assert(可以是指针或者表达式),用于确保程序符合指定条件,如果不符合就会报错·终止运行。(如果需要取消assert,可以在头文件前面包含#define NDEBUG)
八,传值调用和传址调用
eg:写一个函数交换两个数
看程序并没有完成简单的交换;应为当实参传递给形参时候,形参只是实参的一份临时拷贝,改变形参不会影响实参,所以没有交换。
我们可以用指针来解决问题
因此,在未来函数中只是需要主调函数的变量值来实现计算,就可以采用传值调用。如果需要改变函数内部的值,就需要传址调用。