1.36k likes | 1.5k Views
第十章 指 针. 掌握指针与指针变量的概念; 掌握数组的指针和指针数组的使用; 掌握字符串指针和指向字符串的指针变量的使用; 掌握指针函数和函数指针的使用; 了解指向指针的指针的概念及其使用。. C 程序设计中使用指针可以 : 使程序简洁、紧凑、高效 有效地表示复杂的数据结构 动态分配内存 得到多于一个的函数返回值. 预 备 知 识. 1. 内存的概念. 内存: 就是内部存储器,是由存储单元组成 的。它的特点是存储单元是线性连续 的。存储单元的最小单位是字节。. 2. 地址的概念.
E N D
第十章 指 针 • 掌握指针与指针变量的概念; • 掌握数组的指针和指针数组的使用; • 掌握字符串指针和指向字符串的指针变量的使用; • 掌握指针函数和函数指针的使用; • 了解指向指针的指针的概念及其使用。 C程序设计中使用指针可以: • 使程序简洁、紧凑、高效 • 有效地表示复杂的数据结构 • 动态分配内存 • 得到多于一个的函数返回值
预 备 知 识 1. 内存的概念 内存:就是内部存储器,是由存储单元组成 的。它的特点是存储单元是线性连续 的。存储单元的最小单位是字节。
2. 地址的概念 地址:为了访问内存中的某个存储单元,我们 要为它编号,这种编号称为内存地址。 通过地址我们就能够访问该地址所标 识的存储单元。
编译或函数调用时为其分配内存单元 2007 变量的地址:变量在内存中总占用几个连续的 字节,开始字节的地址,就是变量的地址。 存储单元 变量是对程序中数据存储空间的抽象
…... 整型变量i 2000 10 2001 2002 2003 2004 变量地址(指针) 指针变量 变量i_pointer 2005 指向 地址存入 指针变量 2006 变量值 …... 变量 §10.1 指针及其相关概念 指针:一个变量的地址称为该变量的指针。 指针变量:若一个变量专用于存放另一个变量 的地址(指针),则该变量称为指针变量。 指针 变量的内容 变量的地址 2000 指针变量
直接存取:直接根据变量名存取数据。 间接存取:通过指针变量存取相应变量的数据。 指针的对象:当把变量的地址存入指针变量后, 我们就可以说这个指针指向了该变量。 变量的存取方法:直接存取和间接存取。
…... 整型变量i 2000 10 2001 2002 2003 变量i_pointer 2004 指针变量 2005 2006 …... • 直接访问与间接访问 • 直接访问:按变量地址存取变量值 • 间接访问:通过存放变量地址的变量去访问变量 例i=3; -----直接访问 20 3 2000 例 *i_pointer=20; -----间接访问
§10.2 变量的指针和指向变量的指针变量 一、指针变量的定义 一般形式: [存储类型]类型标识符 *变量名 ; 例 int*p1,*p2; float *q ; static char *name; 表示定义指针变量 不是‘*’运算符 合法标识符 指针的目标变量的数据类型 指针变量本身的存储类型 指针变量的类型:指明了该指针指向的内存空 间所存储的数据类型。 在定义指针变量时要注意以下几个问题: ⑴ 变量名ptr2前面的“*”不能省略,如果写成 int *ptr1, ptr2; 则ptr2被定义为整型变量,而非整型指针变量。
⑵定义中的“*”表示所定义的变量是指针变量,但⑵定义中的“*”表示所定义的变量是指针变量,但 指针变量名是ptr1、ptr2,而非*ptr1、*ptr2。 ⑶指针变量只能指向定义时所规定类型的变量。 这个规定的类型称为该指针变量的“基类型”。 如:上例中ptr1、ptr2只能指向整型变量,不 能指向实型或字符型变量。其“基类型” 相同,都是整型。 ⑷定义指针变量后,并未确定该变量指向何处。 也就是说该变量的值是不确定的。在引用指针 变量前必须首先让它指向一个变量,这一点非 常重要。
例int *p=&i; int i; 例 int i; int *p=&i; 赋给指针变量, 不是赋给目标变量 变量必须已说明过 类型应一致 • 指针变量的初始化 一般形式:[存储类型] 数据类型*指针名=初始地址值; 例 int i; int *p=&i; int *q=p; 用已初始化指针变量作初值 例main( ) { int i; static int *p=&i; .............. } () 不能用auto变量的地址 去初始化static型指针
…... 整型变量i 2000 10 2001 2002 2003 指针变量p 2004 随机 2005 2006 …... 指针变量必须先赋值,再使用 例 main( ) { int i=10; int *p; *p=i; printf(“%d”,*p); } 危险! 例main( ) { int i=10,k; int *p; p=&k; *p=i; printf(“%d”,*p); }
零指针与空类型指针 • 零指针:(空指针) • 定义:指针变量值为零 • 表示:int * p=0; p指向地址为0的单元, 系统保证该单元不作它用 表示指针变量值没有意义 例 int *p; ...... while(p!=NULL) { ...… } #define NULL 0 int *p=NULL: 例 char *p1; void *p2; p1=(char *)p2; p2=(void *)p1; • p=NULL与未对p赋值不同 • 用途: • 避免指针变量的非法引用 • 在程序中常作为状态比较 表示不指定p是指向哪一种类型数据的指针变量 • void *类型指针 • 表示: void *p; • 使用时要进行强制类型转换
*i_pointer i_pointer 10 2000 &i_pointer i …... 整型变量i 2000 10 2001 2002 2003 变量i_pointer 2004 2000 指针变量 2005 2006 …... 二、指针变量的运算 含义: 取变量的地址 单目运算符 优先级: 2 结合性:自右向左 含义:取指针所指向变量的内容 单目运算符 优先级: 2 结合性:自右向左 • 两者关系:互为逆运算 • 理解 ㈠ &与*运算符 • 含义 i_pointer &i &(*i_pointer) i *i_pointer *(&i) i_pointer=&i=&(*i_pointer) i=*i_pointer =*(&i) i_pointer-----指针变量,它的内容是地址量 *i_pointer----指针的目标变量,它的内容是数据 &i_pointer---指针变量占用内存的地址
例如:&a 例如:&a 取变量a的地址。 ptr指向了i变量,*ptr表示i的值,即3
“&”运算和“*”运算是一对互逆运算。 &*ptr&i ptr *&i *ptri 我们还可以用这种方法实现对变量的改变: 由此可见:通过指针运算符“*”可以引用一个变量。如:当ptr已经指向变量i后,*ptr就等同于i。 *ptr=15 ; 等价于 i=15 ; 等价于
㈡ 指针的赋值运算(=) 指针的赋值运算:就是把地址赋值给指针变量。 指针的赋值运算可以是以下三种方式: ⑴使用取地址运算符,把地址值赋值给指针变量。 如:int i, *pi ; pi=&i ; ⑵把指针变量的值赋给另一个指针变量。 如:int i,*pa,*pb; pa=&i ; pb=pa; ⑶给指针变量赋值为符号常量NULL。 如:int *pi ; pi=NULL ; 说明:NULL是一个空指针,表示该指针变量的值没有意义。作用是为了避免对没有被初始化的指针变量的非法引用。NULL 的定义在“stdio.h”中。
说明: ⑴在定义指针变量时,可以立即将一个地址值 赋给指针变量,这就是指针变量的初始化。 指针变量的初始化也是指针的赋值运算。 如:float flt,*f_ptr=&flt; 注意:这不是给*f_ptr赋值 。 ⑵指针变量间的赋值和引用应保证基类型相同。 若有定义: int *p , i ; float *q , x ; 则:q=&i ; ╳ p=&x ; ╳
指针的加减运算(+、-) • 指针的自加自减运算(++,--,+=,-=) 指针±整数 +、- 指针-指针 ㈢ 移动指针的运算 1.指针的+、-运算 说明: ⑴指针与整型值加减的结果是指针,表示使该指针指向该指针下移或上移存储单元个数(整型值)之后的内存地址。存储单元的大小就是该指针的数据类型所需的内存大小。 例如:ptr+n (指针ptr,n为整数)这个指针值代表的内存单元的地址是:ptr+n*d(其中d是指针所指向变量的数据类型所占内存字节数),即指针移动了n个元素。
⑵指针与指针的加运算毫无意义,所以指针与指针⑵指针与指针的加运算毫无意义,所以指针与指针 没有加运算。 ⑶指针与指针的减运算要求相减的两个指针属于同 一类型,其结果是整数,表示两个指针之间的数 据的个数。其结果值的计算公式是: ptr1-ptr2=(ptr1的值- ptr2的值) /指针的数据类型所占的字节数 例如: int *ptr1,*ptr2,*ptr3,x; int ary[5]={2,4,8,16,32}; ptr1 = &ary[0] ; ptr2 = &ary[3]; ptr3 = ary; x=ptr2-ptr1; x 的值是3
2.指针的++、 --、+=、-= 运算 ++、 += :是移动指针到下一个或下几个存储单元。 --、 -= :是移动指针到上一个或上几个存储单元。 例如:int *ptr, ary[5]={2,4,6,8,10} ; ptr=ary; ptr+=3; ptr--; 想一想:*ptr++和(*ptr)++有什么 的区别?
三、指针变量作为函数参数 指针可以用作函数参数,这在调用函数希望改变参数的值时非常有用。 例如:用指针变量编写实现两个数的交换的函数 void swap(int *p1, int *p2); main() { int x1=100,x2=200; printf("x1=%d,x2=%d\n",x1,x2); swap(&x1,&x2); printf("x1=%d,x2=%d\n",x1,x2); } void swap(int *p1, int *p2) { int temp; temp=*p1; *p1=*p2; *p2=temp; }
1 2 3 5 6 4 图示交换过程中存储单元内容的变化:
100 100 100 100 200 x1 x1 a 200 x1 a a 200 200 200 200 100 x2 x2 100 x2 b b b 单向传递,实参的值不变 虚实结合,值传递 虚参a、b的值交换 想一想:如果函数的参数不用指针而用整数,能否实现值的交换?为什么? void swap(int a, int b); main() { int x1=100,x2=200; printf("x1=%d,x2=%d\n",x1,x2); swap(x1, x2); printf("x1=%d,x2=%d\n",x1,x2); } void swap(int a, int b) { int temp; temp=a; a=b; b=temp; }
通过函数调用得到n个要改变的值的方法: ⑴在主调函数中设n个变量,用n个指针变量指向它们; ⑵将指针变量作实参,将这n个变量的地址传给所调用 的函数的形参; ⑶通过形参指针变量,改变该n个变量的值; ⑷主调函数中就可以使用这些改变了值的变量。 注意:不能企图通过改变指针形参的值而使指 针实参的值改变。 如:上例swap函数中不能写成: temp=p1; p1=p2; ;p2=temp;
p1 x1 p1 x1 x1 x1 &x1 100 &x1 100 &x1 100 &x1 100 p2 x2 p2 x2 x2 x2 &x2 200 &x2 200 &x2 200 &x2 200 调用swap函数,实参&x1 &x2的值分别传给p1p2 值传递,单向传递(即使是地址) p1p2的值交换 void swap(int *p1, int *p2); main() { int x1=100,x2=200; printf("x1=%d,x2=%d\n",x1,x2); swap(&x1,&x2); printf("x1=%d,x2=%d\n",x1,x2); } void swap(int *p1, int *p2) { int temp; temp=p1; p1=p2; p2=temp; }
§10.3 数组的指针和指向数组的指针变量 一、数组的指针和指向数组的指针变量的概念 数组的指针 :是数组的起始地址。 数组元素的指针 :是数组元素的地址。 当指针变量指向数组或数组元素时,它就是指向数组的指针变量。 C规定: ⑴数组名代表数组的首地址(起始地址),也就是第一个元素的地址。 ⑵当指针变量p指向数组时,p+1指向数组 的下一个元素。假设一个整型元素占两 个字节,p+1是使p的地址加2个字节。 如:int a[10],*p ; 则:p=a ; 与 p=&a[0];等价 称指针变量p指向数组元素a[0] p+i、a+i 、&a[i]都是a[i]的地址。
⑶ *(p+i)、*(a+i)、a[i]、p[i] 等价, 都代表数组a的第i+1个元素。 二、数组元素的引用 1. 用下标法引用数组元素 如:a[3]=45; b[2][5]=200; 2. 用指针法引用数组元素 假如: int a[10], *p, i ; p=a; 则:⑴*(p+i)、*(a+i)则代表元素a[i] ⑵ *(p+i)也可以写成p[i]
程序举例:输出10个元素数组中的全部元素。 方法一:下标法。 main() { int a[10]={54,65,8,2,3,56,8,21,57,98}, i; for(printf("\n"),i=0;i<10;i++) printf("%4d",a[i]); } 方法二:通过数组名计算数组元素地址,找出元素的 值。 main() { int a[10]={54,65,8,2,3,56,8,21,57,98},i; for(printf("\n"),i=0;i<10;i++) printf("%4d",*(a+i)); }
方法三:用指针变量指向数组元素 main() { int a[10]={54,65,8,2,3,56,8,21,57,98},*p,i; p=a; for(printf("\n"),i=0;i<10;i++) printf("%4d",*p++); } 以上三种方法,利用指针变量效率最高。 说明:⑴指针变量与数组名的区别: 指针变量是地址变量,数组名是地址常量。即指针变量的内容可以在程序运行过程中被改变;而数组名一旦被定义,它的值就不能被改变了。 例如: int i, *p, a[6]; 则:p=&i ; √ a=&i ;a++;a+=i ; 不能给常量赋值
p p p p p p p ⑵利用指针变量编程时特别要注意指针变量 的当前值。 例如:通过指针变量输入输出a数组元素。 main() { int *p,i,a[7]; p=a; for(i=0;i<7;i++) scanf("%d",p++); for(printf(“\n”),i=0;i<7;i++) printf(“%6d”,*p++); } 应插入语句 p=a; 指针变量可以指到数组后的内存单元 注意:*p++、*(p++)、(*p)++、*(++p)的含义
注意: *p++: *(p++): *(++p): (*p)++: 右结合性,先用再加,同下 得到p指向的变量的值,然后使指针下移 先加再用,先使p加1,然后取*p的值 表示所指向的元素值加1 若p指向a数组中第i个元素,则: *p(--):a[i--],先对p进行*运算,再使p自减 * (++p):a[++i],先使p自加,再作*运算 *(--p):a[--i],先使p自减,再作*运算
三、数组名作函数的参数 例如: f(int arr[],int n) {…… } main() { int array[10]; …… f(array,10); …… } 现在解释: 实际上,能够接受并存放地址值的只能是指针变量。因此,C编译系统都是将形参数组名作为指针变量来处理的。左例中f(int arr[ ],int n) 等价于 f(int *arr, int n)。 使用形参数组的概念只是为了与实参数组对应,直观,便于理解而已。
例:从10个数中找出其中最大值和最小值。 void max_min(int a[],int n,int *max,int *min); main() { int i,a[]={2,4,1,6,7,32,45,75,45,90},max,min; for(printf("The original array="),i=0;i<10;i++) printf("%5d",a[i]); max_min(a,10,&max,&min); printf("max=%d min=%d",max,min); } void max_min(int a[], int n, int *max, int *min) { int i; *max=*min=a[0]; for(i=0;i<n;i++) { if(*max<a[i]) *max=a[i]; if(*min>a[i]) *min=a[i]; } }
上例中如果形参数组用指针变量,则程序如下: void max_min(int *x,int n,int *max,int *min); main() { int i,a[10]={2,4,1,6,7,32,45,75,45,90},max,min; for(printf("The original array="),i=0;i<10;i++) printf("%5d",a[i]); max_min(a,10,&max,&min); printf("=%d min=%d",max,min); } void max_min(int *x, int n, int *max, int *min) { int i; *max=*min=*x; for(i=1; i<n; i++, x++) { if(*max<*x) *max=*x; if(*min>*x) *min=*x; } }
实参 形参 数组名 数组名 数组名 指针变量 指针变量 数组名 指针变量 指针变量 数组名做函数参数小结: 如果有一个实参数组,想在函数中改变此数组的元素的值,实参与形参都可用数组名或指针变量其对应关系有以下4种情况: 注意:用指针变量作实参时一定要有确定的值。
一级指针变量与一维数组的关系 int *p 与 int q[10] • 数组名是指针(地址)常量 • p=q; p+i是q[i]的地址 • 数组元素的表示方法:下标法和指针法, 即若p=q, 则p[i] q[i] *(p+i) *(q+i) • 形参数组实质上是指针变量,即int q[ ] int *q • 在定义指针变量(不是形参)时,不能把int *p写成int p[]; • 系统只给p分配能保存一个指针值的内存区(一般2字节) 而给q分配2*10字节的内存区
int array[10]; array 四、二维数组的指针 1.二维数组的指针概念 对于一维数组: (1)数组名array表示数组的首地址, 即array[0]的地址; (2)数组名array是地址常量 (3)array+i是元素array[i]的地址 (4)array[i] *(array+i)
在C语言中,一个二维数组可以看成是一个一维数组,其中每个元素又是一个包含若干元素的一维数组。 假如有定义:int a[2][3]; 则C语言编译程序认为a数组是由a[0],a[1]两个元素组成的一维数组,a[0]和a[1]分别是包含三个元素的一维数组名,分别代表数组元素的起始地址(即a[0]是第0行元素的首地址, a[1]是第1行元素的首地址)。因此,a和a[0]是两个基类型不同的指针常量。
*(a[0]+1) *(*(a+0)+1) 2000 a 2000 a[0] a[0][0] 2002 a[0]+1 a[0][1] *(a+0)+1 a[0][2] a[0][3] 2008 a+1 2008 a[1] a[1][0] 2010 a[1]+1 a[1][1] *(a+1)+1 a[1][2] a[1][3] 2016 a+2 2016 a[2] a[2][0] 2018 a[2]+1 a[2][1] *(a+2)+1 a[2][2] a[2][3] 行指针与列指针 int a[3][4]; 对于二维数组: (1)a是数组名, 包含三个元素 a[0],a[1],a[2] (2)每个元素a[i] 又是一个一 维数组,包 含4个元素 基类型
int a[3][4]; 2000 2000 a a[0][0] a[0] 2002 a[0][1] a[0][2] a[0][3] 2008 2008 a+1 a[1][0] a[1] 2010 a[1][1] a[1][2] a[1][3] 2016 a+2 2016 a[2] a[2][0] 2018 a[2][1] a[2][2] a[2][3] • 对二维数组 int a[3][4],有 • a:二维数组的首地址,即第0行的首地址 • a+i:第i行的首地址 • a[i] *(a+i):第i行第0列的元素地址 • a[i]+j *(a+i)+j:第i行第j列的元素地址 • *(a[i]+j) *(*(a+i)+j) a[i][j] • a+i=&a[i]=a[i]=*(a+i) =&a[i][0], 值相等,含义不同 • a+i &a[i],表示第i行首地址,指向行 • a[i] *(a+i) &a[i][0],表示第i行第0列元素地址,指向列
int a[3][4]; 行指针 a[0][0] a[0][1] 列指针 a[0][2] a[0][3] a[1][0] a[1][1] a[1][2] a[1][3] a[2][0] a[2][1] a[2][2] a[2][3] 地址表示: (1) a+1 (2) &a[1][0] (3) a[1] (4) *(a+1) (5)(int *) (a+1) 地址表示: (1) &a[1][2] (2) a[1]+2 (3) *(a+1)+2 (4)&a[0][0]+1*4+2 二维数组元素表示形式: (1)a[1][2] (2)*(a[1]+2) (3)*(*(a+1)+2) (4)*(&a[0][0]+1*4+2)
表示形式 地址 含义 a 2000 二维数组名,数组首地址 2000 a[0],*(a+0),*a 第0行第0列元素地址 2008 a+1 第1行首地址 2008 第1行第0列元素地址 a[1],*(a+1) 2012 第1行第2列元素地址 a[1]+2,*(a+1)+2,&a[1][2] 第1行第2列元素值 13 *(a[1]+2),*(*(a+1)+2),a[1][2]
p int a[3][4]; a[0][0] a[0][1] a[0][2] a[0][3] a[1][0] a[1][1] a[1][2] a[1][3] a[2][0] p=*a; p=&a[0][0]; p=(int *)a; p=a; a[2][1] a[2][2] a[2][3] 例 指向二维数组元素的指针变量 main() { static int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23}; int *p; for(p=a[0];p<a[0]+12;p++) { if((p-a[0])%4==0) printf("\n"); printf("%4d ",*p); } } • 二维数组的指针变量 • 指向二维数组元素的指针变量 p=*a; p=&a[0][0]; p=*(a+0); p=a;
p a int a[3][4]; p[0]+1或 *p+1 a[0][0] *(*p+1)或 (*p)[1] a[0][1] a[0][2] p+1 a+1 a[0][3] a[1][0] p[1]+2或 *(p+1)+2 a[1][1] *(*(p+1)+2) a[1][2] p+2 a+2 a[1][3] a[2][0] a[2][1] a[2][2] a[2][3] • 可让p指向二维数组某一行 如 int a[3][4], (*p)[4]=a; • 指向一维数组的指针变量 • 定义形式: 数据类型 (*指针名)[一维数组维数]; 例 int (*p)[4]; p的值是一维数组的 首地址,p是行指针 ( )不能少 int (*p)[4]与int *p[4]不同 (1)p是一个指向由3个整型元素组成的一维数组的指针变量。 (2)p指向a数组,p+1指向数组a的下一行首地址,a和p的基类型相同,则a数组中任意元素a[i][j]还可以如下表示: *(p[i]+j) 、*(*(p+i)+j) 、(*(p+i))[j] 、p[i][j] 一维数组指针变量维数和 二维数组列数必须相同
p p p int a[3][4]; a[0][0] a[0][1] a[0][2] a[0][3] a[1][0] a[1][1] a[1][2] a[1][3] a[2][0] p=a[0]; p=*a; p=&a[0][0]; p=&a[0]; a[2][1] a[2][2] a[2][3] 例 一维数组指针变量举例:使用行指针变量访问数组元素。 main() { static int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23}; int i,j,(*p)[4]; for(p=a,i=0;i<3;i++,p++) for(j=0;j<4;j++) printf("%d ",*(*p+j)); printf("\n"); } p[0][j] p=a[0]; p=*a; p=&a[0][0]; p=&a[0];
若int a[3][4];int (*p1)[4]=a; int *p2=a[0]; 实参 形参 数组名a 数组名int x[][4] 数组名a 指针变量int (*q)[4] 指针变量p1 数组名int x[][4] 指针变量p1 指针变量int (*q)[4] 指针变量p2 指针变量int *q • 二维数组的指针作函数参数 • 用指向变量的指针变量 • 用指向一维数组的指针变量 • 用二维数组名
79 60 52 65 80 87 90 81 90 99 100 98 p p 例 3个学生各学4门课,计算总平均分,并输出第n个学生成绩 函数说明 void average(float *p,int n) { float *p_end, sum=0,aver; p_end=p+n-1; for(;p<=p_end;p++) sum=sum+(*p); aver=sum/n; printf("average=%5.2f\n",aver); } void search(float (*p)[4], int n) { int i; printf(" No.%d :\n",n); for(i=0;i<4;i++) printf("%5.2f ",*(*(p+n)+i)); } main() { void average(float *p,int n); void search(float (*p)[4],int n); float score[3][4]= {{65,67,79,60},{80,87,90,81}, {90,99,100,98}}; average(*score,12); search(score,2); } 列指针 行指针 float p[][4] p[n][i]
二维数组与一维数组指针变量的关系 如 int a[5][10] 与int (*p)[10]; • 二维数组名是一个指向有10个元素的一维数组的指针常量 • p=a+i使 p指向二维数组的第i行 • *(*(p+i)+j) a[i][j] • 二维数组形参实际上是一维数组指针变量, 即 int x[ ][10] int (*x)[10] • 变量定义(不是形参)时两者不等价 • 系统只给p分配能保存一个指针值的内存区(一般2字节);而给a分配2*5*10字节的内存区
字符指针变量定义的一般形式: char *指针变量名; 例如:char *strp=“Hello!”; 定义了一个指向字符串的指针变量,并将字符串的首地址赋值给strp指针变量,即:使指针变量strp指向字符串首地址。 §10.4 字符串指针和指向字符串的指针变量 字符串指针:字符串的首地址。 字符指针变量:指向字符串的指针变量。 字符指针变量定义时可以赋初值。
C程序访问字符串有以下两种方法: 1. 用字符数组存放一个字符串 例如:char s []="I am a student."; 字符串输出语句可写成: ⑴ printf(“%s\n”,s); ⑵ for(i=0; s[i]; i++)printf(“%c”, s[i]); ⑶ for(i=0; s[i]; i++)printf(“%c”,*(s+i)); 也可用s[i]!=‘\0’ 2.用字符指针指向一个字符串 例如:char *ps="I am a student."; 字符串输出语句可写成: ⑴ printf(“%s\n”,ps); ⑵ for(; *ps; ps++)printf(“%c”, *ps);