147-详细地学习指针

什么是指针?

计算机中所有的数据都必须放在内存中,不同类型的数据占用的字节数不一样,例如int占用4个字节,char占用1个字节。为了正确地访问这些数据,必须为每个字节都编上号码,就像门票号一样,每个字节的编号是唯一的,根据编号可以准确地找到某个字节。我们将内存中字节的编号称为地址或指针。地址从0开始依次增加,对于32位环境,程序能够使用的内存为4GB
最小的地址为0x0000 0000
最大的地址为0XFFFF FFFF
在这里插入图片描述
C/C++中, * 号运算符的意义,* 号运算符所在的环境不一样,*号的含义也不一样
在这里插入图片描述
定义指针变量
定义指针变量与定义普通变量非常类似,不过要在变量名前面加 * 号
格式为:
datatype *name;
或者
datatype * name=&value;
*表示这是一个指针变量,datatype表示该指针变量所指向的数据的类型
在指针定义中, * 号是和变量名结合
在这里插入图片描述
所谓指针,也就是内存的地址,所谓指针变量,就是保存了内存地址的变量
指针的大小在32位平台是4个字节,在64位平台是8个字节
图解指针
在这里插入图片描述
使用指针变量首先要明确指针变量自身的值(存储的是地址),再明确指针变量所指的实体(解引用)
在这里插入图片描述
在这里插入图片描述
定义指针变量时,类型对指针变量起到两个作用
1、解析存储单元的大小
2、指针变量加1的能力
在这里插入图片描述

指针传递,指针和函数

在这里插入图片描述
在这里插入图片描述

指针的运算

类型对指针+1的影响
int指针变量+1
在这里插入图片描述
char类型指针变量+1
在这里插入图片描述
double类型指针变量+1
在这里插入图片描述
指针+1详解
在这里插入图片描述
指针的类型不同,加1的能力也不一样
如:
typename *p;
p=p+1;被编译器解释成:p=p+sizeof(typename)*1
指针和整型加减后的结果仍然是指针类型

类型对指针解引用的影响

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
关于*和&
int a=10; int *pa=&a;
假设有一个int类型的变量a,pa是指向它的指针
*&a可以理解为 *(&a),&a表示取变量a的地址(等价于pa), * (&a)表示是取这个地址上的数据(等价于 *pa), *&a仍然等价于a
&*pa可以理解为&(*pa),*pa 表示取得pa指向的数据(等价于a),&(*pa)表示数据的地址(等价于&a),使用,&*pa仍然等价于pa
*&pa可以理解为 *(&pa),&pa是对指针pa本身取地址, (&pa)就是对pa本身的地址取数据,&pa等价于pa
在这里插入图片描述

指针与数组的关系

