C语言指针学习笔记
参考:http://c.biancheng.net/c/pointer/
指针的定义:指针提供了对地址操作的一种方法,因此,使用指针可以使得C语言能够更高效地实现对计算机底层硬件的操作;另外,通过指针可以更便捷地操作数组。在一定意义上,指针是C语言的精髓所在
内存与地址
- 在计算机中,数据是存放在内存单元中的,一般把内存中的一个字节称为一个内存单元;在内存中,为了更方便的访问这些内存单元,可以给每一个内存单元进行地址编号。每一个地址编号对应一个内存单元,或者说一个地址编号就对应一个内存单元。C语言中把地址形象的称作指针*
- 在C语言中,可以使用&符号得到某个变量的地址
- 例如:int a = 10; &a即可得到变量a在内存中的地址
- 在C语言中,char型变量占一个字节的内存空间,而整型占用的空间大小和系统有关
- 每个地址编号对应字节单元的起始地址
- 例如:int a = 100; char c = ‘A’;在内存中的分布情况
[外链图片转存失败(img-eVcaYmfh-1566195872009)(CPointExp.jpg)]
由上图可知,变量 a 对应于从地址 12ff40 开始的 4 个字节(12ff40、12ff41、12ff42、12ff43)的内存空间,存储的是整数 100 的 32 位二进制形式(为直观表示,本例并没有转换成二进制形式)。字符型变量 c,对应地址为 12ff44,该地址内存储的是字母对应 ASCII 值的 8 位二进制形式。- 语句 printf(“a=%d\n”,a); 输出:a=100。
- 语句 printf("&a=%x\n",&a); 是按十六进制形式输出变量 a 的地址(a 在内存中的起始地址值)为 &a=12ff40。
- 在上例中,变量 a 和 c 的起始地址 12ff40 和 12ff44 均为指针,分别指向变量 a 和变量 c。
- 区分变量的地址值和变量的值。如上例中,变量 a 的地址值(指针值)为12ff40,而变量 a 的值为 100。
指针变量的定义
######. 可以保存地址值(指针)的变量称为指针变量,因为指针变量中保存的是地址值,故可以把指针变量形象地比喻成地址箱。
指针变量的定义形式如下。
类型 * 变量名;
例如:nt *pa; 定义了一个整型指针变量 pa,该指针变量只能指向基类型为 int 的整型变量,即只能保存整型变量的地址。
说明:
1. *号标识该变量为指针类型,当定义多个指针变量时,在每个指针变量名前面均需要加一个 *,不能省略,否则为非指针变量。例如:int *pa, *pb;表示定义了两个指针变量 pa、pb。而: int *pa,pb; 则仅有 pa 是指针变量,而 pb 是整型变量。
2. 在使用已定义好的指针变量时,在变量名前面不能加 *。例如:
int *p,a;
p = &a; //错误,指针变量是p而不是p
p = &a; //正确
3. 类型为该指针变量所指向的基类型,可以为 int、char、float 等基本数据类型,也可以为自定义数据类型。该指针变量中只能保存该基类型变量的地址。
4. 变量名是一合法标识符,为与普通变量相区分,一般指针变量名以字母 p(pointer)开头,如 pa、pb 等。
5. 由于是变量,故指针变量的值可以改变,也即可以改变指针变量的指向。
6. 同类型的指针变量可以相互赋值。
指针变量的引用
访问内存空间,一般分为直接访问和间接访问。
- 如果知道内存空间的名字,可通过名字访问该空间,称为直接访问
- 如果知道内存空间的地址,也可以通过该地址间接访问该空间
- 对内存空间的访问操作一般指的是存、取操作,即向内存空间中存入数据和从内存空间中读取数据
- 在 C 语言中,可以使用间接访问符(取内容访问符)*来访问指针所指向的空间
- 例如:
int *p,a=3;//p中保存变量a对应内存单元的地址
p=&a;
printf(“a=%d\n”,a); //通过名字,直接访问变量a空间(读取)
printf(“a=%d\n”,*p); //通过地址,间接访问变量a空间(读取)
*p=6;//等价于a=6;间接访问a对应空间(存)
“野”指针
- 把没有合法指向的指针称为“野”指针。因为“野”指针随机指向一块空间,该空间中存储的可能是其他程序的数据甚至是系统数据,故不能对“野”指针所指向的空间进行存取操作,否则轻者会引起程序崩溃,严重的可能导致整个系统崩溃。
指针与数组
- 在 C 语言中,指针变量加 1 表示跳过该指针变量对应的基类型所占字节数大小的空间。指向数组元素的指针,其基类型为数组元素类型,指针加 1 表示跳过一个数组元素空间,指向下一个数组元素。
- 数组名相当于数组首元素的地址,即:
int *p, a[10];
p = a; //相当于 p=&a[0];a 等价于 &a[0] - 数组的访问方式:
- 直接访问:数组名[下标]; 的形式。如 a[3]。
- 间接访问:*(数组名+i); 的形式。其中,i 为整数,其范围为:0<i<N,N 为数组大小。数组名 a 为首元素的地址,是地址常量,a+i 表示跳过 i 个数据元素的存储空间,即(a+i)表示 a[i] 元素的地址,从而 *(a+i) 表示 a[i]。
- 如果指针变量 p 被初始化为 a 之后,不再改变,那么也可以使用 *(p + i) 的形式访问 a[i],不过这样就失去了使用指针变量访问数组元素的意义。
- 间接访问:*(指针变量);的形式。当执行语句 p=a; 后,可以通过改变 p 自身的值(可通过自增、自减运算),从而使得 p 中保存不同的数组元素的地址,进而通过 *p 访问该数组中不同的元素。这是使用指针访问数组元素较常用的形式。
- 指针值加 1 与地址值加 1 的区别如下。
- 一般地址单元也称内存单元,是按字节划分的,即地址值加 1,表示跳过一个字节的内存空间。
- 在 C 语言中,指针变量加 1 表示跳过该指针变量对应基类型所占字节数大小的空间。
- 在 VC++ 6.0 中,整型占 4 个字节,故对于整型指针变量来说,指针值加 1 对应地址值加 4,即跳过 4 个字节;字符型占 1 个字节,故字符型指针变量加 1,对应地址值也加 1,即跳过 1 个字节。double 型占 8 个字节,故 double 型指针变量加 1,对应地址值加 8,即跳过 8 个字节等。
二维数组与指针
- 二维数组的逻辑结构为行列形式,但二维数组的存储结构为顺序形式。即二维数组中的数据元素在内存中的存储地址是连续的,故可以使用指针变量保存各个元素的地址值,进而可以间接访问二维数组中的各元素。
- M 行 N 列的二维数组 a,可以看成是含有 a[0]、a[1]、…、a[M-1] 等 M 个元素(M 行)的特殊一维数组,其每个元素 a[i](每行)又是一个含有 N 个元素(N 列)的一维数组。
数组指针与指针数组
数组指针
数组指针: 数组指针,即指向一维数组的指针。
数组指针的定义格式为: 类型 (*指针名)[N]; //N元素个数
指针数组
指针数组,即存储指针的数组,数组中的每个元素均是同类型的指针。
指针数组的定义格式为: 类型 *数组名[数组大小];
指针与字符串
- 字符串常量
字符串常量返回的是一个字符指针常量,该字符指针常量中保存的是该字符串首字符的地址,即指向字符串中第一个字符的指针。
- 字符串变量
字符数组可以理解为若干个字符变量的集合,如果一个字符串存放在字符数组中,那么字符串中的每个字符都相当于变量,故该字符串中的每个字符均可以改变,故可把存放在字符数组中的字符串称为变量字符串。
指针与函数
- 指针作函教形参——传址调用
- 指针作函教返回类型——指针函教
- 指向函教的指针——函教指针