第三章 字符函数和字符串函数
本章将着重介绍处理字符和字符串的库函数的使用和一些注意事项。
- 求字符串长度
strlen
- 长度不受限制的字符串函数
strcpy
strcat
strcmp
- 长度受到限制的字符串函数
strncpy
strncat
strncmp
- 字符串的查找
strstr
strtok
- 错误信息报告
strerror
-
字符操作
-
内存操作函数
memcpy
memmove
memset
memcmp
1 字符串函数介绍
1.1 strlen
size_t strlen (const char* str);
-
字符串是以‘\0’作为结束标志,strlen返回的值是字符串中’\0‘前的字符个数,不包含’\0‘。
-
参数指向的字符串必要要以’\0’为标志结束。
-
函数的返回值为size_t(无符号整型,相当于unsigned int)。
注意:
#include <stdio.h>
#include <string.h>
int main()
{
const char* s1 = "abcdef";
const char* s2 = "abcdqsea";
if (strlen(s1) - strlen(s2) < 0)
{
printf("s1 < s2\n");
}
else
{
printf("s1 > s2\n");
}
return 0;
}
以上代码最后打印的结果为:s1 > s2。
库函数中的strlen返回值类型是无符号整型,这边相减得到负数,但最后会变成一个很大的值。
1.1.1 strlen的使用
#include <stdio.h>
#include <string.h>
int main()
{
char arr[20] = "hello world!";
int len = strlen(arr);
printf("%d\n", len); //12
return 0;
}
1.1.2 strlen的模拟实现
#include <stdio.h>
#include <assert.h>
unsigned int my_strlen(const char* str)
{
assert(*str != NULL);
int count = 0;
while (*str != '\0')
{
count++;
str++;
}
return count;
}
int main()
{
char arr[20] = "hello world!";
printf("%d\n", my_strlen(arr)); //12
return 0;
}
1.2 strcpy
char* strcpy(char * destination, char * source);
-
源字符串必要要以’\0’结束。
-
源字符串中的’\0’将会被拷贝到目标空间。
-
目标空间必须要足够大,确保能够存放的下源字符串。
-
目标空间必须是可变的。
1.2.1 strcpy的使用
#include <stdio.h>
#include <string.h>
int main()
{
char s1[10] = "hello";
char s2[10] = "world";
strcpy(s1, s2);
printf("%s\n", s1);
return 0;
}
1.2.2 strcpy的模拟实现
#include <stdio.h>
char* my_strcpy(char* dest,const char* src)
{
char* ret = dest;
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char s1[10] = "hello";
char s2[10] = "word";
my_strcpy(s1, s2);
printf("%s\n", my_strcpy(s1, s2));
return 0;
}
1.3 strcat
char * strcat(char * destination, char * source);
-
源字符串必要要以’\0’结束。
-
目标空间必须要足够大,确保能容纳下源字符串的内容。
-
目标空间必须可修改。
-
字符串不能自己给自己追加。
1.3.1 strcat的使用
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[20] = "hello ";
char arr2[] = "world";
strcat(arr1, arr2);
printf("%s\n",arr1);
return 0;
}
1.3.2 strcat的模拟实现
#include <stdio.h>
#include <assert.h>
char* my_strcat(char* dest, const char* src)
{
char* ret = dest;
assert(dest && src);
while (*dest)
{
dest++;
}
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char arr1[20] = "hello ";
char arr2[] = "world";
printf("%s\n", my_strcat(arr1, arr2));
return 0;
}
1.4 strcmp
int strcmp (const char* str1, const char* str2);
标准规定:
-
第一个字符串大于第二个字符串的时候,返回大于0的数字。
-
第一个字符串等于第二个字符串的时候,返回0。
-
第一个字符串小于第二个字符串的时候,返回小于0的数字。
1.4.1 strcmp的使用
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[] = "abcd";
char arr2[] = "abdq";
int ret = strcmp(arr1, arr2);
printf("%d\n", ret);
return 0;
}
1.4.2 strcmp的模拟实现
#include <stdio.h>
#include <assert.h>
int my_strcmp(const char* str1, const char* str2)
{
assert(str1 && str2);
while (*str1 == *str2)
{
str1++;
str2++;
}
if (*str1 < *str2)
{
return -1;
}
else
{
return 1;
}
}
int main()
{
char arr1[] = "abcd";
char arr2[] = "abdq";
printf("%d\n", my_strcmp(arr1, arr2));
return 0;
}
1.5 strncpy
char* strncpy (char* destination, const char* source, size_t num);
-
在源字符串中拷贝num个字符串到目标空间。
-
源字符串的长度如果小于num,那么就会在源字符串后面去追加0,直到长度达到num个。
1.5.1 strncpy的使用
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[] = "hello ";
char arr2[] = "wor";
strncpy(arr1, arr2, 2);
printf("%s\n",arr1);
return 0;
}
1.5.2 strncpy的模拟实现
#include <stdio.h>
char* my_strncpy(char* dest,const char* src, size_t num)
{
char* ret = dest;
int i = 0;
for (i = 0; i < num; i++)
{
*dest++ = *src++;
}
return ret;
}
int main()
{
char arr1[] = "hello ";
char arr2[] = "wor";
printf("%s\n", my_strncpy(arr1, arr2, 3));
return 0;
}
1.6 strncat
char* strncat (char* destination, const char* source, size_t num);
1.6.1 strncat的使用
#include <stdio.h>
#include <string.h>
int main()
{
char s1[20] = "hello ";
char s2[20] = "world";
strncat(s1, s2, 3);
printf("%s", s1);
return 0;
}
1.6.2 strncat的模拟实现
#include <stdio.h>
#include <assert.h>
char* my_strncat(char* dest, const char* src, size_t num)
{
char* ret = dest;
assert(dest && src);
while (*dest)
{
dest++;
}
for (int i = 0; i < num; i++)
{
*dest++ = *src++;
}
return ret;
}
int main()
{
char s1[20] = "hello ";
char s2[20] = "world";
printf("%s", my_strncat(s1, s2, 3));
return 0;
}
1.7 strncmp
int strncmp (const char* str1, const char* str2, size_t num);
1.7.1 strncmp的使用
#include <stdio.h>
#include <string.h>
int main()
{
char s1[] = "abcdef";
char s2[] = "abcdqwer";
int ret = strncmp(s1, s2, 4);
printf("%d", ret);
return 0;
}
1.7.2 strncmp的模拟实现
#include <stdio.h>
#include <assert.h>
int my_strncmp(const char* str1,const char* str2, size_t num)
{
assert(str1 && str2);
int i = 0;
int count = 0;
for (i = 0; i < num; i++)
{
if (*str1 == *str2)
{
str1++;
str2++;
count++;
if (count == num)
{
return 0;
}
}
else if (*str1 < *str2)
{
return -1;
}
else
{
return 1;
}
}
}
int main()
{
char s1[] = "abcdef";
char s2[] = "abcdqwer";
printf("%d", my_strncmp(s1, s2, 5));
return 0;
}
1.8 strstr
char* strstr (const char *str1, const char* str2);
-
搜索一个字符串在另个字符串的第一次出现。
-
找到所搜索的字符串,函数返回第一次匹配的字符串的地址。
-
如果没有找到所搜索的字符串,返回NULL。
1.8.1 strstr的使用
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[] = "abcdef";
char arr2[] = "cde";
char* ret = strstr(arr1, arr2);
printf("%s", ret);
return 0;
}
1.8.2 strstr的模拟实现
#include <stdio.h>
#include <assert.h>
char* my_strstr(const char* str1, const char* str2)
{
assert(str1 && str2);
const char* s1 = NULL;
const char* s2 = NULL;
const char* cp = str1;
if (*str2 == '\0')
{
return str1;
}
while (*cp)
{
s1 = cp;
s2 = str2;
while (*s1 && *s2 && (*s1 == *s2))
{
s1++;
s2++;
}
if (*s2 == '\0')
{
return (char*)cp;
}
cp++;
}
return NULL;
}
int main()
{
char arr1[] = "abcdef";
char arr2[] = "cdd";
char* ret = my_strstr(arr1, arr2);
printf("%s", ret);
return 0;
}
1.9 strtok
char* strtook (char* str, const char* sep);
-
参数sep是一个字符串,定义分隔符的字符集合。
-
参数str包含了0个或者多个由sep字符串中一个或多个分隔符作为分割标记。
-
strtok函数会找到str中的下一个标记,并用‘\0’作为结尾,返回指向这个标记的指针。
-
strtok使用时会改变被操作的字符串,所以在使用strtok函数切分字符串一般都是用临时拷贝的内容,且可修改。
-
strtok函数的第一个参数不是NULL,函数将会找到第一个标记,然后会保存它在字符串的位置。
-
strtok函数的第一个参数是NULL,函数将在同个字符串中被保存的位置开始查找下一个标记。
-
字符串不存在更多的标记,返回NULL。
1.9.1 strtok的使用
#include <stdio.h>
#include <string.h>
int main()
{
char arr[] = "Hello#world.!!!";
char* ret = NULL;
/*printf("%s ", ret);
ret = strtok(NULL, "#.");
printf("%s ", ret);
ret = strtok(NULL, "#.");
printf("%s ", ret);*/
for (ret = strtok(arr, "#."); ret != NULL; ret = strtok(NULL, "#."))
{
printf("%s ", ret);
}
return 0;
}
1.10 strerror
- 将错误码给转化成错误信息。
1.10.1 strerror的使用
#include <stdio.h>
#include <errno.h>
int main()
{
FILE* pf = fopen("text.txt", "r");
if (pf == NULL)
{
printf("%s\n", strerror(errno));
return 1;
}
fclose(pf);
return 0;
}
1.11 memcpy
void* memcpy ( void* destination, const void* source, size_t num );
-
从source的位置开始向后复制num个字节的数据到destination的内存位置。
-
该函数遇到’\0’不会停下来。
-
如果destination和source有重叠,复制的结果都是未定义的。
1.11.1 memcpy的使用
#include <stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int len = sizeof(arr) / sizeof(arr[0]);
memcpy(arr + 2, arr + 1, 20);
for (int i = 0; i < len; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
1.11.2 memcpy的模拟实现
#include <stdio.h>
void* my_memcpy(void* dest, const* src, size_t num)
{
void* ret = dest;
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ret;
}
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int len = sizeof(arr) / sizeof(arr[0]);
my_memcpy(arr + 2, arr , 20);
for (int i = 0; i < len; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
1.12 memmove
void* memmove ( void* destination, const void* source, size_t num );
- 源空间和目标空间出现重叠,就需要使用memmove函数处理。
1.12.1 memmove的使用
#include <stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int len = sizeof(arr) / sizeof(arr[0]);
memmove(arr + 2, arr + 1, 20);
for (int i = 0; i < len; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
1.12.2 memmove的模拟实现
#include <stdio.h>
void my_memmove(void* dest, const void* src, size_t num)
{
void* ret = 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 ret;
}
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int len = sizeof(arr) / sizeof(arr[0]);
my_memmove(arr + 2, arr , 20);
for (int i = 0; i < len; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
1.13 memcmp
int memcmp ( const void* ptr1, const void* ptr2, size_t num );
-
比较从ptr1和ptr2指针开始的num个字节。
-
函数返回值与strcmp相同。
1.13.1 memcmp的使用
#include <stdio.h>
int main()
{
char arr1[] = "abcdef";
char arr2[] = "abcdqq";
int ret = memcmp(arr1, arr2, 25);
printf("%d", ret);
return 0;
}
1.13.2 memcmp的模拟实现
int my_memcmp(const void* str1, const void* str2, size_t num)
{
const char* p1 = (char*)str1;
const char* p2 = (char*)str2;
while (num--)
{
if(*p1 == p2 )
{
p1++;
p2++;
}
/*if (*p1 < *p2)
{
return -1;
}
else
{
return 1;
}*/
}
return *p1-*p2;
}
1.14 memset
void *memset( void *dest, int c, size_t count );
- 以字节为单位设置内存
1.14.1 memset的使用
#include <stdio.h>
int main()
{
int arr[] = { 0 };
memset(arr, 1, 20);
return 0;
}
2.字符分类函数
函数 | 符合以下条件返回真 |
---|---|
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 | 任何可打印字符,包括图形字符和空白字符 |
#include <stdio.h>
#include <ctype.h>
int main()
{
char arr[10] = { 0 };
scanf("%s",arr);
int i = 0;
while (arr[i] != '\0')
{
if (isupper(arr[i]))
{
arr[i] = tolower(arr[i]);
}
printf("%c ", arr[i]);
i++;
}
return 0;
}
字符转换:
int tolower ( int c ); //转换小写字母
int toupper ( int c ); //转换大写字母
上一章:C语言深入学习 — 2.指针的进阶
配套练习:
C语言练习题110例(一)
C语言练习题110例(二)
C语言练习题110例(三)
C语言练习题110例(四)
C语言练习题110例(五)
C语言练习题110例(六)
C语言练习题110例(七)
C语言练习题110例(八)
C语言练习题110例(九)
C语言练习题110例(十)
C语言练习题110例(十一)