第8章指针 8,1指针概念 8,2变量的指针和指向变量的指针变量 83指针变量的定义 84指针变量的引用 8.5指针与数组 86字符串的指针和指向字符串的指针变量 8.7指针与函数 88指向结构体类型数据的指针 89动态数据结构
第 8 章 指 针 8.1 指针概念 8.2 变量的指针和指向变量的指针变量 8.3 指针变量的定义 8.5 指针与数组 8.4 指针变量的引用 8.6 字符串的指针和指向字符串的指针变量 8.7 指针与函数 8.8 指向结构体类型数据的指针 8.9 动态数据结构
第8章指针 81指针概念 指针是c的一个重要概念。其特点是: 能有效地表示复杂的数据结构;能动态地分配内存,直 接处理内存地址;能方便、有效地使用字符串和数组; 能在调用函数后获得多个值。 C中定义的变量,在编译时按变量的类型来分配 定长度的内存单元。在运行时,根据变量名与地址的对 应关系,相应地存取变量的数据。这种按变量地址存取 变量值的方法称为“直接访问”方式。 如果变量的地址也存放在某一个内存单元,则存取 方式为先找到存放变量的地址单元,再取变量的值,这 种方式称为“间接访问”方式如: p=&i;将变量的地址存放到变量p"指向”的内存单元
第 8 章 指 针 8.1 指针概念 指针是C的一个重要概念。其特点是: 能有效地表示复杂的数据结构;能动态地分配内存,直 接处理内存地址;能方便、有效地使用字符串和数组; 能在调用函数后获得多个值。 C中定义的变量,在编译时按变量的类型来分配一 定长度的内存单元。在运行时,根据变量名与地址的对 应关系,相应地存取变量的数据。这种按变量地址存取 变量值的方法称为“直接访问”方式。 如果变量的地址也存放在某一个内存单元,则存取 方式为先找到存放变量的地址单元,再取变量的值,这 种方式称为“间接访问”方式。如: p=&i; 将变量i的地址存放到变量p “指向”的内存单元中
8.2变量的指针和指向变量的指针变量 变量的指针就是变量的地址,即p用户数据区 的值。也就是说,指针变量的值就是该 指针变量所指变量的内存首地址。 20003变量i 在p的前面加上一个“”,即p20215 表示指针变量p所指向的变量。 从右图可知: 如p也是一个变量,且与变量是同30102000变量p 回事。 i=3; p=&i; p=3;将3赋给指针变量p所指向的变量,与i=3等价
8.2 变量的指针和指向变量的指针变量 变量的指针就是变量的地址,即p 的值。也就是说, 指针变量的值就是该 指针变量所指变量的内存首地址。 在p的前面加上一个“ * ”,即*p就 表示指针变量p所指向的变量。 从右图可知 : *p也是一个变量,且与变量i是同 一回事。 i = 3; p=&i; *p=3; 将3赋给指针变量p所指向的变量,与i=3等价 用户数据区 2000 3 变量 i 2002 6 变量 j 2004 9 变量 k 3010 2000 变量 p
83指针变量的定义 定义形式: 类型标识符*标识符; p1 *p1 指针变量必须定义为“指针类型”如: int i, j; p2*p2 int*p1, *p2; 口口j p1=&i;p2=&j; p1,p2为指向整型变量i,j的指针变量。 说明:①类型可以是整型、实型、字符型等。 ②标识符前的“*”表示该变量为指针变量。 ③指针变量只能指向同一类型的变量。 ④上述的指针变量是p1、p2,而不是*1、*p2。 *p1和*p2是p1和p2所指向的变量i和j ⑤指针变量中只能存放地址。p1=100;是非法的
8.3 指针变量的定义 定义形式: 类型标识符 *标识符; 指针变量必须定义为“指针类型”。如: int i, j; i j int *p1, *p2; p1 p2 p1=&i; p2=&j; p1, p2 为指向整型变量 i, j 的指针变量。 说明: 类型可以是整型、实型、字符型等。 标识符前的 “*” 表示该变量为指针变量。 指针变量只能指向同一类型的变量。 上述的指针变量是p1、p2,而不是 *p1、 *p2。 *p1 和 *p2 是 p1 和 p2 所指向的变量i和 j。 *p1 *p2 指针变量中只能存放地址。p1=100; 是非法的
84指针变量的引用 与指针有关的运算符 &取地址运算符如:&a为变量a的地址 *指针运算符如:*p为指针变量p所指向的变量 ①*运算和&运算互为逆运算。 ②指针变量p的内容为地址量;*p为指针p的目标量,内 容为数据,即指针变量p所指向的变量的值。 ③*p=i;是将变量i的值赋给目标变量*p。 ④&p为指针变量p的地址。 ⑤&(p)的结果为p,即变量*p也就是变量x的地址 ⑥*(&)表示访问变量i的 p 地址,结果就是i本身。 入 &p区x 至此,你应该明白了 p、p和&p的意义
8.4 指针变量的引用 与指针有关的运算符: & 取地址运算符 如:&a 为变量 a 的地址 指针运算符 如:*p为指针变量p所指向的变量 运算和 & 运算互为逆运算。 指针变量p的内容为地址量; p *p x *p=i; 是将变量 i 的值赋给目标变量*p。 i &p为指针变量 p 的地址。 &p &(*p)的结果为p,即变量*p也就是变量x的地址。 *(&i) 表示访问变量 i 的 地址,结果就是 i 本身。 至此,你应该明白了 p、 *p和&p的意义。 &x *p为指针p的目标量,内 容为数据,即指针变量 p所指向的变量的值
例8.1 main( fint a, b; int *p1, *p2, a=100;b=10; p1=&a;p2=&b;将变量a和b的地址赋给指针变量p1和p2 printf("%d, %dn",a, b); printf(9%d,%dn”4p1,*p2);1和*2就是变量a和b 运行结果: 100.10 100,10
例8.1 main( ) {int a,b; int *p1, *p2; a=100; b=10; p1=&a; p2=&b; printf(“%d,%d\n”,a, b); printf(“%d,%d\n”, *p1, *p2); } 将变量a和b的地址赋给指针变量p1和p2 *p1和*p2就是变量a和b 运行结果: 100, 10 100, 10
说明 ①若先执行p=&a;再执行8p;是什么意思?这里 “&”和“*”的优先级相同,但按“自右至左”结合, &*p1与&a相同 而p2=&*p1;的作用是将&a赋给p2。 ②若先执行p1&a;则*&a和*p1的作用相同。即 *&a与a是等价的 ③(p1)++等价于a++。 &*p1 p 注意:括号是必须的,否则就成为 口□a *(p1++)。这时先按p1的原值进行 *&a 2 *运算得到a的值。然后使p1的值 改变,则p1不再指向a了
说明: 若先执行p1=&a; 再执行&*p1; 是什么意思? 这里 “&”和“*”的优先级相同,但按“自右至左”结合, 即 &*p1与&a相同。 p1 a &*p1 而p2=&*p1; 的作用是将&a赋给p2。 p2 若先执行p1=&a; 则 *&a和*p1的作用相同。即: *&a与a是等价的 (*p1)++ 等价于a++。 *p1 *&a 括号是必须的,否则就成为 *(p1++)。这时先按p1 的原值进行 * 运算得到 a 的值。然后使p1的值 改变,则p1不再指向 a 了。 注意:
例82 main( [int *p1, *p2, * p, a, b; scanf("/dd, &a, &b) p1=&a;p2=&b; if (asb)ip=pl; p1=p2; p2=p; 1 printf((a=%d,b=%dⅦn”,a,b) printf("max=%d, min=%dn", *p1, *p2); 运行情况: p1 a 59 &a 5 p a=5,b=9 max, min=5 p2 b 注意:此例中a和b并未交 &b 9 换,而p1和p2的值改变
例8.2 main( ) {int *p1, *p2, *p, a, b; scanf(“%d%d”,&a,&b); p1=&a; p2=&b; if (a<b) { p=p1; p1=p2; p2=p; } printf(“a=%d,b=%d\n”, a, b); printf(“max=%d,min=%d\n”,*p1,*p2); } a b p1 p2 &a &b 5 9 p 运行情况: 5 9 注意:此例中a和b并未交 换,而p1和p2的值改变。 a=5, b=9 max=9, min=5
8.5指针与数组 1.指向数组元素的指针变量的定义与赋值 例:inta[10],p p=&ao;将a[]元素的地址赋给指针变量p 在c中,数组名代表数组的首地址。因此p=a;与p=&a[0];是等价的。 注:p=a;是将a数组的首地址赋给指针变量p。但这里的a并不 代表整个数组 2.通过指针引用数组元素 ①若p=a;是将整型数组a的首地址赋给整型指针变量p,则*p=5; 是将整数5赋给a数组的第一个元素a[o],等价于a[0]=5。 ②p+1表示指针变量p当前所指的数组元素的下一个元素。但p+1 不是p的值加1。若有p=&a[];则p+i(或a+)就是a[订的地址 (因为a代表数组a的首地址)。 ③若有p=&ao];则p+)或a+就是p+或a+所指向的数组元素, 即a[i]。也就是说*p+i)=*(a+)=a[]。 ④指向数组的指针变量可以带下标,如:p与*p+是等价的
8.5 指针与数组 1. 指向数组元素的指针变量的定义与赋值 例: int a[10],*p; p=&a[0]; 将a[0]元素的地址赋给指针变量p 在C中,数组名代表数组的首地址。因此p=a;与p=&a[0];是等价的。 注:p=a; 是将a数组的首地址赋给指针变量p。但这里的a并不 代表整个数组。 2. 通过指针引用数组元素 若p=a; 是将整型数组a的首地址赋给整型指针变量p,则*p=5; 是将整数5赋给a数组的第一个元素a[0],等价于a[0]=5 。 p+1表示指针变量p当前所指的数组元素的下一个元素。但p+1 不是p的值加1。若有 p=&a[0]; 则p+i(或a+i) 就是a[i]的地址 (因为a代表数组a的首地址)。 若有p=&a[0]; 则*(p+i)或*(a+i)就是p+i或a+i所指向的数组元素, 即a[i]。也就是说 *(p+i) = *(a+i) = a[i]。 指向数组的指针变量可以带下标,如:p[i] 与*( p+i)是等价的
例8.3输出有10个元素的整型数组a的元素值。 main( I int a[101, *p, i for(=0; i<10; i++) scanf(%d', &aD); printf( n): for (p=a; p<(a+10);p++) printf(%d,*p) 也可写成如下: maino int a[101, *p=a, i; for(i=0; i<10; i++)scanf(%d,p++) printf("n) p=a, 此语句必不同少 for(i=0; i<10; i++, p++) printf("%d",p);
例8.3 输出有10个元素的整型数组 a 的元素值。 main( ) { int a[10], *p, i; for (i=0; i<10; i++) scanf(“%d”,&a[i]); printf(“\n”); for (p=a; p<(a+10); p++) printf(“%d”,*p); } 也可写成如下: main( ) { int a[10], *p=a, i; for (i=0; i<10; i++) scanf(“%d”,p++); printf(“\n”); p=a; for (i=0; i<10; i++, p++) printf(“%d”,*p); } 此语句必不可少