字符串是一种重要的数据类型,但是C语言并没有显式的字符串数据类型,因此字符串以字符串常量的形式出现或存储于字符数组中。字符串常量很适用于那些程序不会对它们进行修改的字符串。所有其他字符串都必须存储于字符数组或动态分配的内存中。本次主要描述处理字符串和字符的库函数。
字符串就是一串零个或多个字符,并且以一个位模式为全0的NUL字节结尾。因此,字符串所包含的字符内部不能出现NUL字节。
字符、字符串处理需要引入string.h这个头文件
#include <string.h>
1.字符串长度
API: strlen
原型:size_t strlen(char const *string)
返回值:string字符串的长度,不包括结束符\0
作用:strlen返回一个类型为sizt_t的值,属于一个无符号整数类型。即为传入字符串的长度
用法:1
2
3const char buf[20] = "hello";
int i = strlen(buf);
printf("i = %d\n",i);
这里i打印值为5,即为字符串hello的长度,不包含结束符。
尝试模仿strlen的写法:1
2
3
4
5
6
7
8
9size_t my_strlen(const char* string)
{
size_t length = 0;
while(*string++ != '\0')
{
length += 1;
}
return length;
}
2.复制字符串
1)不受长度限制
API:strcpy
原型:char strcpy(char dst,char const *src)
返回值:返回指向dst字符串的指针
作用:这个函数把参数src字符串复制到dst参数。如果参数src和dst在内存中出现重叠,其结果是未定义的。dst必须是一个字符数组或者是一个指向动态分配内存的数组的指针。
src赋值给dst,dst以前的内容将会被覆盖丢失.如果src的长度超过了dst数组的长度,执行时会crash
用法:1
2
3
4char buf[30] = "hello world";
strcpy(buf,"message");
printf("%s\n",buf);
输出内容为 message
模仿strcpy的写法:1
2
3
4
5
6
7
8
9
10
11
12
13char * my_strcpy(char *dst, const char * src)
{
char *ret = dst;
if((dst == NULL) || (src == NULL))
{
return NULL;
}
while(*src != '\0')
{
*dst++ = *src++;
}
return dst;
}
2)长度受限制
API:strncpy
原型:char strncpy(char dst, char const *src, size_t len);
返回值:返回指向dst字符串的指针
作用:把src字符串的字符复制到dst数组中。它总是正好向dst写入len个字符。如果strlen(src)的值小于len,dst数组会用额外的NUL字节填充到len长度。如果strlne(src)的值大于或等于len,那么只有len 个字符被复制到dst中。
用法:1
2
3
4
5char buf[30] = "hello world";
strncpy(buf,"A message",5);
printf("%s\n",buf); //输出A mes world,长度为5,其余的不拷贝
strncpy(buf,"A message",20);
printf("%s\n",buf); //输出A message
模仿strncpy的写法:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18char * my_strncpy(char *dst, const char * src ,int len)
{
char *ret = dst;
size_t i;
if((dst == NULL) || (src == NULL))
{
return NULL;
}
for (i = 0; i < len && src[i] != '\0'; i++)
{
dst[i] = src[i];
}
for (; i < len; i++)
{
dst[i] = '\0';
}
return dst;
}
3.连接字符串
1)不受长度限制
API: strcat
原型:char strcat(char dst, const char *src);
返回:返回指向dst字符串的指针
作用:把src的字符串添加(连接)到dst字符串后面。这里要求dst原先已经包含了一个字符串(可以为空字符串)。它找到这个字符串的末尾。并把src字符串的一份拷贝添加到这个位置。如果src和dst的位置发生重叠,其结果是未定义的。
用法:1
2
3char buf[20] = “hello”;
strcat(buf,”world”);
printf(“%s\n”,buf); //输出helloworld
模仿strcat的写法:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18char * my_stcat(char *dst, const char * src)
{
char *ret = dst;
if((dst == NULL) || (src == NULL))
{
return NULL;
}
while(*dst != '\0')
{
dst++;
}
while(*src != '\0')
{
*dst++ = *src++;
}
*dst = '\0';
return dst;
}
2)长度受限制
API: strncat
原型:char strncat(char dst, const char *src,size_t len);
返回值:指向dst的指针
作用:从src中复制长度为len个字符到dst中
用法:1
2
3
4
5char buf[20] = “hello”;
strncat(buf,”world”,2);
printf(“%s\n”,buf); //输出hellowo
strncat(buf,”world”,10);
printf(“%s\n”,buf); //输出helloworld,超过部分遇到\0结束符,不再进行连接
模拟strncat:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19char * my_stncat(char *dst, const char * src,size_t len)
{
char *ret = dst;
size_t i;
if((dst == NULL) || (src == NULL))
{
return NULL;
}
while(*dst != '\0')
{
dst++;
}
while(len && (*dst++ = *src++) != '\0')
{
len--;
}
*dst = '\0';
return dst;
}
4.字符串比较
1)不受长度限制
API: strcmp
原型:int strcmp(const char s1, const char s2)
返回值:0表示两个字符串相同,其余表示两个字符串不同
作用:对两个字符串s1\s2逐个字符进行比较,直到发现不匹配为止
用法:1
2
3
4
5
6char buf[20] = "hello";
int ret = 0;
ret = strcmp(buf,"hello”);
printf("%d\n",ret);//输出0,两个字符串相同
ret = strcmp(buf,”hello world");
printf("%d\n",ret);//输出-32,两个字符串不同
模仿strcmp:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15size_t my_strcmp(const char *s1, const char * s2)
{
size_t ret = -1;
if ((s1 == NULL) || (s2 == NULL))
{
return ret;
}
while(!(ret = *(unsigned char*)s1 - *(unsigned char *)s2) && *s2)
{
++s1;
++s2;
}
return ret;
}
2)长度受限制
API: strncmp
原型:int strcmp(const char s1, const char s2,size_t len)
返回值:0表示两个字符串相同,其余表示两个字符串不同
作用:对两个字符串s1\s2逐个字符进行比较,直到发现不匹配为止
用法:1
2
3
4
5
6
7char buf[20] = "hello";
int ret = 0;
ret = strncmp(buf,"hello",2);
printf("%d\n",ret); //输出0,表示hello中前两个字符he跟hello中前两个相同
ret = strncmp(buf,"hello world",8);
printf("%d\n",ret); //输出-32,表示不相等,即hello world前8个字符,与hello不相等
模仿strncmp:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19size_t my_strncmp(const char *s1, const char * s2,size_t len)
{
size_t ret = -1;
if ((s1 == NULL) || (s2 == NULL))
{
return ret;
}
while(!(ret = *(unsigned char*)s1 - *(unsigned char *)s2) && *s2)
{
if (len <=0)
{
break;
}
++s1;
++s2;
len--;
}
return ret;
}
5.字符串查找
原型:char strstr(char s1, char s2)
返回值:NULL,或者指向查找到的起始位置的指针
作用:这个函数在s1中查找整个s2第一次出现的起始位置,并返回一个指向该位置的指针。如果s2并没有完整地出现在s1的任何地方,函数将返回一个NULL指针,如果s2是一个空字符串,函数就返回是
用法:1
2
3
4
5
6char buf[20] = "hello";
char *last = NULL;
last = strstr(buf,"he”);
printf("%s\n",last); //打印hello
last = strstr(buf,"hello world");
printf("%s\n",last); //打印null
模拟strstr写法:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29char* my_strstr(char *s1, char * s2)
{
if (*s1 == '\0')
{
if(*s2)
{
return NULL;
}
return s1;
}
while(*s1 != '\0')
{
int i =0;
while(1)
{
if(s2[i] == '\0')
{
return s1;
}
if (s2[i] != s1[i])
{
break;
}
i++;
}
s1++;
}
return NULL;
}
6.内存操作:
主要有memcpy、memmove、memcmp、memchr、memset几个函数
原型:
void memcpy(void dst,void const src,size_t length);
void memmove(void dst,void const src,size_t length);
void memcmp(void const s1,void const s2,size_t length);
void memchr(void s1,void const s2,size_t length);
void memset(void dst,int ch,size_t length);
用法:
memcpy
从src的起始位置赋值length个字节到dst的内存起始位置,可以复制任何类型。如果src和dst出现重叠,其结果是未知的1
2
3
4
5char dst[20];
char src[20] = "hello";
memcpy(dst,src,strlen(src));
printf("%d\n",strlen(src));
printf("%s\n",dst );
模拟memcpy:1
2
3
4
5
6
7
8
9
10
11
12
13
14char *my_memcpy(char *dst, char * src,size_t len)
{
char *ret = dst;
if((dst == NULL) && (src == NULL))
{
return NULL;
}
while(len-- >0)
{
*dst++ = *src++;
}
return ret;
}
memmove:
memmove用于从src拷贝count个字符到dest,如果目标区域和源区域有重叠的话,memmove能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中。但复制后src内容会被更改。但是当目标区域与源区域没有重叠则和memcpy函数功能相同。
用法:
char s[]=”Golden Global View”;
memmove(s,s+7,strlen(s)+1-7);
printf(“%s”,s);
程序输出结果:Global View
*注意:这里的拷贝长度strlen(s)+1-7表示把字符串结尾的’\0’也拷贝进来。
memcmp
memcmp是比较内存区域buf1和buf2的前count个字节。该函数是按字节比较的。
返回值:
当s1
如:char s1=”abc”;
char s2=”acd”;
int r=memcmp(s1,s2,3);
就是比较s1和s2的前3个字节,第一个字节相等,第二个字节比较中大小已经确定,不必继续比较第三字节了。所以r=-1
memchr:
从buf所指内存区域的前count个字节查找字符ch。1
2
3
4
5
6
7
8char *s="Hello, Programmers!";
void *p;//因为memchr(,,);return void*p;
p=memchr(s,'P',strlen(s));
//p=(char *)memchr(s,'P',sizeof(s)); //s是一个指向char的指针,而任何指针都是个一个4字节的数,在这里应//该是要说明搜索整个字符串的长度,所以应该用strlen(s)
if(p)
printf("%s",p);
else
printf("Not Found!");
memst
将s所指向的某一块内存中的前n个 字节的内容全部设置为ch指定的ASCII值
通常用来进行内存初始化作用
例如:
char dst[20];
memset(dst,0x0,sizeof(dst)); //把dst指向的大小为20的内存区域值都设置为0.