【C语言进阶】字符函数和字符串函数
文章目录
本章目标:
学会并掌握处理字符和字符串的库函数的使用方法和注意事项,并能模拟实现它们。
本章重点:
1.求字符串长度
strlen()
2.长度不受限制的字符串函数
strcpy()
strcat()
strcmp()
3.长度受限制的字符串函数
strncpy()
strncat()
strncmp()
4.字符串查找
strstr()
strtok()
5.错误信息报告
strerror()
6.字符操作函数
字符分类函数
字符转换函数
7.内存操作函数
memcpy()
memmove()
memset()
memcmp()
0 前言
C语言对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,而字符串通常是放在
常量字符串
中或者字符数组
中的。
字符串常量
适用于那些对它不做修改的字符串函数。
一、函数介绍
1 strlen()
1.1 函数原型
求字符串长度。
size_t strlen (const char* str);
1.2 介绍
1.字符串以 \0
作为结束标志,strlen
函数返回的是在字符串中 \0
之前出现的字符个数(但不包括 \0
)。
2.参数指向的字符串必须要以 \0
结束。
3.函数的返回值类型为 size_t
,是无符号整型( unsigned int
)。
4.学会 strlen
函数的模拟实现。
1.3 示例
代码示例:
#include<stdio.h>
#include<string.h>
int main()
{
//strlen()的应用
const char* str1 = "abcdef";
const char* str2 = "bbb";
if (strlen(str2) - strlen(str1) > 0)
{
printf("str2 > str1\n");//输出结果
}
else
{
printf("str1 > str2\n");
}
return 0;
}
解释说明:
1.if (strlen(str2) - strlen(str1) > 0)
:两个无符号数相减,结果也是无符号数。
2 if
语句的修改:
1.if (strlen(str2) > strlen(str1))
2.if ((int)strlen(str2) - (int)strlen(str1) > 0)
3.int ret = strlen(str2) - strlen(str1);
if (ret > 0)
2 strcpy()
2.1 函数原型
拷贝源字符串到目标字符串中。
char* strcpy(cgar* destination, const char* source);
2.2 介绍
1.源字符串 source
必须以 \0
结束。
2.该函数会将源字符串中的 \0
拷贝到目标空间中。
3.目标字符串的空间必须足够大(至少等于源字符串的大小),以确保能够存放源字符串。
4.目标空间必须可变(能够修改)。
5.学会 strcpy
函数的模拟实现。
2.3 示例
代码示例:
#include<stdio.h>
#include<string.h>
int main()
{
//strcpy()的应用
char str1[20] = "XXXXXXXXXXXXXXXXX";
char str2[] = "hello pokemon.";
printf("%s\n", str1);
strcpy(str1, str2);
printf("%s\n", str1);
return 0;
}
解释说明:
1 该函数会将源字符串中的 \0
拷贝到目标空间中。
3 strcat()
3.1 函数原型
将源字符串追加到目标字符串后面。
char* strcat(char* destination, const char* source);
3.2 介绍
1.源字符串必须以 \0
结束。
2.目标空间必须足够大,能容纳下源字符串(追加的字符串)的内容。
3.目标空间必须可变(能够修改)。
4.最好不要自己给自己追加。
5.学会 strcat
函数的模拟实现。
3.3 示例
代码示例:
#include<stdio.h>
#include<string.h>
int main()
{
//strcat()的应用
char arr1[20] = "hello ";
char arr2[] = "pokemon.";
strcat(arr1, arr2);
printf("%s\n", arr1);
char arr3[20] = "hello";
//strcat(arr3, arr3);//error;最好不要自己给自己追加
printf("%s\n", arr3);
return 0;
}
解释说明:
1 最好不要自己给自己追加,不然的话字符串末尾的 \0
会被覆盖,strcat()
就会一直追加,直到填满目标空间,最终会引发异常,程序崩溃。
4 strcmp()
4.1函数原型
比较两个字符串。
int strcmp(const char* str1, const char* str2);
4.2 介绍
1.将两个字符串进行比较。
2.从起始位置开始比较每一对字符,如果两个字符相等,则进行下一对字符的比较,直到有一对字符不同或遇到 \0
就结束比较。
3.该函数会返回一个整型值,用来指示字符串之间的关系。
4.标准规定:
return value | indicates |
---|---|
>0 | str1大于str2 |
=0 | str1等于str2 |
<0 | str1小于str2 |
4.3 示例
代码示例:
#include<stdio.h>
#include<string.h>
int main()
{
//strcmp()的应用
char str1[] = "abcdef";
char str2[] = "abq";
char str3[] = "abc";
char* pc = "abc";
//str1/str2
int ret = strcmp(str1, str2);
if (ret > 0)
printf("str1 > str2\n");
else if (ret == 0)
printf("str1 == str2\n");
else if (ret < 0)
printf("str1 < str2\n");
//str1/str3
ret = strcmp(str1, str3);
if (ret > 0)
printf("str1 > str3\n");
else if (ret == 0)
printf("str1 == str3\n");
else if (ret < 0)
printf("str1 < str3\n");
//str3/pc
ret = strcmp(str3, pc);
if (ret > 0)
printf("str3 > pc\n");
else if (ret == 0)
printf("str3 == pc\n");
else if (ret < 0)
printf("str3 < pc\n");
return 0;
}
解释说明:
1 字符串比较函数,比较的是对应位置字符对的 ASCII
值的大小;哪个字符大,那么其所在的字符串就大。
5 strncpy()
5.1 函数原型
从源字符串
source
中拷贝num
个字符到目的字符串destination
中。
char* strncpy(char* destination, const char* source, size_t num);
5.2 介绍
1.拷贝 num
个字符从源字符串到目的空间。
2.如果源字符串的长度小于 num
,则拷贝完源字符之后,在目标字符串后补充 \0
,直到所有拷贝字符数够 num
个。
3.如果源字符串的长度大于 num
,则不会在目标空间末尾隐式追加 \0
字符。
5.3 示例
代码示例:
#include<stdio.h>
#include<string.h>
int main()
{
//strncpy()的应用
char arr1[20] = "abcdef";
char arr2[] = "xxx";
strncpy(arr1, arr2, 5);
printf("%s\n", arr1);//xxx
return 0;
}
解释说明:
1 如果源字符串的长度小于 num
,则拷贝完源字符之后,在目标字符串后补充 \0
,直到所有拷贝字符数够 num
个。但是待拷贝的字符个数 num
不能超过目标空间的大小。
6 strncat()
6.1 函数原型
追加
num
个字符,不够则只追加到源字符串的结尾\0
处。
char* strncat(cagr* destination, const cahr* source);
6.2 介绍
1.从源字符串中向目标字符串后追加 num
个字符。
2.如果源字符串的长度小于 num
,则只追加到源字符串的末尾 \0
处。
3.如果源字符串的长度大于 num
,则只追加 num
个字符,并在结尾补充 \0
。
6.3 示例
6.3.1 示例1
代码示例:
#include<stdio.h>
#include<string.h>
int main()
{
//strncat()的应用
char str1[20];
char str2[20];
strcpy(str1, "To be ");
strcpy(str2, "or not to be");
strncat(str1, str2, 6);
puts(str1);//To be or not
return 0;
}
解释说明:
1 将源字符串 str2
中前6个字符追加到 str1
中,追加完成后并在末尾补上 \0
。
2 puts()
用来打印字符串并换行。
6.3.2 示例2
代码示例:
#include<stdio.h>
#include<string.h>
int main()
{
//strncat()的应用2
char arr1[20] = "abcdef\0XXXXXXXX";
char arr2[] = "aaa";
strncat(arr1, arr2, 5);
puts(arr1);//"abcdefaaa"
return 0;
}
解释说明:
1 如果源字符串的长度小于 num
,则只追加到源字符串的末尾 \0
处。
即不够追加时只追加到源字符串的 \0
处就停止。
7 strncmp()
7.1 函数原型
比较两个字符串前
num
个字符。
int strncmp(const char* str1, const char* str2, size_t num);
7.2 介绍
1.比较到出现不相同的字符或者其中一个字符串结束或者 num
对字符全部比较完。
2.该函数会返回一个整型值,用来指示字符串之间的关系。
3.标准规定:
return value | indicates |
---|---|
>0 | str1大于str2 |
=0 | str1等于str2 |
<0 | str1小于str2 |
7.3 示例
代码示例:
#include<stdio.h>
#include<string.h>
int main()
{
//strncmp()的应用
char str[][5] = { "R2D2","C3P0", "R2A6" };
puts("Looking for R2 astromech droids...");
int i;
for (i = 0; i < 3; i++)
{
if (strncmp(str[i], "R2xx", 2) == 0)//如果下标i位置的字符串前两个字符为R2则打印
{
printf("found %s\n", str[i]);
}
}
return 0;
}
解释说明:
1 比较源字符串 str[i]
与目标字符串 "R2xx"
前 num
个字符。
8 strstr()
8.1 函数原型
寻找一个字符串中的子串。
char* strstr(const char* str1, const char* str2);
8.2 介绍
1.从字符串 str1
中找第一次出现字符串 str2
的位置,然后返回该位置。
2.如果没找到子串,返回空指针 NULL
。
8.3 示例
代码示例:
#include<stdio.h>
#include<string.h>
int main()
{
//strstr()的应用
char str[] = "This is a simple string.";
char* pch;
pch = strstr(str, "simple");//找子串,然后返回目标位置的地址
strncpy(pch, "sample", 6);//相当于是修改simple为sample
puts(str);//打印输出字符串
return 0;
}
解释说明:
1 通过 strstr()
找到 str
中的子串 "simple"
,然后通过 strncpy()
修改为 "sample"
。
9 strtok()
9.1 函数原型
char* strtok(char* str, const char* sep);
9.2 介绍
1.sep
参数是一个字符串,定义了用作分隔符的字符集合。
2.第一个参数指定一个字符串,它包含了0个或者多个由 sep
字符串中一个或多个分隔符分隔的标记。
3.strtok
函数找到 str
中的下一个标记,并将其用 \0
结尾,返回一个指向这个标记的指针。
4.strtok
函数的第一个参数不为 NULL
,函数将找到 str
中第一个标记,strtok
函数将保存它在字符串中的位置。
5.strtok
函数的第一个参数为 NULL
,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
6.如果字符串中不存在更多的标记,则返回 NULL
指针。
9.3 示例
9.3.1 示例1
代码示例:
#include<stdio.h>
#include<string.h>
int main()
{
//strtok()的应用
char str[] = "- This, a sample string.";
char* pch;
printf("Splitting string \"%s\" into tokens:\n", str);
pch = strtok(str, " ,.-");
while (pch != NULL)
{
printf("%s\n", pch);
pch = strtok(NULL, " ,.-");
}
/*
* This
* a
* sample
* string
*/
return 0;
}
解释说明:
1 用作分隔符的字符集合:" ,.-"
9.3.2 示例2
代码示例:
#include<stdio.h>
#include<string.h>
int main()
{
//strtok()的应用2
const char* p = "xxx_yyy@163.com";
const char* sep = "_@.";
char arr[30];
char* str = NULL;
strcpy(arr, p);
for (str = strtok(arr, sep); str != NULL; str = strtok(NULL, sep))
{
printf("%s\n", str);
}
/*
* xxx
* yyy
* 163
* com
*/
return 0;
}
解释说明:
1 str = strtok(arr, sep)
,从 arr
的位置开始向后查找标记字符,找到后会将该字符置为 \0
并记录其地址,然后返回该地址。
2 str = strtok(NULL, sep)
,从上一个标记位置开始向后查找下一个标记字符,如果不存在则返回 NULL
指针,否则将重复这一过程。
10 strerror()
10.1 函数原型
返回错误码所对应的错误信息首字符的地址。
char* strerror(int errnum);
10.2 介绍
1.库函数在执行的过程中如果发生了错误,会将一个错误码存放在 errno
这个变量中。(运行时错误)
2.errno
是C语言提供的一个全局变量。
3.错误码的可读性差,应该将其翻译成错误信息。
10.3 示例
10.3.1 示例1
代码示例:
#include<stdio.h>
#include<string.h>
int main()
{
//strerror()的应用1
FILE* pFile;
pFile = fopen("unexist.ent", "r");
//如果调用fopen函数失败,则会将会产生的错误码放入errno变量中
if (pFile == NULL)//如果打开失败,显示错误信息
{
printf("Error opening file unexist.ent:\n%s\n", strerror(errno));
//perror("str");//显示输出:No such file or directory
//errno: Last error number
}
return 0;
}
解释说明:
1 strerror(errno)
:将错误码翻译成错误信息,并返回错误信息首字符的地址。
2 perror("str");
找到并打印错误信息。
10.3.2 示例2
代码示例:
#include<stdio.h>
#include<string.h>
int main()
{
//strerror()的应用2
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d:%s\n", i, strerror(i));//打印错误码为0~9的错误信息
}
/*
* 0:No error
* 1:Operation not permitted
* 2:No such file or directory
* 3:No such process
* 4:Interrupted function call
* 5:Input/output error
* 6:No such device or address
* 7:Arg list too long
* 8:Exec format error
* 9:Bad file descriptor
*/
return 0;
}
解释说明:
1 打印错误码为0~9的错误信息。
11 其他字符函数
11.1 字符分类函数
介绍:
函数 | 如果它的参数符合下列条件就返回真 |
---|---|
iscntrl() | 任何控制字符(不可打印字符) |
isspace() | 空白字符:空格 ’ '、换页 ‘\f’、换行 ‘\n’、回车 ‘\r’、制表符 ‘\t’、垂直制表符 ‘\v’ |
isdigit() | 十进制数字:0~9 |
isxdigit() | 十六进制数字:包括所有十进制数字,小写字母af,大写字母AF |
islower() | 小写字母:a~z |
isupper() | 大写字母:A~Z |
isalpha() | 字母: a~z 或 A~Z |
isalnum() | 字母或数字,az,AZ,0~9 |
ispunct() | 标点符号,任何不属于数字或者字母的图形字符(可打印) |
isgraph() | 任何图形字符 |
isprint() | 任何可打印字符,包括图形字符和空白字符 |
… | … |
说明:此处仅作简单介绍。
11.1.1 示例
代码示例:
#include<stdio.h>
#include<ctype.h>
int main()
{
//isupper()、tolower()
char str[] = "Test string.\n";
char c;
int i = 0;
while (str[i])//将大写字符转换为小写字符
{
c = str[i];
if (isupper(c))
{
c = tolower(c);
}
putchar(c);
i++;
}
/*
* test string.
*/
return 0;
}
解释说明:
1 如果字符数组中有大写字母,就将其转换为小写字母并输出,其他字符原样输出。
11.2 字符转换函数
11.2.1 tolower()
① 函数原型:
将大写字母转换为小写字母。
int tolower ( int c );
② 介绍:
1.传入的参数如果是大写字母,就将其转换成小写字母;否则就不进行任何转换。
2.返回值以 int
值的形式返回,该值可以隐式转换为 char
。
3.该函数定义在 <ctype.h>
头文件中。
③ 示例:
代码示例:tolower()
的应用1
#include<stdio.h>
#include<ctype.h>
int main()
{
//tolower()的应用1
char ch1 = '1';
char ch2 = 'A';
char ch3 = 'm';
char ch4 = 65;//'A'
char ch5 = 109;//'m'
putchar(tolower(ch1));//1
putchar(tolower(ch2));//a
putchar(tolower(ch3));//m
putchar(tolower(ch4));//a
putchar(tolower(ch5));//m
return 0;
}
解释说明:
1 tolower
传入的参数如果是大写字母( 值为对应的ASCII码值 ),就将其转换成小写字母;如果是其他字符就不进行任何转换。
2 putchar
用来打印字符。
代码示例:tolower()
的应用2
#include<stdio.h>
#include<ctype.h>
int main()
{
//tolower()的应用2
int i = 0;
char str[] = "Test String.\n";
char c;
while (str[i])
{
c = str[i];
putchar(tolower(c));
i++;
}
/*
* test string.
*/
return 0;
}
11.2.2 toupper()
① 函数原型:
将小写字母转换为大写字母。
int toupper ( int c );
② 介绍:
1.传入的参数如果是小写字母( 值为对应的ASCII码值 ),就将其转换成大写字母;否则就不进行任何转换。
2.返回值以 int
值的形式返回,该值可以隐式转换为 char
。
3.该函数定义在 <ctype.h>
头文件中。
③ 示例:
代码示例:
#include<stdio.h>
#include<ctype.h>
int main()
{
//toupper()的应用
int i = 0;
char str[] = "Test String.\n";
char c;
while (str[i])
{
c = str[i];
putchar(toupper(c));
i++;
}
/*
* TEST STRING.
*/
return;
}
解释说明:
1 传入的参数如果是小写字母( 值为对应的ASCII码值 ),就将其转换成大写字母;如果是其他字符就不进行任何转换。
2 putchar
用来打印字符。
12 memcpy()
12.1 函数原型
用来处理不重叠的内存拷贝。
void* memcpy(void* destination, const void* source, size_t num);
12.2 介绍
1.函数 memcpy
从 source
的位置开始向后复制 num
个字节的数据到 destination
的内存位置。
2.这个函数在遇到 \0
的时候并不会停下来。
3.如果 source
和 destination
有任何的重叠,复制的结果都是都是未定义的。(用来处理不重叠的内存拷贝)
4.函数返回目标空间的起始地址。
12.3 示例
代码示例:
#include<stdio.h>
#include<string.h>
struct
{
char name[40];
int age;
}person, person_copy;
int main()
{
//memcpy()的应用
char my_name[] = "Pierre de Fermat";
//using memcpy to copy string:
memcpy(person.name, my_name, strlen(my_name) + 1);
person.age = 46;
//using memcpy to copy structure:
memcpy(&person_copy, &person, sizeof(person));
printf("person_copy: %s, %d\n", person_copy.name, person_copy.age);
//person_copy: Pierre de Fermat, 46
return 0;
}
13 memmove()
13.1 函数原型
内存移动,可处理重叠的内存拷贝。
void* memmove(void* destination, const void* source, size_t num);
13.2 介绍
1.该函数与 memove
的差别就是本函数处理的源内存块和目标内存块可以是重叠的。
2.如果源空间和目标空间出现重叠,就得使用 memove
函数处理。
13.3 示例
代码示例:
#include<stdio.h>
#include<string.h>
int main()
{
//memmove()的应用
char str[] = "memmove can be very useful......";
memmove(str + 20, str + 15, 11);//str[15] = v(very),str[20] = u(useful);
puts(str);//memmove can be very very useful.
return 0;
}
14 memcmp()
14.1 函数原型
比较两个内存块
int memcmp(const void* ptr1, const void* ptr2, size_t num);
14.2 介绍
1.比较从 ptr1
和 ptr2
指针开始的 num
个字节。
2.返回值:
return value | indicates |
---|---|
>0 | ptr1大于ptr2 |
=0 | ptr1等于ptr2 |
<0 | ptr1小于ptr2 |
14.3 示例
代码示例:
#include<stdio.h>
#include<string.h>
int main()
{
//memcmp()的应用
char buffer1[] = "DWgaotP12df0";
char buffer2[] = "DWGAOTP12DF0";
int n = memcmp(buffer1, buffer2, sizeof(buffer1));
if (n > 0)
{
printf("'%s' is greater than '%s'.\n", buffer1, buffer2);//g>G
}
else if (n < 0)
{
printf("'%s' is less than '%s'.\n", buffer1, buffer2);
}
else
{
printf("'%s' is the same as '%s'.\n", buffer1, buffer2);
}
return 0;
}
总结:
本节介绍了C语言中常见的字符函数与字符串函数;同时给出了使用示例。
感谢您的阅读!如有任何错误,欢迎您的批评指正!