### 字符串 C语言里规定文字信息必须记录在一组连续的字符存储区里。 所有文字信息必须以'\0'字符做结尾,这个字符就是ASCII码的0。 符合以上两种特征的内容叫字符串,C语言里用字符串记录文字信息。 字符串里'\0'字符前面的字符叫有效字符。 所有的字符串都可以采用一个字符指针来表示。 字符串字面值是一种字符串,用两个双信号中间的一组字符表示,例如: "dsg", "!@%Q#"等。 编译器在编译的时候会自动在字符串字面值的末尾增加一个'\0'字符。 /* 字符串演示 */ #include <stdio.h> int main(){ printf("%p\n", "abc"); printf("%c\n", *"abc"); printf("%c\n", *("abc" + 3)); return 0; } 字符串字面值的内容,在程序执行过程中是不可改变的。 程序里内容一样的字符串字面值其实是同一个。 /* 字符串演示 */ #include <stdio.h> int main(){ printf("%p\n", "abc"); printf("%p\n", "abc"); return 0; } 多个并列的字符串字面值会被合并成一个。 /* 字符串演示 */ #include <stdio.h> int main(){ printf("%p\n", "abc"); printf("%p\n", "ab""c"); return 0; } ### 字符数组 字符数组也可以用来记录字符串。 并不是所有的字符数组都可以当字符串使用,只有包含'\0'字符的字符数组才可以当字符串使用。 可以使用字符串字面值对字符数组进行初始化,这个时候编译器会吧字符串字面值里的'\0'字符初始化到字符数组里。 #include <stdio.h> int main(){ char str[] = "abcxyz"; printf("sizeof = %ld\n", sizeof(str)); return 0; } 字符数组里的字符串内容可以修改。 可以在printf函数调用语句里使用%s作为占位符把字符串里的有效字符显示出来。 #include <stdio.h> int main(){ char str[] = "abcxyz"; printf("%s\n", str); return 0; } ### 字符串的标准函数 不可以在程序里使用操作符来操作字符串,而应该使用一组标准函数。 为了使用这些标准函数,需要包含string.h头文件。 **strlen** 这个函数用来统计字符串里有效字符个数。 #include <stdio.h> #include <string.h> int main(){ char str[10] = "abcdef"; printf("%ld\n", strlen(str)); return 0; } 这个函数和sizeof完全没有关系。 **strcat** 用来合并两个字符串的,但是这种方式不可控,有可能会修改不属于数组的存储区,造成严重的后果 实例: /* strcat 演示 */ #include <stdio.h> #include <string.h> int main(){ char str[10] = "abc"; strcat(str, "xyz"); // 将第二个参数合并到第一个参数 printf("str = %s\n", str); return 0; } 结果: lanyulei@lanyulei-c:$ ./a.out str = abcxyz **strncat** 这个函数和strcat类似,但是它是可以修改不属于数组的存储区 实例: /* strncat 演示 */ #include <stdio.h> #include <string.h> int main(){ char str[10] = "abc"; strncat(str, "asdfrgasfg", 3); // 将第二个参数的前三位合并到一个参数的字符数组中 printf("str = %s\n", str); return 0; } 结果: lanyulei@lanyulei-c:$ ./a.out str = abcxyz **strcmp** 用来比较两个字符串的大小,返回值是1表示前一个字符串大,返回值是-1表示后一个字符串大,返回值是0表示一样大,这个函数的比较是字符串穿从左到右每个字符在ASCII中代表的数字的大小 实例: /* strcmp 演示 */ #include <stdio.h> #include <string.h> int main(){ printf("比较的结果是:%d\n", strcmp("aqwe", "arwe")); return 0; } 结果: lanyulei@lanyulei-c:$ ./a.out 比较的结果是:-1 **strncmp** 和strncmp类似,但是这个函数只比较两个字符串的前n个字符 实例: /* strcmp 演示 */ #include <stdio.h> #include <string.h> int main(){ printf("比较的结果是:%d\n", strcmp("aqwe", "arwe", 2)); return 0; } 结果: lanyulei@lanyulei-c:$ ./a.out 比较的结果是:-1 **strcpy** 用来把一个字符串复制到一个字符串数组里,这个函数有可能修改不属于数组的存储区,造成严重的错误 实例: /* strcpy 演示 */ #include <stdio.h> #include <string.h> int main(){ char str[10] = "abcdef"; strcpy(str, "xyz"); printf("str = %s\n", str); return 0; } 结果: lanyulei@lanyulei-c:$ ./a.out str = xyz **strncpy** 功能和strcpy类似,但是可以限制复制的字符的个数,可以保证不会修改不属于数组的存储区 实例: /* strcpy 演示 */ #include <stdio.h> #include <string.h> int main(){ char str[10] = "abcdef"; strcpy(str, "xyz", 2); printf("str = %s\n", str); return 0; } 结果: lanyulei@lanyulei-c:$ ./a.out str = xycdef **memset** 可以把字符数组里多个存储区的内容设置成同一字符 实例: /* memset 演示 */ #include <stdio.h> #include <string.h> int main(){ char str[10] = "abc"; memset(str, 'z', 5); // str字符数组中的前五个字符全部设置成z printf("str = %s\n", str); return 0; } 结果: lanyulei@lanyulei-c:$ ./a.out str = zzzzz **strstr** 用来在一个大字符串里查找小字符串的位置,如果找不到返回值是NULL 实例: /* strstr 演示 */ #include <stdio.h> #include <string.h> int main(){ printf("找到的字符为:%s\n", strstr("asdfdfg", "dfg")); return 0; } 结果: lanyulei@lanyulei-c:$ ./a.out 找到的字符为:dfg **sprintf** 按照格式把多个数字转成一组字符并记录到字符数组里形成字符串 实例: /* sprintf 演示 */ #include <stdio.h> int main(){ char str[20] = {0}; sprintf(str, "%c %d %g", 'a', 5, 2.1f); printf("str = %s\n", str); return 0; } 结果: lanyulei@lanyulei-c:$ ./a.out str = a 5 2.1 **sscanf** 按照格式从字符串里获得数字并记录到存储区里 实例: /* sscanf 练习 */ #include <stdio.h> int main(){ char ch = 0; int num = 0; float fnum = 0.0f; sscanf("p 18 165.5", "%c%d%g", &ch, &num, &fnum); printf("%c %d %g\n", ch, num, fnum); return 0; } 结果: lanyulei@lanyulei-c:$ ./a.out p 18 165.5 **atoi** 可以把字符串中整数转成整数类型,仅能或转换字符串前面连贯的数字 实例: /* 字符串演示 */ #include <stdio.h> #include <stdlib.h> int main(){ int num = atoi("34asdfasd3"); printf("num = %d\n", num); return 0; } 结果: lanyulei@lanyulei-c:$ ./a.out num = 34 **atof** 可以字符串里的浮点数转换成双精度浮点类型 实例: /* atof演示 */ #include <stdio.h> #include <stdlib.h> int main(){ double dnum = 0.0; dnum = atof("23.867asderg"); printf("dnum = %lg\n", dnum); return 0; } 结果: lanyulei@lanyulei-c:$ ./a.out dnum = 23.867 **fgets** 在scanf函数调用语句里使用%s作为占位符可以把用户在键盘输入的字符串记录到键盘里,使用这种办法会产生严重错误,修改不属于字符数组的存储区 fgets函数也可以从键盘得到一个字符串并记录到字符数组中,这个函数可以避免scanf函数的问题 函数参数: 1. 数组名称 2. 数组里的存储区 3. 用stdin表示键盘 如果输入的内容不能充满数组,就会把用户最后输入的换行字符也读入到数组里 若果输入的内容超过数组能容纳的范围就把多余的部分留给下次读,也就是阶段 实例: #include <stdio.h> #include <string.h> int main(){ char str[10] = {0}; printf("请输入一个字符串:"); fgets(str, 10, stdin); // 清理缓冲区里的数据 if (strlen(str) == 9 && str[8] != '\n'){ scanf("%*[^\n]"); scanf("%*c"); } printf("%s\n", str); return 0; } 结果: lanyulei@lanyulei-c:$ ./a.out 请输入一个字符串:asdfasgasgrawsrgasdf asdfasgas 在使用fgets函数从键盘得到字符串以后必须清理输入缓冲区里可能存在的多余数据。 清理语句应该放在分支里,分支需要保证输入缓冲区里存在多余数据。 if (strlen(str) == 9 && str[8] != '\n'){ scanf("%*[^\n]"); scanf("%*c"); }