第 5章指 针回顾
数组是可以在内存中连续存储多个元素的结构数组中的所有元素必须属于相同的数据类型
数组必须先声明,然后才能使用。声明一个数组只是为该数组留出内存空间,并不会为其赋任何值
数组的元素通过数组下标访问
一维数组可用一个循环动态初始化,而二维数组可用嵌套循环动态初始化
二维数组可以看作是由一维数组的嵌套而构成的目标
理解指针的概念
定义指针变量
掌握对指针的操作
理解指针和数组的关系
int x,y,z;
x = 58;
y = 32;
z = x + y;
定义了三个整型变量 x,y,z,编译时系统会自动为它们各自分配两个内存单元 ( 因为整型量占 2个单元 ),假设 3000和 3001两个单元分配给变量 x,3002和
3003分配给变量 y,3004,3005分配给变量 z。 如图 5-1
所示 。 其中每个变量占用的内存单元的首地址即为该变量的地址 。 如变量 x的地址为 3000,y的地址为 3002,
z的地址为 3004。
执行语句 x = 58;首先是根据变量名与地址的对应关系,找到变量 x的地址 3000,然后将数据 58存储到从由 3000开始的两个字节中 。 同理,y = 32语句的执行将数据 32存储到从由 3002开始的两个字节中 。 显然 58、
32则分别为变量 x和 y所对应的内容 。
[Return]
地址和指针的概念内存区的每一个字节有一个编号,这就是,地址,。
如果在程序中定义了一个变量,在对程序进行编译时,
系统就会给这个变量分配内存单元。
直接访问与间接访问(例如找人)
1,按变量地址存取变量值的方式称为,直接访问,方式
printf( ″%d ″,i);
scanf( ″%d ″,&i);
k=i+j;
2,另一种存取变量值的方式称为,间接访问,的方式。
即,将变量i的地址存放在另一个变量中(用存储在一个变量中的地址去访问这个地址所指示的内存单元的方式) 。
在C语言中,指针是一种特殊的变量,它是存放地址的。例如上图中,整型变量 i的内容为 3,占用了从地址 2000开始的两个连续存储单元。假设又定义了一个变量 i_pointer,假若
i_pointer的值为 2000,也就是说,i_pointer的内容为 x的地址。
我们专门定义了一个变量 i_pointer用来存放另一个变量的地址,以后如果我们要访问变量 i的内容,可以不通过 i直接访问,
而是通过变量 i_pointer,用变量 i_pointer内的地址间接地去访问变量 i,这种访问方式就称为间接访问。
一个变量的地址称为该变量的,指针,。
例如,地址 2000是变量i的指针。在计算机中,地址实际上也是数据(如 3001,3002等),所以地址也可以作为存储单元的内容存放在一个变量中,用来存放指针数据的变量叫做指针变量。如果有一个变量专门用来存放另一变量的地址(即指针),则它称为
“指针变量” 。上述的 i_pointer就是一个指针变量。 称 i_pointer指向变量 i,或说 i_pointer是指向变量 i的指针。
指针和指针变量的定义:
指针简介 2-1
内存
10
int x
ED53地址变量数据
ED53
int ptr_x
指针指针 ptr_x 指向变量 x
指针也是一个变量,只不过该变量中存储的是另一个对象的内存地址
如果一个变量存储另一个对象的地址,则称该变量指向这个对象
由于指针值是数据,指针变量可以赋值,所以一个指针的指向在程序执行中可以改变。指针 p 在执行中某时刻指向变量 x,在另一时刻也可以指向变量 y
指针简介 2-2
声明并初始化指针变量
int *ptrnum;
char *ptralpha;
float *rate_ptr;
double *p,*q;
值为 NULL的指针称为空指针,这意味着,指针并不指向任何地址 。
在头文件 stdio.h 中,NULL 定义为常量 。
ptrnum = NULL;
定义指针变量的一般形式为基类型 *指针变量名;
在定义指针变量时要注意两点:
(1)指针变量前面的,*”,表示该变量的类型为指针型变量。
例,float *pointer_1;
指针变量名是 pointer_1,而不是 * pointer_1 。
(2) 在定义指针变量时必须指定基类型。
需要特别注意的是,只有整型变量的地址才能放到指向整型变量的指针变量中。下面的赋值是错误的 ∶
float a;
int * pointer_1;
pointer_1=&a;
与指针相关的运算符 2-1
int num,*ptrnum;
ptrnum = #
内存
100
num
FF7C
ptrnum
指针FF7C
与指针相关的运算符 2-2
int num,*ptrnum;
ptrnum = #
*ptrnum=15;
内存
100
num
FF7C
ptrnum
指针FF7C15
指针变量的引用例如,假设有以下定义:
int i=200,x;
int *ip;
ip = &i;
执行语句 ip = &i; 此时指针变量 ip指向整型变量 i,以后便可以通过指针变量 ip间接访问变量 i了,例如执行语句,
x = *ip;因为运算符,*”访问以 ip为地址的存贮区域,
而 ip中存放的是变量 i的地址,因此,*ip表示访问变量 i
的地址所占用的存贮区域,所以上面的赋值表达式等价于 x = i; 所以 x的值为 200。
即 *ip等价于 i
指针 的特点
指针变量的命名规则和其他变量的命名规则一样
指针不能与现有变量同名
指针可存放 C 语言中的任何基本数据类型、数组和其他所有高级数据结构的地址
若指针已声明为指向某种类型数据的地址,则它不能用于存储其他类型数据的地址
应为指针指定一个地址后,才能在语句中使用指针通过指针变量访问整型变量
#include <stdio.h>
void main ( )
{ int a,b;
int *pointer_1,*pointer_2;
a=100;b=10;
pointer_1=&a; /*把变量a的地址赋给
pointer_1 */
指针使用示例 1
pointer_2=&b; /*把变量b的地址赋给
pointer_2 */
printf( ″%d,%d \n ″,a,b);
printf( ″%d,%d \n ″,*pointer_1,*pointer_2);

指针使用示例 2
void main()
{
int num1 = 50,num2 = 100;
int *ptr1,*ptr2;
ptr1 = &num1;
printf(" num1 的值是,%d",*ptr1);
printf("\n num1 的地址是,%x \n",ptr1);
ptr2 = &num2;
printf("\n num2 的值是,%d",*ptr2);
printf("\n num2 的地址是,%x \n",ptr2);
*ptr2 = *ptr1;
printf("\n 重新赋值后 num2 的值是,%d",*ptr2);
printf("\n 重新赋值后 num2 的地址是,%x\n",ptr2);
}
内存
num1 ptr1
50 12ff7c
12ff7c
num2 ptr2
100 12ff78
12ff78
50
输入a和b两个整数,按先大后小的顺序输出 a和b。
#include <stdio.h>
void main()
{ int *p 1,*p 2,*p,a,b;
scanf( ″%d,%d ″,&a,&b);
p 1=&a;p2=&b;
if(a<b)
{p=p1;p1=p2;p2=p;}
printf( ″a =%d,b =%d \n \n ″,a,b);
printf( ″max=%d,min=%d \n ″,*p 1,*p 2);

运行情况如下:
5,9 ↙
a=5,b=9
max=9,min=5
当输入a=5,b=9时,由于a<b,
将p1和p2交换。交换前的情况见图
(a),交换后见图(b)。
对“&”和,*”运算符说明:
如果已执行了语句 pointer_1=&a;
(1)& * pointer_1的含义是什么?
“&”和,*”两个运算符的优先级别相同,但按自右而左方向结合。因此,& * pointer_1与&a相同,即变量 a的地址。
如果有 pointer_2 =& * pointer_1 ;它的作用是将
&a(a的地址)赋给 pointer_2,如果 pointer_2原来指向b,经过重新赋值后它已不再指向b了,而指向了a。
(2) *&a的含义是什么?
先进行&a运算,得a的地址,再进行 *运算。 *
&a和 *pointer_1的作用是一样的,它们都等价于变量a。即 *&a与a等价。
(3) ( *pointer_1)++相当于a++。
int x,*ptr_x,*ptr_y;
ptr_x=&x;
ptr_y = ptr_x;
指针赋值运算
100
x
FF7C
ptr_x
ptr_y
FF7C
FF7C
int a[5],*pa;
pa=a;
a[0]
a[1]
a[2]
a[3]
a[4]
23
43
11
50
46
pa
FE60
FE64
FE68
FE6C
FE70FE60
指针变量的运算把字符串的首地址赋予指向字符类型的指针变量。
例如:
char *pc;
pc ="C Language";
或用初始化赋值的方法写为:
char *pc ="C Language";
这里应说明的是并不是把整个字符串装入指针变量,而是把存放该字符串的字符数组的首地址装入指针变量。
int *ptrnum,arr_num[8];
ptrnum = &arr_num[0];
ptrnum++;
指针算术运算 2-1
使用递增 /递减运算符( ++ 和 --)将指针递增或递减 内存
arr_num[0]
arr_num[1]
arr_num[2]
arr_num[3]
arr_num[4]
arr_num[5]
arr_num[6]
arr_num[7]
10
23
15
60
41
49
13
39一个类型为 T 的指针的移动,以 sizeof(T)为移动单位。
将指针加上或者减去某个整数值
ptrnum = &arr_num[0];
ptrnum = ptrnum + 4;
printf(“%d”,*ptrnum);
ptrnum = &arr_num[5];
ptrnum = ptrnum - 2 ;
printf(“%d”,*ptrnum);
指针算术运算 2-2
41
60
内存
arr_num[0]
arr_num[1]
arr_num[2]
arr_num[3]
arr_num[4]
arr_num[5]
arr_num[6]
arr_num[7]
10
23
15
60
41
49
13
39
比较两个指针
#include<stdio.h>
void main ()
{
int *ptrnum1,*ptrnum2;
int value = 1;
ptrnum1 = &value;
value += 10;
ptrnum2 = &value;
if (ptrnum1 == ptrnum2)
printf("\n 两个指针指向同一个地址 \n");
else
printf("\n 两个指针指向不同的地址 \n");
}
指针关系运算指向数组的指针
一个数组存储在一块连续内存单元中;数组名就是这块连续内存单元的首地址;
第 (i + 1) 个数组元素的地址可表示为 &data[i] 或
(data+i)。
可以通过以下方式为指向数组的指针赋值:
int a[10];
pa=&a[0]; // 或者 pa=a;
一个指针变量可以指向一个数组元素
int *ptr,data[10];
ptr=data+3;//或者 ptr=&data[3]
通过指针引用数组元素引用一个数组元素,可以用:
(1) 下标法,如a[i]形式
(2) 首地址法,如 *(a+i)
( 3) 指针法,如 *(p+i)
其中a是数组名,p是指向数组元素的指针变量,其初值p=a。
例 5- 5 输出数组中的全部元素。
假设有一个a数组,整型,有10个元素。要输出各元素的值有三种方法:
(1)下标法。
#include <stdio.h>
void main()
{ int a[10];
int i;
for(i=0;i<10;i++)
scanf( ″%d ″,&a[i]);
printf( ″\n ″);
for(i=0;i<10;i++)
printf( ″%d ″,a[i]);

(2) 通过数组名计算数组元素地址,找出元素的值。
#include <stdio.h>
void main()
{ int a[10];
int i;
for(i=0;i<10;i++ )
scanf( ″%d ″,a+i);
printf( ″\n ″);
for(i=0;i<10;i++)
printf( ″%d ″,*(a+i));

(3) 用指针变量指向数组元素。
#include <stdio.h>
void main()
{ int a[10];
int *p,i;
for(i=0;i<10;i++,p++)
scanf( ″%d ″,p);
printf( ″\n ″);
p=a;
for(i=0;i<10;i++,p++)
printf( ″%d ″,*p); }
三种方法中,方法 (1)比较直观,也容易理解。第
(1)和 (2)种方法执行效率是相同的,都是先计算元素地址,费时较多。最快的是第 (3)种方法,用指针变量直接指向元素,不必每次都重新计算地址,这种有规律地改变地址值的方法能大大提高执行效率。
需要注意的是:指针变量可以实现本身的值的改变。如 p++是合法的; 而 a++则不允许 。因为 a
是数组名,它是数组的首地址,是常量。
另外使用指针变量时,还要时刻注意指针变量的当前值,
否则会出现意想不到的结果。例如,将上例方法 (3)第 7行的 p=a;语句去掉,上机运行看看会出现什么结果。
显然输出的数值并不是 a数组中各元素的值。原因是指针变量的初始值为 a数组首地址,但经过第一个 for循环读入数据后,p已指向 a 数组的末尾。因此,在执行第二个 for循环时,p的起始值不是 &a[0]了,而是 a + 10。因此执行循环时,每次要执行 p++,p指向的是 a数组下面的 10个元素。
因此必须在第二个 for循环之前加一个赋值语句,p = a;
使 p的初始值回到 &a[0],才能得到正确的结果。
指向数组的指针示例 1
#include <stdio.h>
void main()
{
int data[] = {5,10,15,20,25};
int i = 0;
int *ptr;
ptr = data;
while(i < 5)
{
printf(“\n 第 %d 个元素的存储地址为,%x,
值为,%d\n“,i+1,ptr,*ptr);
i++;
ptr++;
}
}
内存
data[0]
data[1]
data[2]
data[3]
data[4]
5
10
15
20
25
12ff6c
12ff70
12ff74
12ff78
12ff7c
第 1个元素的存储地址为,12ff6c,值为,5
第 2个元素的存储地址为,12ff70,值为,10
第 3个元素的存储地址为,12ff74,值为,15
第 4个元素的存储地址为,12ff78,值为,20
第 5个元素的存储地址为,12ff7c,值为,25
ptr
ptr
ptr
ptr
ptr
指向数组的指针示例 2void main()
{
char name[5] = {'M','A','D','A','M'};
int flag = 1;
char *start=name,*end=name+4;
for(;start <= end; start++,end--){
if(*start != *end)
{
flag = 0;break;
}
}
if(flag)
printf("\n 该字符串是回文串 \n");
else
printf("\n 该字符串不是回文串 \n");
}
内存
name[0]
name[1]
name[2]
name[3]
name[4]
M
A
D
A
M
该字符串是回文串
start
end
start
end
endstart
总结 2-1
指针是一个变量,它存储另一个对象的内存地址
指针的声明由基本类型、星号 (*) 和变量名组成
为指针赋值,赋值运算符右侧必须是一个地址。
如果是普通变量需要在前面加一个取地址运算符
&;如果是另一个指针变量或者是一个数组,不需要加 &运算符
运算符 * 用于返回指针指向的内存地址中存储的值总结 2-2
指针的算术运算的含义是指针的移动,将指针执行加上或者减去一个整数值 n的运算相当于指针向前或向后移动 n个数据单元
指针可以执行比较相等的运算,用来判断两个指针是否指向同一个变量
指向数组的指针,存储的是数组中元素的地址。
数组 data的第 (i + 1) 个元素的地址可表示为
&data[i] 或 (data+i)