c语言字符串
1.字符串:以0结尾的一串字符
0和'\0'是一样的,但是和'0'不一样,0用来标志字符串的结束,不是字符串的一部分,计算字符串的长度的时候,不包括这个0,字符串以数组的形式存在,以数组或指针的方式访问
char[]={'H','e','l','l','o','w'}; //是字符数组,不是字符串
char[]={'H','e','l','l','o','w','\0'}; //是字符数组,是字符串
字符串声明的方式:
char *str="Hello";
char a[]="Hello";
char line[10]="Hello";
char[]={'H','e','l','l','o','w','\0'};
2.字符串常量:
类似于“Hello”这种用双引号包围的字符序列
编译器会将字符串常量变成一个字符数组存放在某处
不能使用运算符对字符串进行操作,因为他的本质是一个字符数组
3.可修改和不可修改字符串
char *str="Hello" //不可修改,在这里“Hello”作为一个字符串常量,会被存放在代码段,代码段的内容只可以读,不可写,如果使用str[0]='B'来修改字符串,将会报错
char str[]="Hello" //这是一个字符串数组,存放在堆栈区,跟一般的变量一样,因此可以修改。编译器在编译这行代码的时候,仍然会把“Hello”存放在代码段,但是执行这一句的时候,会把代码段的"Hello"拷贝到堆栈区
4.什么时候用char str[]和char *str
字符数组的时候使用str[]
函数参数的时候可以使用*str,这个时候未必指向代码段的字符串地址,可能是堆栈区的字符串地址。malloc动态分配内存的时候用*str.
5.字符串的输入输出
char *s="title"
char *t=s //这时t指向了和s同样的在代码段的字符串的地址,并没有赋值成一个新的字符串
scanf("%s",string) //向字符数组string里面输入字符串,遇到空格、table、换行的时候停止读入,假如后续再读一个字符串,这个空格、tab、换行也不会被读入下一个字符串。假如string的长度为8,而读入了超过7个字符还没有碰到空格、tab或者换行,程序可能报错。
scanf("%7s",string) //string最多读入7个字符,不足7个就遇到空格、tab、换行时直接结束
printf("%s",string) //输出字符串
常见错误:
char *string;
printf("%s",string); //string 没有初始化,可能会出错
6.空字符串
char s[100]=""; //长度为100的空字符串 ,s[0]是‘\0’
char s[]=""; //长度为1的空字符串 ,s[0]是‘\0’
7.字符串数组
char a[][10]={"hello","world"} //连续的20个char长度的地址,注意数组的第二维必须声明长度,否则编译报错
char *a[] //一个字符串指针数组,每一个元素都是一个指向字符串的指针
8.getchar()和putchar()
int getchar() 从键盘读入一个字符,返回一个int类型,假如读入到末尾,返回的是预定义值EOF(-1).
int putchar(int a) //接受一个字符的ASCII码,将这个字符输入到命令行。
9.string.h库文件
string.h提供了很多处理字符串的函数
-strlen 返回 字符串的长度,不包含'\0',sizeof返回的长度包含'\0'
int strlen(const char* s){ int idx=0; while(s[idx]!='\0') idx++; return idx; }
-strcmp 比较字符串
int strcmp(const char* s1,const char* s2){ while(*s1==*s2&&*s1!='\0'){ s1++; s2++; } return *s1-*s2; }
-strcpy 字符串复制
char *strcpy(char *dst,const char *src){ int idx=0; while(src[idx]){ dst[idx]=[src[idx]]; idx++; } dst[idx]='\0'; return dst; }
-strcat 字符串拼接
以上3个函数都不安全,可能存在越界的风险,从函数的实现可以看出这些字符串的处理是直到遇到‘\0’才结束的,因此有越界风险。
解决方法:使用以下安全函数:(注意第一个参数是目的,第二个参数是源)
char * strncpy(char *restrict dst,const char *restrict src,size_n t) 将src字符数组中前n个字符复制到dst中。//resitrct关键字表示两个变量不指向同一个数据(也不能重叠(例如Hello,dst指向H的地址,src指向l的地址就是重叠))。
char * strncat(char *restrict dst,const char *restrict src,size_n t) 将src字符数组中前n个字符复制到dst中。
char * strncmp(char *dst,const char *src,size_n t) 只比较src和dst中的前n个字符
-strchr(const char*s,int c) 从s字符数组中从左往右找c,找到之后返回字符c对应的地址
-strrchr(const char*s,int c) 从s字符数组中从右往左找c,找到之后返回字符c对应的地址
-strstr(const char *s1,const char *s2) 从s1中找字符串s2,返回找到之后的首地址
-strcasestr(const char *s1,const char *s2) 从s1中找字符串s2,返回找到之后的首地址,不区分大小写地找