前言
C语言中对字符和字符串的处理很是麻烦,但是C语言本身是没有字符串类型的,字符串通常放在常量字符串中或者字符数组中。
C库中提供了多个处理字符串的函数,ANSI C把这些函数的原型放在 string.h 头文件中,其中最常用的函数有以下几种。
一、函数介绍
1.求字符串长度
1.1 strlen
size_t strlen ( const char * str );
字符串已将'\0'作为结束标志,strlen函数返回的是在字符串中'\0'前面出现的字符个数(不包含'\0')。
参数指向的字符串必须要以'\0'结束。
注意函数的返回值为size_t,是无符号的
学会strlen函数的模拟实现
2.长度不受限制的字符串函数
2.1 strcpy
char* strcpy(char * destination, const char * source );
将源指向的 C 字符串复制到目标指向的数组中,包括'\0'。
源字符串必须以'\0'结束。
也会将源字符串中的'\0'拷贝到目标空间。
目标空间必须足够大,以确保能存放源字符串。
目标空间必须可变。
学会模拟实现
2.2 strcat
char * strcat ( char * destination, const char * source );
将源字符串的内容追加到目标字符串。目标字符串中的'\0'会被源字符串中的第一个字符覆盖,并且'\0'包含在由目标字符串中两者的串联形成的新字符串的末尾。
源字符串必须以'\0'结束。
目标空间必须有足够的大,能容纳下源字符串的内容。
目标空间必须可修改。
2.3 strcmp
int strcmp ( const char * str1, const char * str2 );
此函数开始比较每个字符串的第一个字符。如果它们彼此相等,则继续比较下一对,直到字符不同或到达'\0'为止。
第一个字符串大于第二个字符串,则返回大于0的数字。
第一个字符串等于第二个字符串,则返回0。
第一个字符串小于第二个字符串,则返回小于0的数字
3.长度受限制的字符串函数介绍
3.1 strncpy
char * strncpy ( char * destination, const char * source, size_t num );
将源字符串的前num个字符复制到目标字符串中。如果在复制num个字符之前找到源字符串的末尾(由'\0'表示),则目标字符串将用零填充,直到总共写入num个字符。
拷贝num个字符从源字符串到目标空间。
如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。
3.2 strncat
char * strncat ( char * destination, const char * source, size_t num );
将源字符串的前 num 个字符追加到目标字符串中,外加一个'\0'字符。
如果源字符串中字符串的长度小于 num,则仅复制终止 null 字符之前的内容。
3.3 strncmp
int strncmp ( const char * str1, const char * str2, size_t num );
比较到出现另个字符不一样或者一个字符串结束或者num个字符全部比较完。
4.字符串查找
4.1 strstr
char * strstr ( const char *str1, const char * str2);
返回指向 str1 中第一次出现的 str2 的指针,如果 str2 不是 str1 的一部分,则返回一个 null 指针。
匹配过程不包括终止 null 字符,但它会停止到此为止。
4.2 strtok
char * strtok ( char * str, const char * sep );
sep参数是个字符串,定义了用作分隔符的字符集合
第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
strtok函数找到str中的下一个标记,并将其用'\0'结尾,返回一个指向这个标记的指针。(注:trtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
如果字符串中不存在更多的标记,则返回 NULL 指针。
5.错误信息报告
5.1 strerror
char * strerror ( int errnum );
返回错误码,所对应的错误信息。
函数
|
如果他的参数符合下列条件就返回真
|
iscntrl
|
任何控制字符
|
isspace
|
空白字符:空格
‘ ’
,换页
‘\f’
,换行
'\n'
,回车
‘\r’
,制表符
'\t'
或者垂直制表符
'\v'
|
isdigit
|
十进制数字
0~9
|
isxdigit
|
十六进制数字,包括所有十进制数字,小写字母
a~f
,大写字母
A~F
|
islower
|
小写字母
a~z
|
isupper
|
大写字母
A~Z
|
isalpha
|
字母
a~z
或
A~Z
|
isalnum
|
字母或者数字,
a~z,A~Z,0~9
|
ispunct
|
标点符号,任何不属于数字或者字母的图形字符(可打印)
|
isgraph
|
任何图形字符
|
isprint
|
任何可打印字符,包括图形字符和空白字符
|
6.字符操作
字符转换:
int tolower ( int c );
int toupper ( int c );
#include <stdio.h>
#include <ctype.h>
int main ()
{
int i=0;
char str[]="Test String.\n";
char c;
while (str[i])
{
c=str[i];
if (isupper(c))
c=tolower(c);
putchar (c);
i++;
}
return 0;
7.内存操作函数
7.1 memcpy
void * memcpy ( void * destination, const void * source, size_t num );
函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
这个函数在遇到'\0'的时候并不会停下来。
如果source和destination有任何的重叠,复制的结果都是未定义的。
7.2 memmove
void * memmove ( void * destination, const void * source, size_t num );
和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
如果源空间和目标空间出现重叠,就得使用memmove函数处理。
7.3 memcmp
int memcmp ( const void * ptr1,
const void * ptr2,
size_t num );
二、库函数的模拟实现
1.模拟实现strlen
有以下三种方法
//递归模拟实现strlen
#include <assert.h>
int my_strlen(const char* str)
{
assert(str);
int count = 0;
while (*str != '\0')
{
count++;
str++;
}
return count;
}
//指针减去指针模拟实现strlen
int my_strlen(const char* str)
{
assert(str);
char* ps = str;
while (*ps != '\0')
{
ps++;
}
return(ps - str);
}
//计数器方法
int my_strlen(const char * str)
{
int count = 0;
while(*str)
{
count++;
str++;
}
return count;
}
2.模拟实现strcpy
//模拟实现strcpy
char my_strcpy(char* arr1, const char* arr2)
{
assert(arr1 && arr2);
char* ps = arr1;
while (*arr1++ = *arr2++)
{
;
}
return ps;
}
int main()
{
char arr1[] = { "xxxxxxxxxx" };
char arr2[] = { "abc def" };
my_strcpy(arr1, arr2);
printf("%s", arr1);
return 0;
}
3.模拟实现strcat
//模拟实现strcat
char* my_strcat(char* str1, const char* str2)
{
assert(str1 && str2);
char* ps = str1;
while (*str1)
{
str1++;
}
while (*str1++ = *str2++)
{
;
}
return ps;
}
int main()
{
char arr1[20] = { "hello " };
char arr2[] = { "world" };
my_strcat(arr1, arr2);
printf("%s", arr1);
return 0;
}
4.模拟实现strstr
//模拟实现strstr
char* my_strstr(const char* str1, const char* str2)
{
assert(str1 && str2);
char* cp = str1;
char* s2 = str2;
char* s1 = cp;
while (*cp)
{
s1 = cp;
s2 = str2;
while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2)
{
s1++;
s2++;
}
if (*s2 == '\0')
{
return cp;
}
cp++;
}
return NULL;
}
int main()
{
char arr1[] = "abcccdef";
char arr2[] = "ccde";
char* ret = my_strstr(arr1, arr2);
if (ret != NULL)
{
printf("%s\n",ret);
}
else
printf("找不到\n");
return 0;
}
5.模拟实现strcmp
//模拟实现strcmp
int my_strcmp(const char* str1, const char* str2)
{
assert(str1 && str2);
while (*str1 == *str2)
{
if (*str1 == '\0')
return 0;
str1++;
str2++;
}
return (*str1 - *str2);
}
int main()
{
int sz = my_strcmp("aaab", "aaac");
printf("%d", sz);
return 0;
}
6.模拟实现memcpy
//模拟实现memcpy
void* my_memcpy(void* dest, const void* src, size_t num)
{
char* tmp = dest;
while (num--)
{
*((char*)dest) = *((char*)src);
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return tmp;
}
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[] = { 2,3,4,5,6,7 };
my_memcpy(arr1, arr2, 20);
for (int i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
7.模拟实现memmove
//模拟实现memmove
void* my_memmove(void* dest, const void* src, size_t num)
{
char* tmp = dest;
if (dest < src)
{
//从前向后拷贝
while(num--)
{
*((char*)dest) = *((char*)src);
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
else
{
//从后向前拷贝
while (num--)
{
*((char*)dest + num) = *((char*)src + num);
}
}
return tmp;
}
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
my_memmove(arr1 + 2, arr1, 20);
for (int i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
结尾
字符串是C语言中最有用、最重要的数据类型之一。虽然我们一直在使用字符串,但是要学的大小还很多。C库提供大量的函数用于读写字符串、拷贝字符串、比较字符串、合并字符串、查找字符串等。通过本次的学习,将进一步提高自己的编程水平。