在这里插入图片描述
数组名被看作该数组的第一个元素在内存中的首地址(仅在sizeof操作中例外,该操作给出数组所占内存的大小)
数组名在表达式中被自动转换为一个指向数组第一个元素的指针常量
数组名是指针,非常方便,但是却丢失了另一个要素:数组的大小,即数组元素的数量。编译器按数组定义时的大小分配内存,但运行时(run time)对数组的边界不加检测。这会带来无法预知的严重错误
在这里插入图片描述
C提供根据数组的存储地址访问数组元素的方法
上图中ar是数组第一个元素的地址,使用* ar是数组的第一个元素ar[0],而ar+1是数组第二个元素的地址,*(ar+1)是第二个元素ar[1]本身。指针加1,则地址移动一个数组元素所占字节数
C语言的下标运算符[]是以指针为操作数的,ar[i[被编译系统解释为 *(ar+i),即表示ar所指(固定不可变)元素向后第i个元素。无论以下标方式或指针方式存取数组元素时,系统都是转换为指针方法实现的。逻辑上有两种方式,物理上只有一种方式

数组名访问
在这里插入图片描述
指针访问
在这里插入图片描述
指针变量与整型量的加减表示移动指针,以指向当前目标前面或者后面的若干个位置的地址。指针与整型量i的加减等于指针值(地址)与i * sizeof(目标类型)积的加减,得出新的地址
运算结果并不表明那儿有一个指针所规定的数据类型的变量,即使是对数组操作,这称作不对数组边界做检查
指针的算术运算很容易超出数组的边界,需要小心越界问题

指针- 指针运算

在这里插入图片描述
两个同类型的指针,指向连续空间可以相减。减后的结果是数据元素的大小
如:
int类型的指针 - int类型指针结果是整型元素的个数
char类型的指针-char类型指针的结果是char数据元素的个数

当且仅当两个同类型指针变量指向同一数组中的元素时,可以用关系运算符 >,==,!=等进行比较,比较规则是指向后面元素的指针高,指向同一元素的相等
在这里插入图片描述
在这里插入图片描述

指针变量与const

const与指针配合使用有两种作用,一是限制指针变量,二是限制指针变量指向的数据
限制指针变量本身,如:int*const p;
意思是:指针变量本身的值不能被修改,但指向可以改变。所以被const修饰的指针变量指针只能在定义时初始化,不能定义之后再赋值
在这里插入图片描述
限制指针变量指向的数据
如:const int *ip; int const *ip;
上面两种写法都可以,一般使用第二种,限制指针变量指向的数据的意思是指针可以指向不同的变量(指指针本身的值可以修改),但是不能用指针修改指针指向的数据的值
在这里插入图片描述
当然也可以同时限制指针变量和指针变量指向的数据的值
写法如下
const int *const ip;
上面这种写法使指针变量和指针变量指向数据的值都不能修改
在这里插入图片描述

普通变量与常变量的区别

在这里插入图片描述
区分const是限制的指针变量还是指针变量指向数据的值:沿着* 号划一条线,如果const位于* 的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;如果const位于*的右侧,cosnt就是修饰指针本身,即指针本身是常量

const和函数形参
在很多情况下cosnt通常用在函数形参中,这也是const最有用之处,用来限定函数的新参,这样该函数将不会修改实参指针所指的数据
在C标准库中有很多函数形参都用const限制了,为了防止在函数内部修改指针指向的数据
例如
在这里插入图片描述

无类型指针 void *

void的作用
1、对于函数返回的限定
2、对函数参数的限定

当函数不需要返回值时,必须使用void限定,这就是第一种情况。例如:void fun(int a)
当函数不允许接受参数时,必须使用void限定,这就是第二种情况。例如int fun(void)
void不能定义变量,但可以定义指针变量,特别之处在于void指针可以指向任意类型变量的地址
在这里插入图片描述
所以我们也把void指针变量称为泛型指针,是指针都可以给void指针变量赋值,甚至vp=&vp;也可以
如果要将void指针vp赋给其他类型的指针,则需要强制类型转换,
int *ip=(int *)vp; double *dp=(double *)vp;
在ANSIC标准中,不允许对void指针进行一些算术运算符如vp++或vp+=1等,因为既然void是无类型,那么每次算术运算我们就不知道该操作几个字节,例如char型操作sizeof(char)字节,而int要操作sizeof(int)字节。而在GNU中则允许,因为在默认情况下,GNU认为void *和char *一样,既然是确定的,当然可以进行一些算术操作,在这里sizeof(*p)==sizeof(char)
好处是:void指针可以任意类型变量的地址。函数中的形参为void *指针变量时,函数就可以接受任意类型变量的地址
例如C语言string.h函数库中:
在这里插入图片描述

数组,指针和函数综合

在这里插入图片描述
用数组作为函数的形参,数组将退化为指针类型
如果想要在函数中传递一个一维数组作为参数,必须以下面三种方式类声明函数形式参数,这三种声明方式的结果是一样的,因为每种方式都会转成指针
在这里插入图片描述
在这里插入图片描述

二级指针

指针可以指向普通类型的数据,例如int double char等,也可以指向指针类型的数据,例如 int* double* char* 等。如果一个指针指向的是另外一个指针,我们就称它为二级指针,或者指向指针的指针
在这里插入图片描述

C语言指针总结

指针就是内存的地址,C语言运行用一个变量来存放指针,这种变量称为指针变量。指针变量可以存放基本类型数据的地址,也可以存放数组、函数以及其他指针变量的地址
程序在运行过程中需要的是数据和指令的地址、变量名、函数名、字符串名和数组名在本质上是一样的,它们都是地址的助记符:在编写代码的过程中,我们认为变量名表示的是数据本身,而函数名、字符串名和数组名表示的是代码块或数据块的首地址;程序被编译和链接后,这些名字都会消失,取而代之的是它们对应的地址
常见指针变量的定义
在这里插入图片描述
1、指针变量可以进行加减运算,例如:p++,p+i,p-=i
指针变量的加减运算并不是简单的加上或减去一个整数,而是跟指针指向的数据类型有关
2、给指针变量赋值时,要将一份数据的地址赋给它,不能直接赋给一个整数,例如:int *ip=(int *)ox1234;是没有意义的,使用过程中一般会导致程序的崩溃。注意0x1234是十六进制整型常量,必须强制转换成指针类型
3、使用指针变量之前一定要初始化,否则就不能确定指针指向哪里(野指针),如果它指向的内存没有使用权限,程序就崩溃了。对于暂时没有指向的指针,建议赋值NULL
4、两个指针变量可以相减。如果两个指针变量指向同一个数组中的某个元素,那么相减的结果就是两个指针之间相差的元素个数
5、数组也是有类型的,数组名的本意是表示一组类型相同的数据。在定义数组时,或者和sizeof、&运算符一起使用时数组名才表示整个数组,否则表达式中的数组名会被转换为一个指向数组首元素的指针
6、指针类型不同,不能互相赋值
如:
int *ip=NULL;
char *cp=NULL;
ip=cp;或cp=ip;都是错误的赋值
必须强制类型转换:ip=(int )cp;或cp=(char)cp;才可以赋值

猜你喜欢

转载自blog.csdn.net/LINZEYU666/article/details/112994889