一.指针与地址与指针变量
(1)首先给出一个很直白的结论:指针就是地址,指针=地址,地址=指针。这两没什么大的区别,就是同一个东西。
(2)指针变量就是设定一个变量来存放地址(指针),存放在指针变量中的值都会理解成指针。
指针变量的类型:
在C语⾔中创建变量其实就是向内存申请空间,int a=10就是创建了整型变量a,内存中申请4个字节,⽤于存放整数10,其中每个字节都有地址
而int*pa=&a,就是创建指针变量pa,用于存放a的地址
int a类型是int 整型,char a类型是char字符型。那么指针变量int *pa类型是什么呢,它的类型是int*,*号是在说明a是一个指针变量,而前面的int是在说明pa指向的是整型类型的对象。
请注意指针变量它是也有自己的地址的,例如int*pa=&a;&pa!=&a,虽然说指针变量是申请一片内存空间用来存放a的地址的,但是不代表变量pa自身的地址就变为了a的地址
请看如下地址示例
#include<stdio.h>
int main()
{
int a = 12;
int* pa = &a;
printf("a的地址是%p\npa的地址是%p", a, pa);
}
(3)解引用操作符
将地址保存起来是要使用的,那怎么使用的呢,我们只要拿到了地址(指针)就可以通过指针找到地址(指针)指向的对象,相当于我们使用地址要找到一个房间,在房间里可以拿走或者存放物品。
通过解引用操作符就可以实现改变房间里的东西了。
比如说int a=0;int *pa=&a;*pa=10;指针变量pa保存了a的地址,而解引用就相当于通过地址去改变a的值,所以a最后值为10。
(4)指针变量的大小
int a=0,变量a是int型,所以a大小为4(因为一个int型变量为4);char b=0,变量b是char型,所以b的大小为1;
而int *pa它的类型是int *类型,它的大小是多少呢?
32位机器假设有32根地址总线,每根地址线出来的电信号转换成数字信号后
是1或者0,那我们把32根地址线产⽣的2进制序列当做⼀个地址,那么⼀个地址就是32个bit位,需要4个字节才能存储。
如果指针变量是⽤来存放地址的,那么指针变量的⼤⼩就得是4个字节的空间才可以。
同理64位机器,假设有64根地址线,⼀个地址就是64个⼆进制位组成的⼆进制序列,存储起来就需要8个字节的空间,指针变量的⼤⼩就是8个字节
(5)const修饰指针变量
const名叫常量限定符,加了const就表示不能修改了
加了const修饰的指针变量有两种型态int const *p和int* const p
const如果放在*的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变。
但是指针变量本⾝的内容可变,const int*p本质上和int const *p是等价的,const都在*号左边
const如果放在*的右边,修饰的是指针变量本⾝,保证了指针变量的内容不能修改,但是指针指
向的内容,可以通过指针改变。
(6)指针的运算
1.指针加或者减整数,指针+-整数大多数用于数组中
#include <stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int* p = &arr[0];//指向数组首元素地址
int i = 0;
int ret = sizeof(arr) / sizeof(arr[0]);//sizeof里如果是单独的数组名表示的是整个数组,且&arr表示取整个数组的地址。其余情况单独arr都表示首元素
for (i = 0; i < ret; i++)
{
printf("%d ", *(p + i));//指针加整数
}
printf("\n");
for (i = 0; i < ret; i++)
{
printf("%d ",arr[i]);//普通数组打印表示
}
}
上面示例中指针加整数解引用和普通数组打印方法的结果是相同的,p一开始指向的是首元素地址,循环加i,它的地址也会随之往后偏移,此时i其实就是数组的下标。*(p+i)等价于arr[i]。
数组名除了sizeof里面单独出现或者单独&数组名表示整个数组,其余情况都表示首元素地址
#include <stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int* p = &arr[0];//指向数组首元素地址
int i = 0;
int ret = sizeof(arr) / sizeof(arr[0]);//sizeof里如果是单独的数组名表示的是整个数组,且&arr表示取整个数组的地址。其余情况单独arr都表示首元素
for (i = 0; i < ret; i++)
{
printf("%d ", *(arr + i));
}
printf("\n");
for (i = 0; i < ret; i++)
{
printf("%d ", p[i]);
交换数组名和指针变量打印结果都一样,因为此时它们都指向首元素地址,本质上是一样的
2.指针减指针
指针减指针得到的是指针之间的元素个数的绝对值,但是运算前提是两个指针都指向同一块空间
3.野指针
野指针是因为指针变量中保存的值不是一个合法的内存空间或者指向不可用内存的指针造成的
但是野指针不是NULL指针,NULL指针可以通过if语句来判断,但是c语言中没有任何一个办法来判断这个指针是否是野指针
野指针成因:1.指针未初始化,局部变量指针未初始化,默认为随机值。
2.指针越界访问,数组中指针指向的范围超出数组的范围时,p就是野指针
3.指针指向的空间释放了
所以指针变量不再使用时,要及时置NULL,指针使用之前检查有效性