泪干肠断网

23.1 指针的基本概念

23.1 指针的基本概念

23.1 指针的指针基本概念

第一种指针:堆栈有栈顶指针,队列有头指针和尾指针,本概这些概念中的指针“指针”本质是一个整数,是本概数组的索引,通过指针访问数组中的指针某个元素。
第二种指针:把一个变量所在的本概内存单元的地址保存在另外一个内存单元中,保存地址的指针这个内存单元称为指针,访问变量要通过指针间接寻址,本概这种指针在C语言中可以用一个指针类型的指针变量表示。

int i;int *pi = &i;char c;char *pc =&c;

(1)&是本概取地址运算符,&i表示取变量i的指针地址;int *pi = &i;表示定义一个指向int型的指针变量pi,并用i的本概地址来初始化pi。
(2)定义字符型变量c和一个指向c的指针字符型指针pc。

如果要让pi指向另一个整型变量j,本概可以重新读pi赋值:

pi =&j;

现在要通过指针pi间接寻址到变量j,指针把变量j的值增加10,可以写成:

*pi = *pi +10;

[ ]在声明和表达式中有不同的含义,[ ]用在声明中表示一个数组;用在表达式中提取下标运算符。同理,*用在声明中表示一个指针类型,用在表达式中是间接寻址运算符。

*和&互为逆运算。如果表达式E可以做左值,则*&E和E等价;如果表达式E是指针类型,则&*E和E等价。

指针之间相互赋值,用一个指针初始化另一个指针:

int *ptri = pi;

或者

int *ptri;prti = pi;

上述代码表示pi指向哪就让prti也指向哪,本质上就是把变量pi所保存的地址赋值给变量prti。

强制类型转换。两个指针必须同一类型,才能用一个指针给另一个指针赋值。不同类型,先强制转换再赋值,如pi是int *型,pc是char *型,不可以pi = pc,应该如下操作

pi = (int *)pc;

在这里插入图片描述

**定义一个指针类型的局部变量需要初始化。**错误情况如下:

int main(void){ 	int *p;	...	*p =0;	...}

解析:栈上分配的变量初始值是不确定的,也就是说指针p所指向的内存地址是不确定的,后面用*p访问不确定的地址会导致不确定的后果,可能引发段错误,也可能以外改写了数据而导致程序在随后的运行中出错。像这种指向不确定地址的指针称为野指针,为避免野指针,在定义指针变量时就应该明确地给它赋值,或把它初始化为NULL:

int main(void){ 	int *p = NULL;	...	*p =0;	...}

NULL在C标准库的头文件stddef.h中定义:

#define NULL ((void *) 0)

指针也是一种标量类型,可以用()运算符做强制类型转换,其他标量类型也可以转换成指针类型,指针类型也可以转换成其他标量类型,比如在上面的定义中把整形的0强制转成void *指针,这个指针指向0地址,称为空指针

空指针的特殊之处在于,操作系统不会把任何数据保存在地址0及其附近,也不会把地址0~0xfff的页面映射到物理内存,所以任何对地址0的访问都会立刻导致段错误。*p = 0;会导致段错误,就像放在眼前的炸弹一样很容易找到,相比之下,野指针的错误就像埋下地雷一样,更难发现和排除,这次走过去没事,下次走过去就有事。

**void *类型。**在编程时经常需要一种通用指针,可以转换为任意其它类型的指针,任意其它类型的指针也可以转换为通用指针。ANSI在将C语言标准化时引入了void *类型,void *指针与其它类型的指针之间可以隐式转换,而不必用类型转换运算符。

void func(void *pv){ 	/* *pv = 'A' is illegal */	char *pchar = pv;	*pchar = 'A';}int main(void){ 	char c;	func(&c);	printf("%c\n", c);...}

未经允许不得转载:泪干肠断网 » 23.1 指针的基本概念