760 likes | 916 Vues
程序设计基础( C 语言). 东北大学高级语言程序设计课程组 课程网站: www.neu.edu.cn/cxsj. 程序设计基础( C 语言). 指针. 概述. 指针是C语言的重要概念之一 它使C语言比之其它程序设计语言更具特色 深入理解C语言特性 指针是学习使用C语言的难点 指针是 C 语言的一个重要概念 正确而灵活地使用指针 有效地描述各种复杂的数据结构 动态地分配内存空间 自由地在函数之间传递各种类型的数据 使程序简洁、紧凑,执行效率高 指针是 C 提供的一种数据结构 属于简单数据类型 它的意义和作用明显又不同于一般的数据类型. 直接. A.
E N D
程序设计基础(C语言) 东北大学高级语言程序设计课程组 课程网站:www.neu.edu.cn/cxsj
程序设计基础(C语言) 指针
概述 • 指针是C语言的重要概念之一 • 它使C语言比之其它程序设计语言更具特色 • 深入理解C语言特性 • 指针是学习使用C语言的难点 • 指针是C语言的一个重要概念 • 正确而灵活地使用指针 • 有效地描述各种复杂的数据结构 • 动态地分配内存空间 • 自由地在函数之间传递各种类型的数据 • 使程序简洁、紧凑,执行效率高 • 指针是C提供的一种数据结构 • 属于简单数据类型 • 它的意义和作用明显又不同于一般的数据类型
直接 A 间接 B A …… …… 1.预备知识 • 直接和间接的含义 • 内存 • 即内部存储器,是由内存单元组成 • 特点 • 存储单元是线性连续的 • 存储单元的最小单位为字节
地址 0 1 2 3 … 2000 …… …… 45 变量内容 1.预备知识 • 内存 • 计算机的内存中的每一个字节都有一个编号 • 所有的内存单元都要统一进行“编号” • 这个编号就是该字节在整个内存中的“地址” • 所有的内存单元都要有地址 • 每一内存单元具有唯一的内存地址 • 系统为每一个已定义的变量分配一定存储空间 • 使变量名与内存的一个地址相对应 • 通过地址我们就能够访问该地址所标识的存储单元 • 程序处理过程 • 需要根据地址取出变量所对应的内存单元中存放的值 • 参与计算/操作 • 处理结果存入相应的变量名所对应的内存单元
存入/取出 存入/取出 1.预备知识 • 计算机的寻址方式 • 直接寻址 • 间接寻址 数据 数据 内存 地址 … 1003 1004 1008 100C 内存 数据 数据 地 址 地址 … 1050 1051 … 3020 3021 … A单元 B单元
1.预备知识 • C语言如何处理? • 高级语言中的变量具有三个属性 • 变量的名、变量的值、变量的地址 • 编程者使用c程序的一个变量 • 定义变量的数据类型 • 数据类型决定了一个变量在内存中所占用的存储空间的大小 • 变量在内存中总是占用几个连续的字节 • 定义变量名 • C语言的编译系统会根据变量的数据类型为该变量分配内存单元 • 确定变量的地址 • 变量的地址就是为变量分配的内存单元的起始编号 • 就可以通过变量名对内存中变量对应的地址进行操作
地址 变量名 变量类型 字节数 2000 i int 2 10 2001 2002 2003 2004 2005 2006 2007 pi float 4 3.1415926 ‘a’ ch char 1 1.预备知识
1010 300 1012 2002 2004 1010 1.预备知识 • C语言如何处理? • 直接访问 • 通过变量名访问数据的方式称为"直接访问" • 例如:printf("%d", n); /* 通过变量名访问变量n */ • 间接访问 • 如果将变量n的地址存放在另一个变量pn中,通过访问变量pn,间接达到访问变量i的目的,这种方式称为变量的"间接访问" • 在C语言中,间接寻址方式访问内存是通过指针变量实现的 • 指针变量通过直接寻址方式访问获得的是一个地址值 • 在该地址起始的一个存储单元中存放程序需要的数据
2.指针变量 • 定义 • 用于指向其他变量的变量 • 指针变量是一个变量 • 和普通变量一样占用一定的存储空间 • 该存储空间存放的是一个地址值而不是普通的数据值 • 指针变量是一个地址变量 • 指针变量的值是一个内存单元的地址 • 它指向另一个变量的值 • 指针就是地址 • 当将变量的地址存入指针变量后,就说这个指针指向了该变量 • 指针变量只能存放某一数据类型的变量 • 问题? • 变量的类型和指向变量的类型之间的区别?
2.指针变量 • 指针变量的声明 • 指针变量与一般的变量的区别 • 格式<数据类型名> *指针变量名; • 说明 • 数据类型表示指针所指向的数据的数据类型 • 提示:不是指针变量的数据类型 • *是指针的标志,表示它后面的变量名是指针类型 • 例 • int *i_p;/*定义了指针变量i_p ,指向的对象类型为整型*/ • char *cp;/*定义了指针变量cp, 指向的对象类型为字符型*/
2.指针变量 • 指针变量的声明 • 提示 • 声明语句的*只能用于指针变量 • 这种表示方式说明被声明的变量是一个指针 • *不针对声明语句中的所有变量 • 每一个指针都必须在其名字前面有一个前缀*声明 • 例如:int *pt1,pt2; • pt2为整型变量而不是整型指针变量 • 指针变量名是pt1而不是*pt1 • 指针变量只能指向定义时规定的类型变量 • 只有同一数据类型的地 址才能存放在指向该类型变量的指针变量中 • 例如: int *ip;/*ip指针变量只能存放整型变量的地址*/
内存单元 指针P 指针变量p的地址 2.指针变量 • 指针变量的声明 • 提示 • 在定义指针时可以用void将指针定义为空类型 • 不指定指针指向一个确定的类型 • 区分“值”与“内容”的含义 • 例如 • 整型变量是内容为整型数值的变量 • 整型指针变量是存放整型变量地址的变量 • 在引用指针变量前必须首先让指针指向一个变量 • 这一点非常重要 • 定义指针变量后,并未确定该变量指向何处,该变量的值是不确定的
2.指针变量 • 指针变量初始化 • 在使用指针变量时,要首先对指针变量进行初始化,让指针变量指向一个具体的变量 • 初始化的方式 • 使用赋值语句 • 例 • int i, *pi; /* 说明指针变量pa和变量a */pi=&i; /*使用取地址符&把变量i的地址赋值给指针变量:pi指向了整型变量i */ • 说明指针变量的时候同时进行 • 例:使用先声明变量的地址 • int i,*pi=&i; • 问题? • 写成int *pa; *pa=&a;会出现什么问题?
指针变量 指针P 空地址NULL 内存单元 2.指针变量 • 指针变量初始化 • 在使用指针变量时,要首先对指针变量进行初始化,让指针变量指向一个具体的变量 • 初始化的方式 • 给指针变量赋空值(赋值为符号常量NULL ) • 例 • p=NULL;/*表示指针p为空,没有指向任何对象*/ • 一般情况下给没有初始值的指针变量赋值为NULL • 实际上,NULL是整数0,系统保证0单元不存储任何数据的值(地址) • NULL是头文件<stdio.h>以及其它几个头文件中定义的符号常量
2.指针变量 • 指针变量初始化 • 提示 • 在使用指针之前一定要对其进行初始化 • 否则程序不知道指向何处 • 系统在执行程序时会给出如下的信息 • run-time error R6001——null pointer assigment • 或者引起更严重的错误——系统崩溃 • 对未使用的指针应该赋以空值NULL • 表明它未指向任何地方 • 这并不是对指针的初始化 • 只是 表示该指针未被使用而已
2.指针变量 • 指针变量初始化 • 提示 • 一个指针变量赋空值与不赋值是完全不同的概念 • 前者是有不指向任何变量的地址 • 后者是一个不确定的随机值 • 这时指针可能指向一个事先未指定的数据 • 利用空指针可以简化程序代码、提高效率 • 指针变量应具有无符号整型类型的值 • 存放的是地址 • 由于地址本身的特征,不能将一个整型值赋给一个指针变量。同样也不能将指针变量的值赋给一个整型变量 • 例如:int *p;p=2000;(非法)
2.指针变量 【例】定义指针变量 void *p2; int *p1,i=5; p1=&i;p2=p1; 演示91。C • 指针变量初始化 • 提示 • 用void将指针定义为空类型 • 即不指定指针指向一个确定的类型 • 例如:void *p;/*表示指针变量P不指向一个确定的类型*/ • 它的作用仅用来存放一个地址 • 作用 • 任何类型的指针都可以赋给指向void类型的指针 • 指向void类型的指针也可以赋给任何类型的指针 • 但是:不能复引用void*类型的指针 • 编译器不能根据类型确定它引用的字节数 • 常见错误 • 将一种类型的指针赋给另一种类型的指针,而这两种指针都不是void*类型
3.指针变量 • 指针变量的运算 • C语言提供的指针运算 • 取地址运算(&) • 作用是取变量的地址 • 运算对象必须是(任意类型的)变量 • 例如 • &i /*表示求变量 i的地址*/ • int x=3, *p;p=&x /* &x表示取x的地址,将变量x地址赋给指针变量p */ • 提示 • &是一个单目运算符,它返回变量的地址 • &的操作数必须是一个变量 • 取地址运算符“&”是取操作对象的地址而不是其值
3.指针变量 • 指针变量的运算 • C语言提供的指针运算 • 取内容运算(*) • 运算对象必须是指针(该指针所指向的对象可以是任意类型) • 作用是取指针所指向变量的内容。*也称为“间接引用运算符”或“指针的复引用” • 例如 • a=*prt; /*表示指针 prt所指向变量的内容赋a*/ • int a=3, *p, x;pa=&a; • x=*pa; /* *pa表示取指针变量pa所指单元的内容,即变量a的值,则x=3 */
3.指针变量 • 指针变量的引用 • 当指针变量定义和赋值之后,引用变量的方式 • 用变量名直接引用 • 例如 • scanf(“%d”,&a);/*在函数中直接使用变量a的地址 */ • 通过指向变量的指针间接引用 • 利用指针变量,提供对变量的一种“间接访问”形式 • 指针变量的引用形式 *指针变量 • 含义是指针变量所指向的值 • 例如 • int a=3,*pa;pa=&a; /* 指针pa指向变量a*/printf("%d\n",*pa); /* 通过 * 运算符实现间接访问 */
3.指针变量 • 指针变量的引用 • 例:用指针变量进行输入输出 main() { int *p,m; scanf(“%d”,&m); p=&m; printf(“%d”,*p); } main() { int *p,m; p=&m; scanf(“%d”,p); printf(“%d”, m ); } 运行结果完全一样。请思考一下若将程序修改为如下形式: main() {int *p,m; scanf(“%d”, p ); p=&m; printf(“%d”, m ); }会产生什么结果?
3.指针变量 • 指针变量的引用 • 例:本程序演示了指针运算符的用法 #include<stdio.h> main() { int a, *aptr; a=7; aptr=&a; printf(“The address of a is %p\n” ”The value of aptr is %p\n\n”,&a,aptr); printf(“The value of a is %d\n” ”The value of *aptr is %d\n\n”,a,*aptr); printf(“Proving that * and & are complements of” ”each other .\n&*aptr=%p\n*&aptr=%p\n”, &*aptr,*&aptr); }
3.指针变量 【例】 main() {int *p1,*p2; int i=10,j=20; p1=&i; p2=&j; p2=p1; printf(“*p1=%d;*p2=%d\n”,*p1,*p2); printf(“i=%d;j=%d\n”,i,j); printf(“p1=%p,p2=%p\n”,p1,p2); } 结果为: *p1=10;*p2=10 i=10;j=20 本题中若*p2=*p1? 将p1指向变量的值传递给* p2的内存单元。即j的内存单元中,P2和p1中存放的地址并不发生变化。 结果: *p1=10;*p2=10 i=10;j=10
3.指针变量 • 指针变量的提示 • 取内容运算符*p与定义指针变量时使用的*p含义不同 • 定义时的*p表示的是一个指针变量,该变量指向一个整型变量的地址 • 取内容运算符*p则表示取指针变量的内容,即另一个变量值 • 对指针的引用需要*和& • &用于求任一类型变量的指针,求出的指针具有对应的类型 • *和指针一起使用时被认为是同类型的一个变量 • 可以参与该类型变量的一切运算 • *和&是一对功能恰好相反的运算操作符 • 在实际应用中, 应特别注意&和*的操作对象 • &的操作对象是一个“变量” • *的操作对象是一个“地址”
4.指针与数组 • 指针和数组紧密联系 • 对数组元素的访问可以通过指针和借助数组元素下标的方法实现 • 凡是由数组下标完成的操作皆可用指针来实现 • “下标方式“访问数组元素 • 通过数组的下标唯一确定了某个数组元素在数组中的顺序和存储地址 • 例如:int a[5] = {1, 2, 3, 4, 5}, x x=a[0]; /* 通过下标将第1个元素的值赋给x=1 */
4.指针与数组 • 指针和数组紧密联系 • 对数组元素的访问可以通过指针和借助数组元素下标的方法实现 • 凡是由数组下标完成的操作皆可用指针来实现 • 指针最常见的一种用途就是指向数组元素 • 当一个指针指向数组后,就可以灵活快速地处理数组元素,从而体现出指针的优点 • “指针方式”访问数组中的元素 • 一个数组(/数组元素)有相应的地址,可以将数组的起始地址或某一个数组元素的地址放到一个指针变量中 • 数组的指针就是数组的起始地址(数组名),既数组第一个元素的地址(&数组名[0]) • 数组元素的指针就是该数组元素的地址
4.指针与数组 • 指针和数组紧密联系 • 分析程序 • C语言中规定 • 数组第1个(下标为0)元素的地址就是数组的首地址 • 数组名代表的就是数组的首地址 • 数组名代表的一个地址常量,是数组的首地址 • 它不同于指针变量 #include <stdio.h>main ( ){ int a[ ] = {1, 2, 3, 4, 5} ; int x, y, *pt,*p2;pt = &a[0]; x = *(pt+2); p2=&a[4]; y=pt[4]; printf ("*p=%d, x=%d, y=%d\n", *pt, x,y,*p2); }
*(pt+2) pt[2] ary[2] *(ary+2) 4.指针与数组 • 指针和数组紧密联系 • C语言中规定说明 • 当指针指向数组首地址时(pt=ary或pt=&ary[0]时) 指针可以向数组一样使用 • 提示 • 对数组元素的访问,下标方式和指针方式是等价的 • 从C语言系统内部处理机制上讲,指针方式效率高 • 指针方式不如下标方式直观 • 下标方式可以直截了当地看出要访问的是数组中的哪个元素 • 指向数组的指针变量,进行运算以后,指针变量的值改变了,其当前指向的是哪一个数组元素不再是一目了然
4.指针与数组 • 指针和数组的可替代性 • C语言中的指针和数组几乎可以互换 • 指针可以用来完成涉及数组下标的操作 • 例如:int a[10];int *p; • 若p=&a[0];或 p=a;则p就指向了数组a的首址 • 当p指向了一维数组a,指针对数组元素可以表示: • p+n与a+n( n (偏移量)的取值为0~9 )表示数组元素 a[n]的地址,既&a[n] • *(p+n)和*(a+n) 表示数组元素a[n] ( n的取值为0~9 ) • 指向数组的指针变量也可以用数组的下标形式p[n],其效果相当于*(p+n),等价于a[n]
4.指针与数组 这两个函数都将一 个字符串(可能是 一个字符数组)拷 贝到一个字符数组 中,比较这两个函 数原型可以发现其 形式是相同的,虽 然这两个函数完成 同样的功能,但是 他们的实现过程是 不同的。 • 指针和数组的可替代性 • 例 #include<stdio.h> void strcopy1(char str[],const char *); void strcopy2(char str[],const char *); main( ) { char str1[10],*str2=“teacher”; char str3[10],*str4=“boys and girls”; strcopy1 (str1,str2); printf(“str1=%s\n”,str1); strcopy2(str3,str4); printf(“str3=%s\n”,str3); }
4.指针与数组 /* 采用数组表示法将s2拷贝到s1.*/ void strcopy1(char *s1,const char *s2) { int i; for(i=0;s1[i]=s2[i];i++) ; /*函数体中没有任何动作*/ } /* 采用指针表示法将s2拷贝到s1.*/ void strcopy2(char *s1,const char *s2) { for( ;*s1=*s2;s1++,s2++) ; /*函数体中没有任何动作*/ }
4.指针与数组 • 指针和数组的可替代性 • 数组的表示法 • 数组/下标 • 指针/偏移量 • 利用*p、*(p+1)、来代表数组a[0]、a[1] • 数组/偏移量 • 对数组的引用以*a、*(a+ 1)、代替a[0]、…a[9] • 指针/下标 • 表达式p[1]引用了数组元素a[1]
4.指针与数组 【例1 】采用指针/偏移量表示的地址法输入输出数组元素。 main() { int n,a[10],*pa=a; /*定义时对指针变量初始化*/ for (n=0;n<=9;n++) scanf(“%d”,pa+n); for(n=0;n<=9;n++) printf(“%d”,*(pa+n)); printf(“\n”); } 【例2】采用表示的数组/偏移量表示的地址法输入输出数组元素。 main() { int n,a[10],*pa=a; /*定义时对指针变量初始化*/ for (n=0;n<=9;n++) scanf(“%d”,a+n); for(n=0;n<=9;n++) printf(“%d”,*(a+n)); printf(“\n”); }
4.指针与数组 【例3】采用指针/下标法输入输出数组元素。 main() { int n,a[10],*pa=a; for (n=0;n<=9;n++) scanf(“%d”,&pa[n]); for(n=0;n<=9;n++) printf(“%d”,pa[n]); printf(“\n”); } 【例4】采用数组/下标法输入输出数组元素。 main() { int n,a[10]; for (n=0;n<=9;n++) scanf(“%d”,&a[n]); for(n=0;n<=9;n++) printf(“%d”,a[n]); printf(“\n”); }
4.指针与数组 • 指针和数组的可替代性 • 例:将一个数组按正向、逆向输出 main() {int ary[4]={2,4,8,16}; int *iprt,i; iprt=ary; /*按正序输出数组元素*/ for (i=0;i<4;i++) printf(“%d”,iprt[i]); prntf(“\n”); /*按逆序输出数组元素*/ for (i=3;i>=0;i- -) printf(“%d”,*( iprt+i )); prntf(“\n”); }
4.指针与数组 • 指针和数组的关系 • 提示 • 指针变量与数组的区别 • 指针变量是地址变量,数组名是地址常量 • 指针变量的内容可以在程序运行过程中被修改,数组名一旦被声明,它的值在整个程序运行中是不能改变 • (p+1)和 *(a+ 1)都可以表示数组元素a[1], 两者并不能完全等价 • 对 数组a只能引用,不能修改 • 实际上就是指针与指针变量的区别 • 对于数组名,虽然可以使用它得到其元素的值,但它仅表示数组的首地址,不能将其改变 • 试图用指针算术运算修改数组名是一种语法错误
4.指针与数组 • 指针和数组的关系 • 提示 • 指针变量与数组的区别 • 指针变量可以改变其自身的值,应该特别注意其的当前值 • 例如:对上例程序中的a和pa,若有程序段: pa=a;printf(”%d\n”,*pa); pa++;printf(“%d\n”,*pa); • 第一个printf输出的是a[0]的值 • 第二个printf则输出的是a[1]的值 • 指向数组的指针在数组处理时不要越界 • 由于C语言不检查数组越界,对一个仅有10个元素的数组a引用第11个元素a[10]时系统仍按 *(a+10)处理,发生错误
4.指针与数组 • 指针的运算 • 指针的运算旨在针对数组进行 • 指针的运算 • 指针与正整数的加减运算 • 两个指针的减法运算 • 两个指针的关系运算 • 禁止的运算 • 指针做乘除法运算 • 指针进行位操作运算 • 指针与浮点型数据运算 • 两个指针相加没有意义 • 指针运算的结果依赖于指针所指向对象的大小 • 指向对象的数据类型
内存 地址 … 2000 2001 2002 2003 2004 2005 2006 2007 2008 · 指针变量ptr 4.指针与数组 • 指针的运算 • 指针与正整数的加减运算 • 该指针下移或上移整型值所指定个数的存储单元的内存地址 • 存储单元的大小就是该指针的数据类型所需要的内存的大小 • p+(-)i*sizeof(type) • 对指针的加/减(整数)操作运算在用指针访问数组元素是经常用到 • 表达式:p+n表示指针p所指向当前元素之后的第n个元素 • 而表达式:p-n表示指针p所指向当前元素之前的第n个元素
a[10] a[10] a[0] a[1] … a[i] … a[9] a[0] a[1] … a[i] a[9] 2000 2002 2004 200+2*i … 2018 p p-i p+i p 4.指针与数组 • 指针的运算 • 指针与正整数的加减运算 • 例如: int a[10] ,*p; p=a;(或p=&a[0] ;)
array[5] array[0] array[1] array[2] array[3] array[4] (1) array prt 2 2000 (5) 4 2002 (3) 2004 6 (2) 2006 8 2008 10 4.指针与数组 • 指针的运算 • 指针与正整数的加减运算 • 自增/自减 • 指针的自增(++)/自减(--)运算分别表示将指针移动到下一个/上一个存储单元并指向新的数据 • p++的含义 • 指针加1,指向数组中的下一个元素 • p--的含义 • 指针减1,指向数组中的前一个元素 main() {int *prt; int arrary[]={2,4,6,8,10}; prt=array; prt+=3; prt--; prt-=2; prt++; }96。C
4.指针与数组 • 指针的运算 • 提示 • 例如:int a[5],*pa:pa=a; • pa++; /*使pa指向下一个元素a[1];*/ • *pa; /*指针所指向的数组名(或变量或数组元素)*/ • *pa++; /*先取出pa所指向元素的值 (*pa),后pa+1送 与pa。由于++与*的优先级相同,自右向左的结 合方向,所以它等价于*(pa++);*/ • *(++pa);/*先令pa加1,再取pa指向的值*/ • (*pa)++; /*pa所指向的元素的值加1,即(a[0])++*/ • 对于--运算同上
4.指针与数组 • 指针的运算 • 两个指针的减法运算 • 减法运算的含义 • 当两个指针指向同一数组中的元素时 • p-q表示计算两个指针相差的存储单元个数 • 计算公式为 提示 • 只有当两个指针指向同一数组中的元素时才可进行两个指针的减法运算 prt1-prt2= (prt1的值-prt2的值)/指针的数据类型的所占字节数
4.指针与数组 • 指针的运算 • 两个指针的减法运算 • 例:计算一个字符串的长度(不用strlen函数) #include<stdio.h> main() { int len; char a[80] ; gets(a); puts(a); len=lenth(a); printf(“%d\n” ,len); } lenth(char *p) { char *q=p; while (*q!=‘\0’) q++; return(q-p); }
4.指针与数组 • 指针的运算 • 两个指针的关系运算 • 比较两个指针的含义 • 比较两个存储单元的地址(相对位置) • 除非两个指针指向同一数组,否则这种比较是没有意义的 • 比较两个指向同一数组的指针反映的是指针所指向元素的先后顺序 • 任何指针p与NULL进行“p==NULL”或“p!=NULL”运算均有意义 • “p==NULL”是当指针p为空时成立 • “p!=NULL”的含义是当p不为空时成立 • 例如:有两个指针ptr1和ptr2 • if (ptr1<ptr2) printf(“ptr1 points to lower memory than ptr2\n”);
4.指针与数组 例1: 以下程序的输出结果是: #include<stdio.h> main( ) { int x[ ]={10,20,30,40,50,60}; int *p=x; *(p+4)+=6; printf(“%d,%d”,8,*(p+4)); } A) 10,46 B) 0,56 C) 10,56 D) 50,46 例2: 已知: int a[10]={1,2,3,4,5,6,7,8,9,10}; int *p=a; 则不能表示数组a中元素的表达 式是: A)*p B)a[10] C)*a D)a[p-a]
4.指针与数组 • 指针的运算 • 提示 • 数组名代表数组的首地址 • 固定的,不允许修改的 • 不能对数组名采用 ++/--操作 • 指针的算术运算除了应用于数组外没有什么意义 • 除数组外,不能认为两个数据类型相同的变量在内存中是连续存储的 • 指针的运算与其基类型有关 • 通常情况下允许一个指针或多个指针指向同一个目标 • 常见错误 • 对不指向数组的指针进行算术运算 • 指针的运算结果超出的数组的范围
5.指针与字符串 • 可以通过字符数组和字符型指针处理字符串 • 例如: • 字符数组实现的方式 char ch[ ]={“this is a book!” }; printf (“%s\n” ,ch); • 对字符数组初始化 • ch是字符数组 • 它存放了一个字符串 • 字符指针实现的方式 char *ch=“this is a book!” ; printf (“%s\n” ,ch); • 是对字符指针初始化 • *ch是字符指针 • 它指向的是一个字符串常量的首地址,即指向字符串的首地址
5.指针与字符串 • 可以通过字符数组和字符型指针处理字符串 • 字符指针与字符数组区别 • char *ch字符指针是一个变量 • 指向字符串的第一个字符 • 可以改变字符指针使它指向不同的字符串 • char ch[ ] 是一个字符数组 • 一个足以存放字符串和空字符‘\0’的一维数组 • 可以改变数组中保存的内容 • 数组名 ch是一个不可改变的常量 • C语言规定 • 一个指针类型的变量如果指向对象为字符型 • 可以对其赋值(或初始化)字符串常量 • 此时字符指针指向的就是用来保存字符串的字符数组的首地址