第五次课大纲

一、回顾6.3节字符数组中字符串的概念:

  1、字符串的定义和初始化

  在C语言中,没有字符串这个数据类型,字符串是以字符数组的形式存在的,并且字符串的末尾会有结束符‘\0’标志字符串的结束。所以定义以及初始化字符串时,可以使用下列方式:

char str[]={"hello world"};
char str[]="hello world";

  问题:按照上图方式定义字符数组str,那么str的长度为?

  答案是12,注意不要忽略末尾的结束符,验证方法:sizeof()输出长度

  2、字符串的输入与输出

  字符数组的输入输出有两种方式:一种是使用%c格式符输入或输出一个字符,另一种是使用%s格式符一次输入与输出整个字符串。

  问题:回忆并使用两种方式编程输出上图中str字符数组。

  答案:答案不唯一,只要输出字符串即可,下面代码只是其中的三种方法,结果会输出三次hello world。

 1 #include <stdio.h>
 2
 3 int main(int argc, char const *argv[]){
 4     int i;
 5     char a[]="hello world";
 6     printf("sizeof a=%lu\n",sizeof(a));
 7
 8     i=0;
 9     while(a[i]!=‘\0‘){
10         printf("%c",a[i]);
11         i++;
12     }
13         printf("\n");
14     for(i=0;i<sizeof(a);i++){
15         printf("%c",a[i]);
16     }
17
18     printf("\na[]=%s\n",a);
19
20     return 0;
21 }

二、字符串和指针

  1、字符串的指针形式定义

  通过数组和指针的学习,我们知道数组可通过指针进行访问(读写),且指针和数组具有天然的联系,可以以指针的形式去访问或者遍历一个数组,也可以以数组的形式去访问指针所代表的那一大片连续的地址空间。数组和指针有着这种联系,字符串在内存里的表达形式是数组,那么定义或访问字符串时可以使用指针也可以使用数组。因此字符串的定义可以使用下述两种方式:

 char *str = "hello";            //指针形式
 char str[] = "hello";           //数组形式 

  上述两种方式均可使用格式符%s和格式符%c输出字符串str的内容。

  问题:使用指针形式定义字符串,且使用%s和%c输出字符串str。

  答案:答案有多种形式,下面的代码可供参考,编译运行后输出两次hello wolrd。另外思考:在下述代码中若使用%c输出,再使用%s输出,也就是将printf ("%s\n",str);  放在第10行,结果是否不变?如果变化为什么?(这个思考题其实属于指针和数组内容)

 1 #include <stdio.h>
 2
 3 int main(void){
 4     char *str="hello world";
 5
 6     printf ("%s\n",str);
 7
 8     while ((*str)!=‘\0‘)
 9         printf ("%c",*str++);
10
11     return 0;
12 }

  若将printf ("%s\n",str)放在第10行再次编译时,只能输出一次hello,world。为什么哪?因为在使用格式符%c输出字符串时,str指针执行了++运算,那么当输出字符串后,str指向了最后一个字符”\0“,可通过%p输出str的值验证,具体代码如下:

 1 #include <stdio.h>
 2
 3 int main(void){
 4     char *str="hello world";
 5
 6     printf ("%p\n",str);
 7
 8     while ((*str)!=‘\0‘)
 9         printf ("%c",*str++);
10
11     printf ("\n%p\n",str);
12     printf ("%s\n",str);
13     return 0;
14 }

  2、数组形式和指针形式定义字符串的区别

  既然可以使用指针形式定义字符串,并且和数组形式定义字符串形式一样可使用格式符%s和%c输出字符串,那么两种定义方式是完全等价的吗?并不是,两种形式的不同体现在给字符串赋值时,如下述代码:

1 #include <stdio.h>
2
3 int main(void){
4     char *s={"hello,world"};
5     s[0]=‘B‘;
6
7     printf("here!s[0]=%c\n",s[0]);
8 }

  上述代码使用指针形式定义字符串,编译运行时会出现错误,但是当将*s改为s[]时,也就是使用数组形式定义字符串,编译运行没有错误,正常输出结果如下:

