指针是什么?
任何程序数据载入内存后,在内存都有它们的地址,这就是指针。而为了保存一个数据在内存中的地址,我们就需要指针变量。
因此:指针是程序数据在内存中的地址,而指针变量是用来保存这些地址的变量。
一 指针数组(存放指针的数组)与数组指针(指向数组的指针)
指针数组:首先它是一个数组,数组的元素都是指针,数组占多少个字节由数组本身决定。它是“储存指针的数组”的简称。
数组指针:首先它是一个指针,它指向一个数组。在32 位系统下永远是占4 个字节,至于它指向的数组占多少字节,不知道。它是“指向数组的指针”的简称。
int *arr_a [10]; //数组指针
int (*)arr_b[10]; //指针数组
ptr1先与“[]”结合,构成一个数组的定义,数组名为ptr1,int *修饰的是数组的内容,即数组的每个元素。那现在我们清楚,这是一个数组,其包含10个指向int 类型数据的指针,即指针数组。
至于ptr2就更好理解了,在这里“()”的优先级比“[]”高,“*”号和ptr2 构成一个指针的定义,指针变量名为ptr2,int 修饰的是数组的内容,即数组的每个元素。数组在这里并没有名字,是个匿名数组。那现在我们清楚ptr2 是一个指针,它指向一个包含10个int 类型数据的数组,即数组指针。
二 指针变量
指针变量是用来存储地址的,而一般变量是存储数值的。指针变量可指向任意一种数据类型,但不管它指向的数据占用多少字节,一个指针变量占用四个字节。
定义格式: 类型名 * 指针变量名。二维指针变量 int **p,可以理解为基类型是(int *)类型。
三 指针变量的的引用
&是取地址符,*是间接访问运算符,它们是互逆的两个运算符。在指针变量名前加间接访问运算符就等价于它指向的量。
四 指针的运算
int *p中*p和p的差别:
*p可以当做变量来用, * 的作用是取后面地址p里面的数值; p是当做地址来用。
*p++和(*p)++之间的区别:
*p++是地址会变;(*p)++是数值会变化。
三名定义:
数组名: 表示第一个元素的地址。数组名不可以自加,它是地址常量名。
函数名:表示函数的入口地址。
字符串常量名:表示第一个字符的地址。
五 空指针和void*类型指针
空指针:指向空,或者说不指向任何东西。在C语言中,我们让指针变量赋值为NULL表示一个空指针,而C语言中,NULL的本质是((void*) 0),在C++中NULL的实质是0。换种说法:任何程序不会存储在地址为0的内存块中,它是被操作系统预留的内存块。
void*类型指针:由于void是空类型,因此void*类型的指针只保存了指针的值,而丢失了类型信息,我们并不知道它指向的数据类型是什么,只指定这个数据在内存中的起始地址,如果想要完整的提取指向的数据,就必须先为它做出正确的类型转换,然后在解引用。因为,编译器不允许直接对void *类型的指针进行解指针操作。
六 指针的赋值
浅拷贝:指针之间的赋值是一种浅拷贝,是在多个编程单元之间的共享内存数据的高效的方法。
深拷贝: 数据真正的被拷贝了,在每个内存中都有自己的一份,对目标数据的操作不受影响。
七 const和指针
如果const后面是一个类型,则跳过最近的原子类型,修饰后面的数据。(原子类型是不可再分割的类型,如int, short, char, 以及typedef包装后的类型)
如果const后面就是一个数据,则直接修饰这个数据。
简单总结:近水楼台先得月,忽略类型名,距离哪个变量近就修饰哪个。
const int *p; //const修饰*p,p是指针p可变,p指向的对象*p不可变
int const *p; //const修饰*p,p是指针p可变,p指向的对象*p不可变
int *const p; //const修饰p,p是指针p不可变,p指向的对象*p可变
const int * const p; //前一个const修饰*p,后一个const修饰p,指针p和p指向的对象都不可变