字符串
-
1.概念
- 一组连续的字符
- 必须以\0字符做结尾
- 存放在一组连续的字符类型存储区里
-
2.分类(字符串存储方式不同)
- 字符串字面值
- 一对双引号中间夹杂着一堆字符
- “asjkdh”, 编译器在编译时会自动在最后一个字符后面加 \0, 并且会把这个字符串字面值替换成第一个字符所在存储区的地址,字符串字面值编译完以后其实是一个地址数据
- 字符串字面值内容在程序执行过程中不能修改,所以如果写了两个一样的字符串字面值,他们在程序中其实是同一个(在代码段中)
- “abc”“def”,两个字符串字面值并列写在一起,编译器会把这两个字符串字面值合并成一个 "abcdef’
- 字符数组里的字符串
- 字符数组天然就包含了一组连续字符类型的存储区,天然适合存放字符串(前提是这个数组里包含/0字符,不然字符数组里的内容没法当做字符串来使用
- 字符数组里的字符串内容是可以被修改的
- 字符串字面值
-
3.使用方法
- 不可以使用操作符来处理字符串(比如+)
- C语言专门提供了一组标准函数来处理字符串(需要包含string.h头文件)
-
4.操作字符串函数
- 4.1 strlen
- 获得字符串里有效字符的个数(\0字符前面的字符)
- 参数是一个字符串,返回值就是得到的有效字符串个数
- strlen(”abcdef“)
- 4.1 strlen
#include <stdio.h>
#include <string.h>
int main() {
//声明字符数组并用字符串字面值给字符数组初始化,把字符串字面值里的所有有效数字放进数组里
//编译的时候会在"abc"的末尾加上一个\0字符,初始化的时候也会把\0放到数组里,这样字符数组里的内容才能当做字符串来使用
char str[10] = "abc"; // //str[3]到str[9]的存储区里都放的0
int size = 0;
//字符数组里已经放好的字符串,然后把字符数组当做字符串交给strlen使用
size = strlen(str);
printf("str[3]是%d\n", str[3]);
printf("str[4]是%d\n", str[4]);
printf("str[10]是%d\n", str[9]);
printf("size是%d\n",size);
return 0;
}
/*
output:
str[3]是0
str[4]是0
str[10]是0
size是3
*/
- 4.2 strcat
- 把第一个字符串的内容追加到另外一个字符串的末尾
- 需要两个字符串做参数,第一个字符串必须是字符数组里的字符串(因为字符串字面值内容在程序执行过程中不能修改)
- 把第二个参数里的有效字符追加到第一个参数的末尾
- 返回值就是第一个参数
- strcat(str, “xyz”)
#include <stdio.h>
#include <string.h>
int main() {
char str[10] = "abc";
char *p_ch = NULL;
p_ch = strcat(str, "def");
//%s 占位符比较特殊,可以显示多个连续字符类型存储区内容
//它是从一个地址开始的,一个字符一个字符的显示,直到碰到\0字符的存储区为止
printf("%s\n", p_ch);
printf("%s\n", str);
return 0;
}
/*
output:
abcdef
abcdef
*/
-
4.3 strncat
- 功能和strcat类似
- 多一个整数类型参数表示最多追加的字符个数
- strncat(str, “asdfsd”, 2); //为了避免str存储区不够用的情况,只是把"as"追加上去
-
4.4 strcmp
- 比较两个字符串大小
- 从第一个字符开始一对一对的比较,比较的依据就是ASCII码,ASCII大的字符所在的字符串就大
- 返回值表示比较结果,1表示前一个字符串大,-1表示后一个字符串大,0表示一样大
- strcmp(“abc”, “def”);
-
4.5 strncmp
- 功能和strncmp类似
- 可以只比较前n个字符
- strncmp(“abc”, “abd”, 2);
-
4.6 strcpy
- 可以把一个字符串复制到字符数组里
- 如果后面的字符串的内容超过数组所能容纳的范围,有可能会发生严重的错误
#include <stdio.h>
#include <string.h>
int main() {
char str[10] = "abcdef";
char *p_ch = NULL;
//除了会复制字符串的有效数字以外,还会把字符串后面的\0字符也复制到数组里去
//复制完以后str字符数组的前4位存储区是x, y, z, \0,后面的存储区还留有原来的一些字符
//因为它们处在\0后面,已经不被当做字符串的有效字符看待
p_ch = strcpy(str, "xyz");
printf("%s\n", p_ch);
printf("%s\n", str);
return 0;
}
/*
output:
xyz
xyz
*/
-
4.7 strncpy
- 功能和strcpy类似
- 可以只复制前n个字符
- 有可能不复制"\0"字符
-
4.8 memset
- 用来把一组字符类型存储区的内容设置成同一个字符
- memset(str, ‘x’, 9); //前9个字符类型存储区里的内容都设置成’x’
-
4.9 strstr
- 在一个字符串里查找另外一个字符串内容的位置
- 如果没有就返回NULL
#include <stdio.h>
#include<string.h>
int main() {
char *p_ch = NULL;
//找到第二个字符串的第一个字符d在第一个字符串中存储区的地址并返回
p_ch = strstr("abcdefghigklmn", "def"); //不加(char *)会报错,可能是因为strstr的返回值是 const char *
printf("%s\n", p_ch);
return 0;
}
// output: defghigklmn
- 5.0 下面两个操作字符串的函数不要求包含string.h头文件
- sprintf 可以把多个数字组合成一个字符串记录到字符数组里
- sscanf 可以从字符串里获得多个数字并记录到存储区里
#include <stdio.h>
int main() {
char str[10] = {0};
char ch = 0;
int val = 0;
float fval = 0.0f;
//printf会先把3个数字按照格式要求转换成字符,然后再显示在屏幕上
printf("%c %d %g \n", 'r', 87, 5.4f);
//sprintf 会把3个数字按照格式要求转换成字符,然后把这组字符存在str数组里,成为一个字符串
sprintf(str,"%c %d %g", 'r', 87, 5.4f);
printf("%s \n", str);
//scanf可以从键盘里获得多个数字并记录到存储区里
// scanf("%c%d%g", &ch, &val, &fval);
//sscanf可以从字符串里获得多个数字并记录到存储区里
sscanf("p 34 7.6","%c%d%g", &ch, &val, &fval);
printf("%c %d %g \n",ch, val, fval);
return 0;
}
/*
output:
r 87 5.4
r 87 5.4
p 34 7.6
*/
- 5.1 下面两个字符串相关函数需要包含stdlib.h头文件
- atoi 函数可以把字符串开头部分整数转换成整数类型
- atof 函数可以吧字符串开头部分的浮点数转换成双精度浮点类型
#include <stdio.h>
#include <stdlib.h>
int main() {
int val = atoi("12sdfkasf");
printf("%d\n", val);
double dval = atof("34.23zfsdafasf");
printf("%lg \n", dval);
return 0;
}
/*
output:
12
34.23
*/
- 6.从键盘获得字符串的方法
- scanf 有可能出现严重错误
- 1.会将输入空格符当做’\0’,’\0’后面的并不记录。
- 2.存放输入的字符数组不够大了
- fgets函数也可以从键盘得到字符串并记录到字符数组里,
- 避免了scanf可能出现的问题
- 如果输入内容不能充满数组就把用户最后输入的enter当做’\n’字符放进数组里
- 如果数组放不下用户输入的内容就只获得输入的前一部分内容,把后面的一部分内容留在输入缓冲区里,如果下次再调用fgets函数,得到的将只会是上一次遗留在缓冲区的内容
- 每次使用fgets函数从键盘得到字符串后应该删除输入缓冲区里的多余数据(删除语句应该写在分支里,确定输入缓冲区里存在多余数据的时候才应该进行删除操作,不然删除操作会卡住)
- scanf 有可能出现严重错误
#include <stdio.h>
#include <string.h>
int main() {
char str[10] = {0};
printf("请输入字符串: ");
fgets(str, 10, stdin);
printf("%s \n", str);
//删除输入缓冲区的内容
//用分组来保证输入缓冲区里是有多余数据的
//首先数组要被充满,且最后一个存储区不能是enter对应的\n,不然缓冲区还是可能没数据,程序又会卡主等待用户输入到缓冲区内容,再删缓冲区
//数组充满的情况是:数组里有10个存储区, 有效字符是9个,最后一个放\0
if (strlen(str) == 9 && str[8] != '\n') {
scanf("%*[^\n]");
scanf("%*c");
}
printf("请输入字符串: ");
fgets(str, 10, stdin);
printf("%s \n", str);
return 0;
}
- 7.字符指针数组
- 在c语言中记录多个相关字符串*
#include <stdio.h>
// #include <string.h>
int main() {
//char * : 字符指针类型
//声明一个字符指针数组, 第一个指针指向"abc"这个字符...
//编译器在编译的时候会把"abc"替换成字符'a'所在存储区的地址
char *str[] = {"abc", "def", "ghi"};
int num = 0;
for(num = 0; num <= 2; num++) {
printf("%s\n", str[num]);
}
return 0;
}
/*
output:
abc
def
ghi
*/
-
- 主函数的第二个参数就是一个字符指针数组
#include <stdio.h>
// #include <string.h>
//主函数的第一个参数是一个整数,第二个参数是一个字符指针数组。
int main(int argc, char *argv[]) {
int num = 0;
for (num = 0; num <= argc -1; num ++) {
printf("%s\n", argv[num]);
}
return 0;
}
/*
intput:
./a.out abc def ghi
output:
abc
def
ghi
*/