指针的奥秘

废话不多说直接上干货!

探究指针的奥秘之前,我们需要先了解内存是什么。

内存就是存放CPU上的数据的地方,就是我们所说的多少GB.内存被划分为一个个内存单元,一个内存单元的大小为1个字节(8个bit位)。

在C语言中,我们常说的指针其实就是地址,地址也就是内存单元编号。

指针 <=> 地址 <=> 内存单元编号

&取地址操作符   用%p打印地址(取的是第一个字节的地址)

*解引用操作符(间接访问操作符)

指针变量

指针变量是用来存放地址的,指针变量的大小取决于地址

eg. int a = 20;

      int * pa = &a;

(pa是一个变量,叫做指针变量;*表示pa是指针变量;int * 是pa的类型;int表示pa指向的变量a的类型是int

* pa = a(即通过pa的地址找a)

指针变量的大小与类型无关,只要指针的变量在相同的平台下,大小都是相同的。

X86环境下:指针变量大小为4个字节空间;

X64环境下:指针变量大小为8个字节空间。

解引用

char * 的指针解引用只能访问一个字节

int *的指针解引用只能访问四个字节

+-整数

char * 类型的指针变量+1跳过一个字节

int * 类型的指针变量+1跳过四个字节

eg. int * pa :pa + 1 => +1 * sizeof(int)

                      pa + n => +n * sizeof(int)

      char * pc : pc + 1 => 1 * sizeof(char)

                       pc + n => n * sizeof(char)

void*

无具体类型的指针。(也叫泛型指针,可以接受任意类型地址,但是不能直接进行指针的+-整数和解引用运算

const修饰指针变量

int * p //没有const修饰

int * const p //const在*的右边,即限制p,不限制*p(限制指针变量本身,指针不能改变它的指向(即p里存放的地址不能改变),但可通过指针变量修饰它所指向的内容(即值可变))

int const * p 或 const int * p //const在*的左边,即限制*p,不限制p(不能通过指针变量来修改它所指向的内容,但指针变量本身可以被改变)

int const * const p  <=> p和*p都被限制了

指针-指针

无指针+指针(无意义)

指针-指针 计算的前提条件:两个指针指向的是同一块空间。

指针- 指针相当于地址相减:大地址-小地址为+;小地址-大地址为-

指针-指针的绝对值是指针之间的元素个数

野指针

指针指向的位置不可知(随机/不正确/无明确限制)

野指针会造成内存非法访问,甚至篡改内存中的内容。

野指针成因:1.指针未初始化,系统会默认为随机值。

                      2.指针越界访问。

                      3.指针指向的空间释放。例如,函数中的局部变量出了函数后空间已经不能使用了,但是main函数中的变量又运用了局部变量这块空间,则此时该变量为野指针)

如何避免野指针

1.指针初始化。

如果不知道指针指向哪里时,可以用NULL给指针赋值

NULL是C语言中定义的一个标识符常量,值为0,0也是地址,但是该地址无法使用,读写该地址会报错。

2.小心指针越界。

3.指针变量不再使用时,及时置为NULL,指针使用之前检查有效性。

4.避免返回局部变量的地址。

assert断言

assert()头文件为assert.h

assert(p != NULL)验证变量p是否等于NULL

如果不等于NULL,程序继续运行;否则就会终止运行,并且给出报错信息提示

传值调用和传址调用

传值调用

传址调用

数组名的理解

数组名是数组首元素的地址

但有两个例外:

1. sizeof(数组名)——这里的数组名是整个数组,计算的是整个数组的大小,单位字节

2. &数组名——这里的数组名也表示整个数组,取出的是整个数组的地址

使用指针访问数组

arr[i]  <=>  *(arr + i)  <=>  *(i + arr)  <=> i[arr]

二级指针

用来存放一级指针的地址

int a = 20;

int *pa = &a;

int *ppa = &pa;//先通过*ppa找到pa,然后对pa进行解引用操作——*pa=a

注意!二级指针和二维数组没有对应关系!!!

指针数组

是存放指针的数组。是一个数组,该数组的每个元素都是一个指针

char arr[ ]——存放字符的数组

int arr[ ]——存放整型的数组

char * arr[ ]——存放字符指针的数组

int * arr[ ]——存放整型指针的数组

字符指针变量

char * p = “abcdef” = const char * p

此为是常量字符串,不能被修改

这里的赋值是将字符串中首字符的地址赋给p

使用%s打印字符串时,只需提供首字符的地址即可

数组指针变量

是指向数组的指针。是指针,数组指针变量中存放数组变量的地址

char * ——指向字符的指针

int * ——指向整型的指针

eg.int arr[10] = {1,2,3,4,5};

     int (*p) [10] = &arr;

p是数组指针,p中存放的是数组的地址

数组指针类型为int (*)[10]  (即把数组名去掉就是数组类型)

函数指针变量

函数名和&函数名都是函数的地址

函数指针类型:

解析上面代码:

int (*pf3)(int x,int y)

int :pf3指向函数的返回类型

pf3:函数指针变量名,必须有括号(pf3)

int x:pf3指向函数的参数个数

int y:pf3指向函数的个数

int (*)(int x,int y) //是pf3函数指针变量的类型

typedef关键字

typedef是用来类型重命名的

eg. typedef unsigned int uint

//将unsigned int 重命名为uint

如果重命名指针类型,例如把int * 重命名为 ptr_t

typedef int * ptr_t

如果重命名数组指针类型,例如把int(*)[5]重命名为parr_t

typedef int (*parr_t) [5]   //新的类型命名必须在*的右边

int (*p)[6] = &arr;

parr_t p2 = &arr      //这时的p2和p是一个东西

如果重命名函数指针类型,例如把void(*)(int)重命名为pf_t

typedef void(*pf_t)(int)   //新的类型命名必须在*的右边

函数指针数组

把函数的地址存到一个数组中,这个数组就叫函数指针数组

在函数指针基础上定义函数指针数组

int (*parr1[3])()//parr1先和[ ]结合,说明parr1时数组;是int (*)()类型的函数指针数组

指针的分享就到这里!友友们,下次再见!

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值