here!s[0]=B

--------------------------------
Process exited after 0.0329 seconds with return value 0
请按任意键继续. . .

  所以指针形式定义的字符串是不可修改的,若定义一个可修改的字符串则需要使用数组的形式定义字符串。那么为什么哪?为什么字符指针的形式不可修改,而数组的形式可修改。

  3、指针形式定义的字符串为什么不可修改

  为什么指针形式定义字符串,字符串不可修改,我们通过下面的这段代码来分析原因:

 1 #include <stdio.h>
 2
 3 int main(void){
 4     int i;
 5     char *s = "hello,world";
 6     //s[0]=‘B‘;
 7     char *s2 = "hello,world";
 8     printf("&i=%p\n",&i);
 9     printf("&s=%p\n",&s);
10     printf("&s2=%p\n",&s2);
11
12     printf("s =%p\n",s);
13     printf("s2=%p\n",s2);
14     printf("s[0]=%c\n",s[0]);
15 }

  新建一个整数变量i、字符串s2,给s和s2同样的初值,输出变量i、s和s2的地址:编译可能还是会有警告,先不管警告,运行后发现结果如下:

&i=000000000062FE4C
&s=000000000062FE40
&s2=000000000062FE38
s =0000000000404000
s2=0000000000404000
s[0]=h

--------------------------------
Process exited after 0.01247 seconds with return value 0
请按任意键继续. . .

  从结果可以看出,作为变量i、s、s2地址是相邻的,且先定义的变量的地址大,后定义的变量的地址小。而s和s2的结果是一样的,s和&s结果不一致,变量i、s、s2地址是一个很大的数,而s和s2的值比较小,主要是因为“hello,world”在程序的代码段,地址一般比较小且所在区域一般不允许修改,如果程序修改该区域,那么操作系统会有个保护机制,会让你的代码运行错误,说你在做坏事不让你写,如果该操作系统允许你写,那么这个操作系统不够安全。

  写好程序编译的时候,编译器会对编译时就已经有值(hello,world)的东西,将该值放在一个只读不能写的位置(也就是代码区),然后让你的指针指向这个值的位置,如果有两个指针的值都是这个值,那么就需要将两个指针都指向这个值的位置,也就因为允许多个指针指向这个位置,所以才不允许修改。实际上,s是一个指针,初始化为指向一个字符串常量,由于这个常量在只读不可写的位置,所以实际上s是const char *s,但是由于历史的原因,编译器接收不带const的写法,或者是省略const的写法,但是试图对这个字符串常量做写入会导致严重的后果。

  4、数组形式定义的字符串为什么可修改

  数组形式定义的字符串为什么可修改?在上述代码的基础上再添加数组形式定义字符串s3:

 1 #include <stdio.h>
 2
 3 int main(void){
 4     int i;
 5     char *s = "hello,world";
 6     char *s2 = "hello,world";
 7     char s3[] = "hello,world";
 8     printf("&i=%p\n",&i);
 9     printf("&s=%p\n",&s);
10     printf("&s2=%p\n",&s2);
11     printf("&s3=%p\n",&s3);
12     printf("s3=%p\n",s3);
13
14     printf("s =%p\n",s);
15     printf("s2=%p\n",s2);
16
17     s3[0]=‘B‘;
18     printf("s3[0]=%c\n",s3[0]);
19 }

  编译运行结果如下,发现&s3和s3是同一个位置,和i、s、s2都在同一个位置:

&i=000000000062FE4C

&s=000000000062FE40

&s2=000000000062FE38

&s3=000000000062FE20

s3=000000000062FE20

s =0000000000404000

s2=0000000000404000

s3[0]=B

--------------------------------

Process exited after 0.03045 seconds with return value 0

