C语言高级编程(第四部分) 字符串 北京大学 信息科学技术学院
数组 的 存储方式
数组 的 存储方式 int shuzu[5]; 数组包含的一组变量 在 内存 中 是 连续存放 的 shuzu[0] shuzu[1]
关于 数组名称 的说明
shuzu shuzu[0] shuzu[1] shuzu[2] shuzu[3] shuzu[4] int main(){ 内存 shuzu[0] shuzu[1] shuzu[2] shuzu[3] shuzu[4] int main(){ int shuzu[5]; if(shuzu == &(shuzu[0])){ printf("True\n"); }else{ printf("False\n"); } return 0; shuzu
数组名称 是 一个地址 数组名称 是 shuzu shuzu[0] shuzu[1] shuzu[2] 该数组所占内存空间的起始地 址,是数组第一个元素的地址。
数组名 与 指针变量 静态数组: 动态数组: 静态数组和动态数组在内存中的本质是一样的,可以用指针变量来代表数组名: 数组名是一个指向该数组所占内存空间的地址。 动态数组: 通过指针变量,指向一块自己申请的内存空间,这块空间也是一个数组。 静态数组和动态数组在内存中的本质是一样的,可以用指针变量来代表数组名: #include <stdio.h> #define N 10 int main(){ int i; int distance[N]; for( i=0; i<N; i++){ scanf(“%d”, &distance[i]); } return 0; #include <stdio.h> #define N 10 int main(){ int i; int distance[N]; int *pint; pint = distance; for( i=0; i<N; i++){ scanf(“%d”, &pint[i]); } return 0;
数组元素 的 赋值 声明后 赋值 声明时 赋值
声明后 赋值 int shuzu[5]; 内存 随机值 shuzu[0] shuzu[1] shuzu[2] shuzu[3]
声明后 赋值 int shuzu[5]; int i; for(i = 0; i < 5; i++){ shuzu[i] = i; } 内存 声明后 赋值 shuzu[0] shuzu[1] shuzu[2] shuzu[3] shuzu[4] 随机值 int shuzu[5]; int i; for(i = 0; i < 5; i++){ shuzu[i] = i; }
声明后 赋值 int shuzu[5]; 1 int i; for(i = 0; i < 5; i++){ 2 内存 声明后 赋值 shuzu[0] shuzu[1] shuzu[2] shuzu[3] shuzu[4] 1 2 3 4 int shuzu[5]; int i; for(i = 0; i < 5; i++){ shuzu[i] = i; }
声明时 赋值 1 2 3 4 int shuzu[5] = {0, 1, 2, 3, 4}; 内存 shuzu[0] shuzu[1] 1 2 3 4 声明时 赋值 int shuzu[5] = {0, 1, 2, 3, 4};
声明时 赋值 1 int shuzu[5] = {0, 1}; 内存 当 数值数目 小于 数组变量数目 时, 剩余的数组变量 被赋值为 0 1 声明时 赋值 int shuzu[5] = {0, 1}; 当 数值数目 小于 数组变量数目 时, 剩余的数组变量 被赋值为 0 这个规律 对float, double, char 类型的数组 也适用!
声明时 赋值 int shuzu[5] = {0, 1}; int shuzu[5] = {0, 1, 0, 0, 0};
字符串
回顾:字符型变量 的 赋值
如何 给一个字符型变量赋予一个特定的值? 基本方法:通过 赋值语句 int main( ){ char b, c, d; b = ‘x’; return 0; } b = ‘x’; c = b; 可以把字符的ASCII编码值 赋给一个字符型变量 d = 120;
编码值为 0 的字符 是什么字符? 字符 x 的编码值是 120 ASCII 编码表
这个字符的 输出效果是什么 一个 特殊 的 字符 编码值为 0 的字符 是什么字符? 答: int main(){ char a; printf("A%cB\n", a); return 0; } 编码值为 0 的字符 是什么字符?
编码值为 0 的字符 int main(){ char a; a = 0; …… return 0; } int main(){
什么是 字符串
什么是 字符串 字符串 是 由 一个或多个 字符 构成 的 序列 you are a student!
在C语言中, 字符串 被实现为 一维字符数组 在C语言中, 字符串 被存储在 一维字符数组 中
在C语言中, 字符串 是 如何 实现/存储 的 在C语言中, 字符串 以 字符‘\0’ 作为结尾
“you are a student!” 如何声明 一个 字符串常量 用 双引号 把 需要表达的字符串 括起来 编译器 负责 在 末尾 添加 一个‘\0’字符
如何声明 一个 字符串变量 第一步: 确定 想要存储的字符串 的 最大长度LEN 第二步: 声明一个 长度为 LEN+1 的 一维字符数组 字符串 以 字符‘\0’ 作为结尾; 需要为 该字符 预留一个存储空间 WHY
字符串变量 一维字符数组
向控制台 输出 字符串 常量
向控制台 输出 字符串常量 printf 函数 方法1: 字符串常量 int main(){ printf(“u r a student”); return 0; }
printf(“you are a stud\0ent”); printf(“\n”); return 0; } int main(){ printf(“you are a stud\0ent”); printf(“\n”); return 0; } 这个程序 的 输出效果 是什么?
向控制台 输出 字符串常量 puts 函数 方法2: int main(){ puts(“u r a student”); return 0; } int main(){ printf(“u r a student\n”); return 0; }
字符串 中 第一个‘\0’字符 之前 的 字符 的 个数 字符串 的 长度 字符串 中 第一个‘\0’字符 之前 的 字符 的 个数 长度为18 “you are a student!” 长度为14 “you are a stud\0ent!”
向控制台 输出 字符串 变量
向控制台 输出 字符串变量 printf 函数 +%s修饰符 方法1: int main(){ char zfc[50]; printf(“%s”, zfc); return 0; }
向控制台 输出 字符串变量 puts 函数 方法2: int main(){ char zfc[50]; … … //赋值 puts(zfc); return 0; } int main(){ char zfc[50]; … … //赋值 printf(“%s\n”, zfc); return 0; }
字符串变量 的 赋值 声明时 赋值 声明后 赋值
声明时赋值 之 烦琐方式 char zfc[LEN] = {‘u’, ‘ ’, ‘r’, ‘ ’, ‘a’, ‘ ’, ‘s’, ‘t’, ‘u’, ‘d’, ‘e’, ‘n’, ‘t’, ‘\0’}; LEN 必须大于 13 请不要使用这种方式! … 1 2 3 4 5 6 7 8 9 10 11 12 13 LEN-1 … u r a s t u d e n t \0 \0
char zfc[LEN] = “u r a student”; 声明时赋值 之 简洁方式 char zfc[LEN] = {‘u’, ‘ ’, ‘r’, ‘ ’, ‘a’, ‘ ’, ‘s’, ‘t’, ‘u’, ‘d’, ‘e’, ‘n’, ‘t’, ‘\0’}; char zfc[LEN] = “u r a student”; char zfc[LEN]; zfc = “u r a student”; u r a s t d e n \0 … 1 2 3 4 5 6 7 8 9 10 11 12 13 LEN-1
声明后赋值 之 从控制台输入 方法1: scanf函数 + %s修饰符 int main(){ char zfc[50]; scanf(“%s”, zfc); printf(“%s\n”, zfc); return 0; } 缺点: 不能接收 包含空格的字符串
声明后赋值 之 从控制台输入 方法2:gets函数 int main(){ char zfc[50]; gets(zfc); printf(“%s\n”, zfc); return 0; }
声明后赋值 之 从控制台输入 方法1: scanf函数 + %s修饰符 方法2:gets函数 请 尽量使用 方法1 除非 字符串中 含有空格
strcpy(目标字符串, 源字符串); 声明后赋值 之 从另一个字符串赋值 方法:“字符串复制”函数 功能:把 源字符串 赋值给 目标字符串 #include <string.h> 注意:调用时,要确保 目标字符串所在数组的长度 大于 源字符串的长度
声明后赋值 之 从另一个字符串赋值 int main(){ char zfc_src[50], zfc_tgt[50]; gets(zfc_src); strcpy(zfc_tgt, zfc_src); printf(“%s\n”, zfc_tgt); return 0; }
char *zfc = “u r a student”; 声明时赋值 之 指针方式 char *zfc = “u r a student”;
字符串 数组 由 字符串变量 构成 的 数组
字符串 数组 字符串变量 一维字符数组 字符串数组 二维字符数组
如何声明 字符串 数组 char zfcsz[N][LEN+1]; 第一步: 确定 数组中存储的字符串 的 最大长度LEN 第二步: 第三步: 声明 一个 行数为N,列数为LEN+1 的 二维字符数组 char zfcsz[N][LEN+1];
如何使用 字符串 数组 int main(){ char zfc_src[50], zfc_tgt[50]; gets(zfc_src); strcpy(zfc_tgt, zfc_src); printf(“%s\n”, zfc_tgt); return 0; } int main(){ char zfc[2][50]; gets(zfc[0]); strcpy(zfc[1], zfc[0]); printf(“%s\n”, zfc[1]); return 0; }
关于 字符串 的 常用函数 strcpy(目标字符串,源字符串) strlen(字符串) strcmp(字符串A,源字符串B) strcat(目标字符串,源字符串) strlwr(字符串) strupr(字符串) 使用这些函数前,需要#include <string.h>
strcpy(目标字符串, 源字符串); “字符串复制”函数 功能:把 源字符串 赋值给 目标字符串 int main(){ char zfc_src[50], zfc_tgt[50]; gets(zfc_src); strcpy(zfc_tgt, zfc_src); printf(“%s\n”, zfc_tgt); return 0; }
int strlen(字符串); “获得字符串长度”函数 int main(){ char zfc[100]; gets(zfc); printf(“%d\n”, strlen(zfc)); return 0; }
int strcmp(字符串A, 字符串B); “字符串比较”函数 int strcmp(字符串A, 字符串B); 功能: 比较 两个字符串 的 大小
int strcmp(字符串A, 字符串B); “字符串比较”函数 int strcmp(字符串A, 字符串B); 当 字符串A 和 字符串B 相等时, 该函数 返回0 对于 字符串A 和 字符串B, 当且仅当 两者的长度相等,且 结尾字符‘\0’前的对应字符均相等 时 称:这两个字符串相等,
int strcmp(字符串A, 字符串B); “字符串比较”函数 int strcmp(字符串A, 字符串B); result == 0 int result = strcmp(“Hello!”, “Hello!”); result != 0 int result = strcmp(“Hello!”, “hello!”); result == 0 int result = strcmp(“Hel\0lo!”, “Hel\0lo”);
int strcmp(字符串A, 字符串B); “字符串比较”函数 int strcmp(字符串A, 字符串B); 当 字符串A 和 字符串B 不相等时, 该函数 返回: 两个字符串中第一对不相等的字符 对应的ACSII码值的差 result == -32 int result = strcmp(“helloH”, “helloh”);
字符 H 的编码值是 72 字符 h 的编码值是 104 72 – 104 == -32
int strcmp(字符串A, 字符串B); “字符串比较”函数 int strcmp(字符串A, 字符串B); 当 字符串A 和 字符串B 不相等时, 该函数 返回: 两个字符串中第一对不相等的字符 对应的ACSII码值的差 result == 32 int result = strcmp(“helloh”, “HelloH”);
int strcmp(字符串A, 字符串B); “字符串比较”函数 int strcmp(字符串A, 字符串B); 字符串比较:对两个字符串从前往后逐个字符相比较(按ASCII码值大小比较),直到出现不同的字符或遇到'\0'为止。如果全部字符都相同,则认为相同;如果出现不相同的字符,则以第一个不相同的字符的比较结果为准。例如: "A"<"B","12"<“123" ,"123"<"2", "there">"that" strcmp函数返回一个整数,其意义: 如果函数返回值为0,则字符串1 和 字符串2 的内容相同 如果函数返回一个正整数,则字符串1 > 字符串2 如果函数返回一个负整数,则字符串1 < 字符串2 strcmp("A", "B") < 0 strcmp("there", "that") > 0 strcmp("abc", "abc") == 0 不能用==比较字符串内容: str1==str2 "abc"=="abc"的值为?
strcat(目标字符串, 源字符串); “字符串连接”函数 功能:把 源字符串 添加到 目标字符串 的结尾 注意:调用时,要确保 目标字符串所在数组的长度 大于 源字符串的长度 +目标字符串的长度
strcat(目标字符串, 源字符串); “字符串连接”函数 int main(){ char zfc_src[50], zfc_tgt[100]; gets(zfc_tgt); gets(zfc_src); strcat(zfc_tgt, zfc_src); printf("%s\n", zfc_tgt); return 0; }
“大写字母变小写”函数 strlwr(字符串); “小写字母变大写”函数 strupr(字符串);
int main(){ char zfc[100]; gets(zfc); strlwr(zfc); printf("%s\n", zfc); strupr(zfc); return 0; } 注意:这两个函数 在编程网格中 不支持!
sprintf(字符数组, 格式控制, 变量列表) 另一个常用的字符串函数: sprintf(字符数组, 格式控制, 变量列表) 与printf()函数的作用相似,但是将输出结果送到字符数组中,形成字符串。 #include <string.h> void main() { char s1[50]; int a=20; double b=3.1416; sprintf(s1,”An int %d and a double %f.”, a, b); printf("%s", s1); } (注意字符数组S1的长度) S1的值为:An int 20 and a double 3.141600.
字符串应用的例子 求字符串中大写字母的个数(使用strlen()) #include <stdio.h> #include <string.h> void main() { char str[256]; int count = 0, len; scanf("%s", str); len = strlen(str); for ( int i = 0; i<len; i++ ) if ( str[i] >= 'A' && str[i] <= 'Z' ) count++; } printf("%s has %d uppercases\n", str, count);
自己实现strlwr()和strupr() 问题:如何将一个字符串中的大写字母变为小写字母,而小写字母则变为大写字母? #include <stdio.h> #include <string.h> void main() { char str[256]; int count = 0, len; scanf("%s", str); len = strlen(str); for ( int i = 0; i<len; i++ ) if ( str[i] >= 'A' && str[i] <= 'Z' ) str[i] = str[i] – ‘A’ + ‘a’; else if ( str[i] >= ‘a' && str[i] <= ‘z' ) str[i] = str[i] – ‘a’ + ‘A’; } printf("%s\n", str); 如果把“else”去掉,结果会怎样? 注意:可以仿照这个方法, 自己实现strlwr()和strupr()
课堂作业 请同学们拿出笔和纸, 1. 写下 姓名和学号; 2. 写下 满足上述要求的程序;