C语言字符串操作
程序占用的内存分区形式
一、预备知识-程序内存分配 一个由c/C 编译程序占用的内存分为以下部分 1、栈区(stack)—由编译器自动分配释放,存储函数的参数值、局部变量值等。其操作模式与
数据结构中的栈。 2、堆区(heap)—一般由程序员分配释放。如果程序员不释放,程序可能会结束OS回收。注意它和数据
结构中的堆是两回事,但分布方式类似链表,呵呵。 3.全局区(静态区)(static)—将全局变量和静态变量的存储放在一起,初始化全局变量和静态变量
变量在一个区域,未初始化的全局变量和未初始化的静态变量在相邻的另一个区域。程序结束后,系统
释放。 4.文本常量区-常量字符串放在这里。程序完成后,由系统释放。 5.程序代码区
text data bss dec hex filename 1033 276 4 1313 521 a.out
- text : 文本大小,即程序代码区
- data:数据段的大小包括静态变量和初始化的全球变量。
- bss:可执行文件中不包含其初始化值的全局变量
这是一位前辈写的,非常详细 //main.cpp int a=0; ///全局初始化区 char *p1; //整体未初始化区 main() {
int b;栈 char s[]="abc"; //栈 char *p2; //栈 char *p3="123456"; 常量区//123456/0,p3在栈上。 static int c=0; ///全局(静态)初始化区 p1 = (char*)malloc(10); p2 = (char*)malloc(20); //分配10和20字节的区域在堆区。 strcpy(p1,"123456"); 在常量区放置//123456/0,编译器可以将其与p3所向"123456"优化成一个地方。 }
二、堆和栈的理论知识 2.1申请方式 stack: 由系统自动分配。例如,声明函数中的局部变量int b;该系统在栈中自动为B开辟空间 heap: 程序员需要自己申请,并在c中指出尺寸malloc函数 如p1=(char*)malloc(10); 在C 中用new运算符 如p2=(char*)malloc(10); 但是注意p1、p2本身就在栈里。 2.2 系统响应后申请 栈:只要栈的剩余空间大于申请空间,系统就会为程序提供内存,否则会提示栈溢出。 堆:首先要知道操作系统有一个链表,记录空闲内存地址,当系统收到程序申请时, 通过链表,找到第一个空间大于申请空间的堆结点,然后从空闲结点链表中删除结点,并将其删除
此外,对于大多数系统来说,结点的空间分配给程序将在这个内存空间的第一个地址记录本次分配的大地址
小,这样,代码中的delete语句可以正确释放本内存空间。此外,由于发现的堆点的大小不一定正确
好等于申请的大小,系统会自动将多余的部分重新放入空闲链表中。 2.3申请大小的限制 栈:在Windows下面,栈是向低地址扩展的数据结构,是一个连续的内存区域。这句话的意思是栈顶的地面
系统提前规定了地址和栈的最大容量WINDOWS下,栈的大小是2M(也有人说是1M,总之是编译
如果申请的空间超过了栈的剩余空间,则提示overflow。因此,从栈中获得的空间
较小。 堆:堆是扩展到高地址的数据结构,是一个不连续的内存区域。这是因为该系统是一个空闲内存区,用链表存储
地址自然是不连续的,链表的遍历方向是从低地址到高地址。堆的大小受计算机系统中有效堆的限制
虚拟内存。由此可见,堆获得的空间更加灵活和大。 2.4申请效率比较: 栈:由系统自动分配,速度快。但程序员无法控制。 堆:是由new分配的内存一般速度慢,容易产生内存碎片,但使用最方便. 另外,在WINDOWS下,最好的方式是用Virtual Alloc分配内存,他不是堆,也不是堆,而是直接进去
程的地址空间中保留一块内存,虽然用起来最不方便。但是速度快,也最灵活。 2.5堆和栈中的存储内容 栈:在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的
地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变
量。。 当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主
函数中的下一条指令,程序由该点继续运行。 堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容由程序员安排。 2.6存取效率的比较 char s1[]=“aaaaaaaaaaaaaaa”; char *s2=“bbbbbbbbbbbbbbbbb”; aaaaaaaaaaa是在运行时刻赋值的; 而bbbbbbbbbbb是在编译时就确定的; 但是,在以后的存取中,在栈上的数组比指针所指向的字符串(例如堆)快。 比如: #include voidmain() { char a=1; char c[]=“1234567890”; char *p=“1234567890”; a = c[1]; a = p[1]; return; } 对应的汇编代码 10:a=c[1]; 004010678A4DF1movcl,byteptr[ebp-0Fh] 0040106A884DFCmovbyteptr[ebp-4],cl 11:a=p[1]; 0040106D8B55ECmovedx,dwordptr[ebp-14h] 004010708A4201moval,byteptr[edx+1] 004010738845FCmovbyteptr[ebp-4],al 第一种在读取时直接就把字符串中的元素读到寄存器cl中,而第二种则要先把指针值读到edx中,在根据
edx读取字符,显然慢了。 2.7小结: 堆和栈的区别可以用如下的比喻来看出: 使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会
切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。 使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。
自我总结: char *c1 = “abc”;实际上先是在文字常量区分配了一块内存放"abc",然后在栈上分配一地址给c1并指向
这块地址,然后改变常量"abc"自然会崩溃
然而char c2[] = “abc”,实际上abc分配内存的地方和上者并不一样,可以从 4199056 2293624 看出,完全是两块地方,推断4199056处于常量区,而2293624处于栈区
2293628 2293624 2293620 这段输出看出三个指针分配的区域为栈区,而且是从高地址到低地址
2293620 4199056 abc 看出编译器将c3优化指向常量区的"abc"
继续思考: 代码:
输出: 2293628 4199056 abc 2293624 2293624 abc 2293620 4012976 gbc 写成注释那样,后面改动就会崩溃 可见strcpy(c3,“abc”);abc是另一块地方分配的,而且可以改变,和上面的参考文档说法有些不一定,
#include using namespace std;
main() { char *c1 = “abc”; char c2[] = “abc”; char c3 = ( char )malloc(3); // *c3 = “abc” //error strcpy(c3,“abc”); c3[0] = ‘g’; printf("%d %d %s/n",&c1,c1,c1); printf("%d %d %s/n",&c2,c2,c2); printf("%d %d %s/n",&c3,c3,c3); getchar(); }
字符串声明与使用
定义一个可变的字符串:
char ch[]={“123456abc”}; char ch2[5]={“123456789”}; //会出现警告提示初值太长,可忽略系统将会自动截取
ch[3]=‘B’;
定义一个字符串常量(不可变):
字符常量默认后面后‘\0’作为结束符
char *ch=“123456abc”;//"123456abc"编译时存放在常量区,是不能被改变的。参考文章
ch[3]=‘B’;//不可用,会出现段错误。
将字符串常量转换成可变字符串可以使用strcpy()函数,将指针变量拷贝到数组中
格式化输入
sprintf:
#include<stdio.h>
#include<string.h>
void main() {
char str[256] = {
0 };
int data = 1024;
//将data转换为字符串
sprintf(str,"%d",data);
//获取data的十六进制
sprintf(str,"0x%X",data);
//获取data的八进制
sprintf(str,"0%o",data);
const char *s1 = "Hello";
const char *s2 = "World";
//连接字符串s1和s2
sprintf(str,"%s %s",s1,s2);
}
sscanf :
sscanf可以支持格式字符%[]:
(1)-: 表示范围,如:%[1-9]表示只读取1-9这几个数字 %[a-z]表示只读取a-z小写字母,类似地 %[A-Z]只读取大写字母
(2)^: 表示不取,如:%[^1]表示读取除'1'以外的所有字符 %[^/]表示除/以外的所有字符
(3),: 范围可以用","相连接 如%[1-9,a-z]表示同时取1-9数字和a-z小写字母
(4)原则:从第一个在指定范围内的数字开始读取,到第一个不在范围内的数字结束%s 可以看成%[] 的一个特例 %[^ ](注意^后面有一个空格!)
注意:当sscanf遇到空格,制表符,换行符时,会停止读取。可以用get来处理更一般的字符串。
//sscanf 的第二个参数,有点像正则表达式,输入的字符串必须匹配第二个字符串参数,然后才能按顺序把字符传递给字符数组。
const char *s = "http://www.baidu.com:1234";
char protocol[32] = {
0 };
char host[128] = {
0 };
char port[8] = {
0 };
sscanf(s,"%[^:]://%[^:]:%[1-9]",protocol,host,port);
printf("protocol: %s\n",protocol);
printf("host: %s\n",host);
printf("port: %s\n",port);
sprintf详解
sprintf(s, “%d”, 123); //产生"123" 可以指定宽度,不足的左边补空格: sprintf(s, “%8d%8d”, 123, 4567); //产生:" 123 4567" 当然也可以左对齐: sprintf(s, “%-8d%8d”, 123, 4567); //产生:“123 4567” 也可以按照16 进制打印: sprintf(s, “%8x”, 4567); //小写16 进制,宽度占8 个位置,右对齐 sprintf(s, “%-8X”, 4568); //大写16 进制,宽度占8 个位置,左对齐
这样,一个整数的16 进制字符串就很容易得到,但我们在打印16 进制内容时,通常想要一 种左边补0 的等宽格式,那该怎么做呢?很简单,在表示宽度的数字前面加个0 就可以了。 sprintf(s, “%08X”, 4567); //产生:“000011D7”
short si = -1; sprintf(s, “%04X”, si); 产生“FFFFFFFF”,怎么回事?因为spritnf 是个变参函数,除了前面两个参数之外,后面的 参数都不是类型安全的,函数更没有办法仅仅通过一个“%X”就能得知当初函数调用前参数压栈 时被压进来的到底是个4 字节的整数还是个2 字节的短整数,所以采取了统一4 字节的处理方式, 导致参数压栈时做了符号扩展,扩展成了32 位的整数-1,打印时4 个位置不够了,就把32 位整数 -1 的8 位16 进制都打印出来了。如果你想看si 的本来面目,那么就应该让编译器做0 扩展而不是 符号扩展(扩展时二进制左边补0 而不是补符号位): sprintf(s, “%04X”, (unsigned short)si);
%o打印8进制,与%x类似,机制与%x一样。
控制浮点数打印格式 浮点数的打印和格式控制是sprintf 的又一大常用功能,浮点数使用格式符”%f”控制,默认保 留小数点后6 位数字,比如: sprintf(s, “%f”, 3.1415926); //产生"3.141593" 但有时我们希望自己控制打印的宽度和小数位数,这时就应该使用:”%m.nf”格式,其中m 表 示打印的宽度,n 表示小数点后的位数。比如: sprintf(s, “%10.3f”, 3.1415626); //产生:" 3.142" sprintf(s, “%-10.3f”, 3.1415626); //产生:"3.142 " sprintf(s, “%.3f”, 3.1415626); //不指定总宽度,产生:“3.142”
**连接字符串**
sprintf 的格式控制串中既然可以插入各种东西,并最终把它们“连成一串”,自然也就能够连
接字符串,从而在许多场合可以替代strcat,但sprintf 能够一次连接多个字符串(自然也可以同时
在它们中间插入别的内容,总之非常灵活)。比如:
char* who = "I";
char* whom = "CSDN";
sprintf(s, "%s love %s.", who, whom); //产生:"I love CSDN. "
strcat 只能连接字符串(一段以’\0’结尾的字符数组或叫做字符缓冲,null-terminated-string),
但有时我们有两段字符缓冲区,他们并不是以’\0’结尾。比如许多从第三方库函数中返回的字符数
组,从硬件或者网络传输中读进来的字符流,它们未必每一段字符序列后面都有个相应的’\0’来结
尾。如果直接连接,不管是sprintf 还是strcat 肯定会导致非法内存操作,而strncat 也至少要求第
一个参数是个null-terminated-string,那该怎么办呢?我们自然会想起前面介绍打印整数和浮点数
时可以指定宽度,字符串也一样的。比如:
char a1[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};
char a2[] = {'H', 'I', 'J', 'K', 'L', 'M', 'N'};
如果:
sprintf(s, "%s%s", a1, a2); //Don't do that!
十有八九要出问题了。是否可以改成:
sprintf(s, "%7s%7s", a1, a2);
也没好到哪儿去,正确的应该是:
sprintf(s, "%.7s%.7s", a1, a2);//产生:"ABCDEFGHIJKLMN"
这可以类比打印浮点数的”%m.nf”,在”%m.ns”中,m 表示占用宽度(字符串长度不足时补空
格,超出了则按照实际宽度打印),n 才表示从相应的字符串中最多取用的字符数。通常在打印字
符串时m 没什么大用,还是点号后面的n 用的多。自然,也可以前后都只取部分字符:
sprintf(s, "%.6s%.5s", a1, a2);//产生:"ABCDEFHIJKL"
在许多时候,我们或许还希望这些格式控制符中用以指定长度信息的数字是动态的,而不是
静态指定的,因为许多时候,程序要到运行时才会清楚到底需要取字符数组中的几个字符,这种
动态的宽度/精度设置功能在sprintf 的实现中也被考虑到了,sprintf 采用”*”来占用一个本来需要一
个指定宽度或精度的常数数字的位置,同样,而实际的宽度或精度就可以和其它被打印的变量一
样被提供出来,于是,上面的例子可以变成:
sprintf(s, "%.*s%.*s", 7, a1, 7, a2);
或者:
sprintf(s, "%.*s%.*s", sizeof(a1), a1, sizeof(a2), a2);
实际上,前面介绍的打印字符、整数、浮点数等都可以动态指定那些常量值,比如:
sprintf(s, "%-*d", 4, 'A'); //产生"65 "
sprintf(s, "%#0*X", 8, 128); //产生"0X000080","#"产生0X
sprintf(s, "%*.*f", 10, 2, 3.1415926); //产生" 3.14"
**打印地址信息**
有时调试程序时,我们可能想查看某些变量或者成员的地址,由于地址或者指针也不过是个32 位的数,你完全可以使用打印无符号整数的”%u”把他们打印出来:
sprintf(s, "%u", &i);
不过通常人们还是喜欢使用16 进制而不是10 进制来显示一个地址:
sprintf(s, "%08X", &i);
然而,这些都是间接的方法,对于地址打印,sprintf 提供了专门的”%p”:
sprintf(s, "%p", &i);
我觉得它实际上就相当于:
sprintf(s, "%0*x", 2 * sizeof(void *), &i);
利用sprintf 的返回值
较少有人注意printf/sprintf函数的返回值,但有时它却是有用的,spritnf 返回了本次函数调用
最终打印到字符缓冲区中的字符数目。也就是说每当一次sprinf 调用结束以后,你无须再调用一次
strlen 便已经知道了结果字符串的长度。如:
int len = sprintf(s, "%d", i);
对于正整数来说,len 便等于整数i 的10 进制位数。
下面的是个完整的例子,产生10 个[0, 100)之间的随机数,并将他们打印到一个字符数组s 中,
以逗号分隔开。
#include
#include
#include
int main() {
srand(time(0));
char s[64];
int offset = 0;
for(int i = 0; i < 10; i++) {
offset += sprintf(s + offset, "%d,", rand() % 100);
}
s[offset - 1] = '\n';//将最后一个逗号换成换行符。
printf(s);
return 0;
}
strftime
sprnitf 还有个不错的表妹:strftime,专门用于格式化时间字符串的,用法跟她表哥很像,也
是一大堆格式控制符,只是毕竟小姑娘家心细,她还要调用者指定缓冲区的最大长度,可能是为
了在出现问题时可以推卸责任吧。这里举个例子:
time_t t = time(0);
//产生"YYYY-MM-DDhh:mm:ss"格式的字符串。
char s[32];
strftime(s, sizeof(s), "%Y-%m-%d %H:%M:%S", localtime(&t));
printf支持的格式:
%c 字符
%d 带符号的整数
%i 带符号的整数
%e 科学计数法,小写e
%E 科学计数法,大学E
%f 浮点数
%g 使用%e或%f中较短的一个
%G 使用%E或%f中较短的一个
%o 八进制
%s 一串字符
%u 无符号整数
%x 无符号十六进制数,用小写字母
%X 无符号十六进制数,用大写字母
%p 一个指针
%n 参数应该是一个指向一个整数的指针,指向的是字符数放置的位置
%% 一个%符号
%ld 带符号的long int
%hd 带符号的short int
字符处理函数
int tolower(char ch)若ch是大写字母(‘A’-‘Z’)返回相应的小写字母(‘a’-‘z’)
int toupper(char ch)若ch是小写字母(‘a’-‘z’)返回相应的大写字母(‘A’-‘Z’)
int _tolower(char ch)返回ch相应的小写字母(‘a’-‘z’)
int _toupper(char ch)返回ch相应的大写字母(‘A’-‘Z’)
int toascii(char c)返回c相应的ASCII
#include<stdio.h>
void main(){
char ch1='j';
printf("%c\n",tolower('H'));//输出:h
printf("%c\n",_toupper('h'));//输出:H
printf("%d\n",toascii('a'));//输出:97
}
测试代码:
#include<stdio.h>
#include<string.h>
#include<time.h>
void main() {
printf("%d\n", 123);
printf("%8d%8d\n", 123,4567);
printf("%-8d%8d\n", 123,4567);
printf("%-8x%8X\n", 123,4567);
printf("%08x%08X\n", 123,4567);
short si = -1;
printf("%04X\n", si);//拓展为32位的-1
printf("%04X\n", (unsigned short)si);//正常打印
printf("%04o\n", si);//拓展为32位的-1
printf("%04o\n", (unsigned short)si);//正常打印
printf("%f\n", 3.1415926);
printf("%10.3f\n", 3.1415626);
printf("%-10.3f\n", 3.1415626);
printf("%.3f\n", 3.1415626);
//打印整形表达的char,digit,Ox的值
// int i;
// for(i = 32; i < 127; i++) {
// printf("[ %c ]: %3d 0x%#04X\n", i, i, i);
// }
char a1[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G'};
char a2[] = {
'H', 'I', 'J', 'K', 'L', 'M', 'N'};
printf("%.7s%.7s\n", a1, a2);
time_t t = time(0);
char s[32];
strftime(s, sizeof(s), "%Y-%m-%d %H:%M:%S", localtime(&t));
printf("%s\n",s);
}
//输出结果
/* 123 123 4567 123 4567 7b 11D7 0000007b000011D7 FFFFFFFF FFFF 37777777777 177777 3.141593 3.142 3.142 3.142 ABCDEFGHIJKLMN 2019-09-19 10:28:47 */
字符判断函数
int isalpha(char ch) 若ch是字母(‘A’-‘Z’,‘a’-‘z’)返回非0值,(返回1024)否则返回0
int isalnum(char ch) 若ch是字母(‘A’-‘Z’,‘a’-‘z’)或数字(‘0’-‘9’),返回非0值,否则返回0
int isascii(char ch) 若ch是字符(ASCII码中的0-127)返回非0值,否则返回0
int iscntrl(char ch) 若ch是作废字符(0x7F)或普通控制字符(0x00-0x1F),返回非0值,否则返回0
int isdigit(char ch) 若ch是数字(‘0’-‘9’)返回非0值,否则返回0
int isgraph(char ch) 若ch是可打印字符(不含空格)(0x21-0x7E)返回非0值,否则返回0
int islower(char ch) 若ch是小写字母(‘a’-‘z’)返回非0值,否则返回0
int isupper(char ch) 若ch是大写字母(‘A’-‘Z’)返回非0值,否则返回0
int isprint(char ch) 若ch是可打印字符(含空格)(0x20-0x7E)返回非0值,否则返回0
int ispunct(char ch) 若ch是标点字符(0x00-0x1F)返回非0值,否则返回0
int isspace(char ch) 若ch是空格(’ ‘),水平制表符(’\t’),回车符(’\r’),走纸换行(’\f’),垂直制表符(’\v’),换行符(’\n’) 返回非0值,否则返回0
int isxdigit(char ch) 若ch是16进制数(‘0’-‘9’,‘A’-‘F’,‘a’-‘f’)返回非0值, 否则返回0
#include<stdio.h>
void main(){
char ch1='j';
printf("%d\n",isalpha(ch1));//输出:1024
printf("%d\n",isalnum(ch1));//输出:8
printf("%d\n",isdigit(ch1));//输出:0:
}
类型转换
头文件:stdlib.h
函数原型:double strtod(const char *nptr,char **endptr);
说明:nptr为原字符串,endptr原字符串转换后抛弃的后面的内容,填写NULL则不返回,原字符串数字前面只能是控制或者加减号。
返回值:正负double值
举个栗子:
#include<stdio.h>
#include<stdlib.h>
void main(){
char *ch1=" -100.65987ffjj";
char *endss;
printf("%lf\n",strtod(ch1,NULL));//输出:-100.659870
printf("%lf\n",strtod(ch1,&endss));//输出:-100.659870
printf("%s\n",endss);//输出:ffjj
}
头文件:stdlib.h
函数原型:long int strtol(const char *str, char **endptr, int base)
返回值:长整型,以base提取,然后再转换为long int 类型
参数:
str – 要转换为长整数的字符串。
endptr – 对类型为 char* 的对象的引用,其值由函数设置为 str 中数值后的下一个字符。
base – 基数,必须介于 2 和 36(包含)之间,或者是特殊值 0(如0x开头的自动设置为十六进制等)。
举个栗子:
#include<stdio.h>
#include<stdlib.h>
void main(){
char *ch1="0101jjx";
char *endss;
printf("%ld\n",strtol(ch1,NULL,2));//输出:5
printf("%ld\n",strtol(ch1,&endss,10));//输出:101
printf("%s\n",endss);//输出:jjx
}
头文件:stdlib.h
原型:int atoi(const char *nptr);
注意:原字符串开头必须是空格或者数字或者加减号
举个栗子:
#include<stdio.h>
#include<stdlib.h>
void main(){
char *ch1=" 11.963xxx";
printf("%d\n",atoi(ch1));//输出:11
}
atof() 字符串转换到 double 符点数,使用方法与stoi相似
atol() 字符串转换到 long 整型,使用方法与stoi相似
字符串处理函数
长度计算:
头文件:string.h
原型:int strlen(const char *str)
返回值:遇到’\0’就返回,返回此之前的字符串长度
举个栗子:
#include<stdio.h>
#include<string.h>
void main(){
char ch[]={
'a','b','\0','c'};
printf("strlen为:%d\n",strlen(ch)); //输出2
}
C/C++中的一个操作符(operator),返回是一个对象或者类型所占的内存字节数
举个栗子:
#include<stdio.h>
void main(){
char ch[]={
'b',0,'c'};
int inx=10;
printf("ch===sizeof:%d\n",sizeof(ch));//输出:3
printf("int===sizeof:%d\n",sizeof(inx));//输出:4
}
头文件:string.h
原型:char *strcpy(char *dest, const char *src);
返回值:将str以’\0’为截止前的字符串替换dest,返回值为dest首地址或者也可以直接访问dest获得最终结果
举个栗子:
#include<string.h>
void main(){
char ch1[100]="123456789";
char *ch2="abc";
printf("%s\n",strcpy(ch1,ch2));//输出abc
printf("%s\n",ch1);//输出:abc
printf("%s\n",ch2);//输出:abc
printf("%c\n",ch1[6]);//输出:7,说明strcpy只是把abc\0复制到了ch1的前4位,printf看到\0就输出了,就不再往后看。
}
头文件:string.h
原型:char *strncpy(char *dest, const char *src, int n)
返回值:将src以’\0’或者n长度为截止前的字符串替换dest,返回值为dest首地址或者也可以直接访问dest获得最终结果
注意:这个n值很重要,如果拷贝到了src最后的‘\0’则如同替换效果了,如果拷贝是n的值小于或者等于strlen(),则会保留dest未使用的内容。
举个栗子:
#include<stdio.h>
#include<string.h>
void main(){
char ch1[100]="123456789";
char *ch2="abc";
printf("%s\n",strncpy(ch1,ch2,strlen(ch2)));//输出:abc456789
printf("%s\n",ch1);//输出:abc456789
printf("%s\n",ch2);//输出:abc
}
头文件:string.h
原型:
int strcmp(const char *s1, const char *s2);
int strncmp(const char *s1, const char *s2,int n);
返回值:若参数s1 和s2 字符串相同则返回0,s1 若大于s2 则返回大于0 的值,s1 若小于s2 则返回小于0 的值。
举个栗子:
#include<stdio.h>
#include<string.h>
void main(){
char *ch1="BCD";
char *ch2="BCd";
printf("%d\n",strcmp(ch1,ch2)); //输出:-32
printf("%d\n",strncmp(ch1,ch2,2));//输出:0
}
忽略字母大小写进行比较,其他类似strcmp()函数
举个栗子
#include<stdio.h>
#include<string.h>
void main(){
char *ch1="abdc";
printf("%d\n",strncasecmp(ch1,"ABC",2));//输出:0
}
追加函数
strcat()与strncat()函数
头文件:string.h
原型:
char *strcat(char *dest, const char *src)
char *strcat(char *dest, const char *src,int n)
返回值:将src以追加的方式添加到dest中,返回值为dest首地址或者也可以直接访问dest获得最终结果
举个栗子:
#include<stdio.h> #include<string.h> void main(){ char ch1[100]="BCD"; char *ch2="123456"; printf("%s\n",strcat(ch1,ch2)