请按任意键继续. . .

  使用数组形式定义字符串,那么字符串就在当前位置,也就是字符串不会在地址比较小的代码区,而是就在定义当前变量的位置。所以数组形式定义的字符串是可修改的。

  综上所述:当程序需要一个字符串的时候,那么我们是将字符串写成数组的形式还是指针的形式呢?如果是作为数组,那么表示这个字符串就在这里,作为本地变量空间自动被释放。而如果作为指针,那么这个字符串不知道在哪里,所以通常我们使用指针定义字符串完成下列事情:

  1)如果需要一个只读不写的字符串;

  2)如果该字符串需要作为函数参数时,在学指针和数组时我们知道,将数组作为函数参数时,传递到函数内的就是指针;

  3)如果需要动态分配空间,那就只能使用指针了。

  所以,选择指针和数组的基本原则:如果要构造一个字符串,使用数组形式定义字符串,如果要处理一个字符串,使用指针形式定义字符串。

三、字符指针作为函数参数

  字符串存在形式是字符数组,而在上一节说过数组作为函数参数时,传递到函数内部的就是指针,那么练习分别使用字符指针和字符数组的形式传递两个字符串from和to,并且将字符串to的内容复制为字符串from的内容,在赋值的时候可选用指针(*运算符)和数组形式([]运算符)完成。详见课本P259,8.4.2 字符指针作函数参数。

时间: 2024-10-07 10:08:00

第五次课大纲的相关文章

七月算法--12月机器学习在线班-第五次课笔记—回归

七月算法--12月机器学习在线班-第五次课笔记—回归 七月算法(julyedu.com)12月机器学习在线班学习笔记 http://www.julyedu.com

centos lamp/lnmp阶段复习 第二十五节课

centos  lamp/lnmp阶段复习   第二十五节课 上半节课 下半节课 f

centos mysql 优化 第五节课

centos mysql  优化  第五节课 f

centos mysql 优化 第十五节课

centos mysql  优化  第十五节课 f

七月算法-12月机器学习在线班--第十五次课笔记—主题模型

七月算法-12月机器学习--第十五次课笔记—主题模型 七月算法(julyedu.com)12月机器学习在线班学习笔记http://www.julyedu.com 复习的知识: 1.,Γ函数 是阶乘在实数上的推广,即实数的阶乘 2,Beta分布 Beta分布的概率密度: 其中系数B为: 两者的关系 1,朴素贝叶斯分析 朴素贝叶斯没有分析语意,无法解决语料中一词多义和多词一义的问题,更像是词法的分析,可以 一, 1个词可能被映射到多个主题中——一词多义 二,多个词可能被映射到某个主题的概率很高——多

centos NFS/FTP服务配置 第二十五节课

centos  NFS/FTP服务配置   第二十五节课 上半节课 下半节课 f

一周第五次课(12月15日)

一周第五次课(12月15日)2.1/2.2 系统目录结构2.3 ls命令2.4 文件类型2.5 alias命令 系统目录结构: [[email protected] ~]# lsanaconda-ks.cfg[[email protected] ~]# ls /bin dev home lib64 mnt proc run srv tmp varboot etc lib media opt root sbin sys usr[[email protected] ~]# ls /root//.ss

二周第五次课(12月22日)

二周第五次课(12月22日)2.23/find命令2.24/find命令2.25/ find命令2.26 文件名后缀 其他搜索文件命令: · which搜索文件是从环境变量PATH里找的 · whereis在事先准备好的库里搜索 ·  locate需要安装mlocate包,之后使用updatedb命令生成一下文件列表路径数据库,然后才能搜索. 快捷键: ctrl + l清屏 crtl + d 退出终端 ctrl + c 终止运行或暂停 crtl +u 删除光标前面所有的 crtl + e光标挪到

三周第五次课(12月29日) 4.5/4.6 磁盘格式化 4.7/4.8 磁盘挂载 4.9 手动增加swap空间

三周第五次课(12月29日)4.5/4.6 磁盘格式化4.7/4.8 磁盘挂载4.9 手动增加swap空间 [[email protected] ~]# [[email protected] ~]# mke2fs命令文件系统管理mke2fs命令被用于创建磁盘分区上的"etc2/etc3"文件系统. 语法:mke2fs(选项)(参数) 选项:-b<区块大小>:指定区块大小,单位为字节:-c:检查是否有损坏的区块:-f<不连续区段大小>:指定不连续区段的大小,单位为