第九章-字符串
简介
- 在第七章-数组与第八章-指针中都简单的讲了字符串
- 本章将着重讲解C语言的字符串
- 在各种编程语言中,字符串的地位都十分重要,C语言中并没有提供“字符串”这个特定类型,而是以特殊字符数组的形式来存储和处理字符串,这种字符数组必须以空字符’\0’结尾,因此,也将这种特定字符数组称为C风格字符串
- 本节讨论字符串和字符串的一些处理函数。 C风格字符串是字符数组的一种特例,这个“特”字体现在“以’\0’(空字符,null character)结尾”,如何声明创建一个C风格字符串,如何使用C风格字符串,这是本节要解决的问题
字符数组
- 字符数组的定义
- 形式为:
char 数组名[ 常量表达式 ];
- 如:
char a[100];
- 定义了一个字符数组,名字叫c;
- a数组的数据类型是char
- [100] 表示a中存储有100个字符元素;
- 这100个字符元素的名字分别是:[0],a[1],a[2], …… ,a[99]
- 形式为:
- 字符数组的初始化
-
字符数组的常见初始化形式如下例:
char c[5]={ ‘a’,’b’,’c’,’d’,’e’ };
- 如果初始化时初值个数大于数组长度,会报错。
- 如果初始化时初值个数小于数组长度,系统会为剩余元素自动赋值为’\0’ 。
- C语言允许用字符串常量来初始化字符数组:
char c[100] ={"C Program"};
- 上面的例子也可以写成:
char c[100] ="C Program";
- 两种初始化的区别:
-
字符串就是字符数组,字符数组不一定是字符串
//字符串就是结尾带\0的字符数组,只是展示方式不同 // "jack" == {'j','a','c','k','\0'}
-
字符串的一个初始化
void test2() { // 都是字符串 char name[8] = "it"; char name2[8] = {'i', 't', '\0'}; // \0的ASCII码值是0(相当于\0) char name3[8] = {'i', 't', 0}; //元素不够,直接补零(相当于\0) char name4[8] = {'i', 't'}; // 不算是一个字符串(只能说是一个字符数组) char name5[] = {'i', 't'}; }
-
-
- 字符数组的输入输出
- 字符指针变量与字符数组
char *cp;
与char str[20];
-
str由若干元素组成,每个元素放一个字符;而cp中存放字符串首地址
char str[20]; str=“I love China!”; //错误 char *cp; cp=“I love China!”; //正确
- str是地址常量;cp是地址变量
-
cp接受键入字符串时,必须先开辟存储空间
//正确 char str[10]; scanf(“%s”,str); //错误 char *cp; scanf(“%s”, cp); //修改为 char *cp,str[10]; cp=str; scanf(“%s”,cp);
-
字符指针输出字符
void main( ) { char *string=“I love China!”; printf(“%s\n”,string); string+=7; while(*string) { putchar(string[0]); string++; } }
- 字符指针变量与字符数组
- 字符串与字符数组的关系
- 字符串用一维字符数组存放
- 字符数组具有一维数组的所有特点
- 数组名是指向数组首地址的地址常量
- 数组元素的引用方法可用指针法和下标法
- 数组名作函数参数是地址传递等
- 区别
- 存储格式:字符串结束标志
- 赋值方式与初始化
- 输入输出方式:%s %c
(char *a char a[])小结
用字符数组和字符指针变量都能实现字符串的存储和运算,但它们二者之间是有区别的,不应混为一谈,主要有以下几点
- 字符数组由若干个元素组成,每个元素中放一个字符,而字符指针变量中存放的是地址(字符串第1个字符的地址),决不是将字符串放到字符指针变量中。
-
赋值方式。可以对字符指针变量赋值,但不能对数组名赋值。
char *a; a=”I love China!”; // 对 char str[14];str[0]=’I’; // 对 char str[14]; str=”I love China!”; //错
-
初始化的含义
char *a=”I love China!”; 与 char *a; a=”I love China!”;等价 char str[14]= ”I love China!”;与 char str[14]; str[]=”I love China!”; 不等价
- 存储单元的内容
-
编译时为字符数组分配若干存储单元,以存放各元素的值,而对字符指针变量,只分配一个存储单元存储地址
char *a; scanf(“%s”,a); // 错 char *a,str[10]; a=str; scanf (“%s”,a); //对
-
-
指针变量的值是可以改变的,而数组名代表一个固定的值(数组首元素的地址),不能改变。
int main() { char *a="I love China!";//不能改为char a[]=“I love China!”; //只有变量才能加,如果为a[],那么a就是常量了 a=a+7; printf(“%s\n”,a); return 0;}
-
字符数组中各元素的值是可以改变的,但字符指针变量指向的字符串常量中的内容是不可以被取代的。
char a[]=”House”,*b=” House”; a[2]=’r’; 对 *(b+3) = 'x'; //错误,因为” House”在常量区是不能被修改的
- 引用数组元数
- 对字符数组可以用下标法和地址法引用数组元素
(a[5],*(a+5))
。如果字符指针变量p=a,则也可以用指针变量带下标的形式和地址法引用(p[5],*(p+5))。 char *a=″I love China!″;
- 则a[5]的值是第6个字符,即字母’e’
- 对字符数组可以用下标法和地址法引用数组元素
-
用指针变量指向一个格式字符串,可以用它代替printf函数中的格式字符串。
char *format; format=”a=%d,b=%f\n”; printf(format,a,b); 相当于printf(“a=%d,b=%f\n”,a,b);
字符串的操作:
-
字符串的初始
char a[100] = "I Love China"; char b[] = "I Love China"; char *c = "I Love China"; char d[6] = { 'c', 'h', 'i', 'n', 'a', '\0' }; printf("%s\n", a); printf("%s\n", b); printf("%s\n", c); printf("%s\n", d);
- 相关输入输出函数处理字符串
-
scanf和printf
char ch[100]; scanf(“%s”,ch);/*空格、制表符、换行为分隔符*/ printf(“%s”,ch);/*输出后不会自动换行*/
-
gets和puts
char ch[100]; gets(ch);/*回车为分隔符*/ puts(ch); /*输出后会自动换行*/
-
-
字符串复制函数strcpy
#include <stdio.h> #include <string.h> void main(void) /*主函数*/ { char str1[256]={'\0'}; /*开辟一字符数组str1*/ char str2[256]={'\0'}; /*开辟一字符数组str2*/ printf ("请输入第1个字符串: \n"); /*提示用户输入第1个字符串*/ gets (str1); /*使用gets函数读取一行输入*/ strcpy(str2,str1); /*将第1个字符串复制给第2个字符串*/ printf("第2个字符串为:\n%s",str2); /*输出第2个字符串*/ getchar(); /*等待,按任意键继续*/ }
- 字符串的拼接
- sprintf函数:把格式化的数据写入某个字符串缓冲区。
- 形式:
int sprintf( char *buffer, const char *format, [ argument] … );
- buffer:char型指针,指向将要写入的字符串的缓冲区。
- format:格式化字符串。
- [argument]…:可选参数,可以是任何类型的数据。
- 返回值:字符串长度(strlen)
-
代码示例:
//字符串拼接 void test3(){ //调用window系统的cmd命令连续打开5个计算器 //char a[100] = "for /l %i in (1,1,5) do calc"; //system(a); //格式化一个字符串把他打印出来 //printf("for /l %%i in (1,1,%d) do %s", 5, "calc"); //printf:是往屏幕里面输出 //sprintf:是往字符串里面输出 char a[100] = { 0 }; int num = 0; char op[30] = { 0 }; //通过屏幕输入 scanf("%d%s", &num, op); //拼接新的字符串,此时的a已经是新的字符串了 sprintf(a, "for /l %%i in (1,1,%d) do %s", num, op); //调用新的字符串 system(a); }
- 字符串的分离:
- 形式
int sscanf( string str, string fmt, mixed var1, mixed var2 ... );
- sscanf与scanf类似,都是用于输入的,只是后者以键盘(stdin)为输入源,前者以固定字符串为输入源。
-
代码举例:
//字符串分离 void test4(){ //scanf 是屏幕输入 //sscanf 是字符串输入 //提取出1000,要输入的字符串 char a[100] = "我有1000元"; //要分离出的数据 int num; //字符串输入分离 sscanf(a, "我有%d元", &num); //打印为1000 printf("%d", num); }
- 形式
- 字符串的查找
- 函数:strstr()
- strstr() 函数搜索一个字符串在另一个字符串中的第一次出现。
- 找到所搜索的字符串,则该函数返回第一次匹配的字符串的地址;如果未找到所搜索的字符串,则返回NULL。
- 函数名: strstr
- 函数原型:extern char *strstr(const char *str1, const char *str2);
- 语法:* strstr(str1,str2)
- str1: 被查找目标 string expression to search.
- str2: 要查找对象 The string expression to find.
- 返回值:若str2是str1的子串,则先确定str2在str1的第一次出现的位置,并返回此位置到str1末尾的所有字符;如果str2不是str1的子串,则返回NULL。(注:若想返回str2在str1第一次出现的位置,不是这个函数)
-
代码举例:
int main(){ char str[100] = "my name is cheng"; char str2[20] = "chen"; char *p = strstr(str, str2); if (p == NULL){ printf("没有找到"); } else { printf("找到"); } getchar(); return 0; }
- 字符串的比较
- strcmp函数:
- C/C++函数,比较两个字符串。设这两个字符串为str1,str2,若str1==str2,则返回零;若str1>str2,则返回正数;若str1<str2,则返回负数。
- 原型:
extern int strcmp(const char *s1,const char * s2);
- 所在头文件:
string.h
- 功能:比较字符串s1和s2。
- 一般形式:strcmp(字符串1,字符串2)
- 说明:
- 当s1<s2时,返回为负数
- 当s1=s2时,返回值= 0
- 当s1>s2时,返回正数
- 即:两个字符串自左向右逐个字符相比(按ASCII值大小相比较),直到出现不同的字符或遇’\0’为止。如:
A"<"B" "a">"A" "computer">"compare"
- 特别注意:
strcmp(const char *s1,const char * s2)
这里面只能比较字符串,不能比较数字等其他形式的参数。
- 字符串前n字母比较函数
- 函数名:strncmp
- 功能:比较字符串的前N个字节
- 用法:比较字符串str1和str2的大小,如果str1小于str2,返回值就<0,如果相等就=0;len指的是str与str2比较的字符数。
- 比较2个字符串的前7个字节:
strncmp(str1,str2,7);
- 字符串处理函数strchr
- 功能: 查找字符串str中首次出现字符c的位置
- 说明:返回首次出现c的位置指针,如果str中不存在c,则返回NULL;
char *p = strchr(str,'c');
- 字符串连接函数strcat
- 字符串连接函数的原型为:
char* strcat(字符串1,字符串2);
- 所在头文件:
string.h
- 功能:
- 把字符串2的前n个字符添加到字符串1结尾处(覆盖字符1结尾处的\0),并添加\0。
- 说明:字符串1、字符串2所指向内存区域不能重叠,字符串1必须有足够的空间,来容纳字符串2
- 返回指向字符串1.
- 示例:
strcat("333", "ddd", 2);
- 字符串连接函数的原型为:
- 字符串处理函数atoi
- 函数名:atoi
- 功能:将字符串转换成整形数
-
示例
char a[18] = "e8848"; int num = atoi(a); //转化的时候,传递字符串的地址,地址不要求是首地址, //字符串的任何地址都可以,num起到接受赋值作用, //转化成功就是整数,失败就是0,出现非数字字符就会转化失败
- strset
- 函数名:strset
- 功能:将一个串中的所有字符都设为指定字符
-
示例:
char str[20] = "eee888"; _strset(str,‘8’); //str就全部是:”888888“
- strrev
- 功能:串倒转
-
示例
char *str = strrev("123"); //"321"
- 字符大小写转换函数
- 函数名:strlwr
- 功能:大小写转换
-
程序例:
//大写转小写 char *str = strlwr("ABC");
- Strupr字符串全部转大写
- 在某些场合,要求输入一个字符串,如果是大小写无关的,问题就来了,比如,在大小写无关意义下,“AB”、“ab”、“aB”、“Ab”都是等价的,这仅仅是两个字母的情况,如果字母更多,情况更复杂,在程序中去一一判断也很不现实,为此,C标准库提供了字符串处理函数strupr,用于将字符串中所有的字母都转换成大写形式,其原型为;
char* strupr(字符串);
- 常用内存函数
- memset
- 在头文件memory.h中 头文件memory.h为内存操作函数头文件
- 第一个参数是内存的首地址,第二个参数是要设置的字符,第三个参数是正数,从首地址开始设置多少个字节为第二个参数
- 多用于清空字符串,用法 memset(str,’\0’,strlen(str));
-
示例:
//内存替换 char str[100] = "falksjaldjladsjfjkl"; memset(str, 'A', 10); printf("%s\n", str);
- memcpy
- memcpy 是字符串覆盖函数,在头文件memory.h中
- memcpy 的三个参数 第一个参数是被覆盖的字符串,第二个参数是覆盖到的字符串,第三个参数是覆盖的字符串的位数
-
下面代码为 从字符串str1中复制5位字符覆盖掉str的前5位。
char str[100] = "falksjaldjladsjfjkl"; char str1[100] = "11111111"; memcpy(str, str1, 5); printf("%s\n", str);
- memset