目录
七. strncpy函数的使用与模拟实现
7.1 strncpy函数理解
strncpy
是 C 标准库中用于复制字符串的函数,定义在 <string.h>
头文件中。相比 strcpy
,它提供了长度限制,可以防止缓冲区溢出。
函数原型
char *strncpy(char *dest, const char *src, size_t n);
参数说明
dest
: 目标字符数组,用于存储复制的内容
src
: 源字符串,将被复制的字符串
n
: 最多复制的字符数(包括 ‘\0’)返回值
返回目标字符串
dest
的指针功能特点
复制最多 n 个字符 从
src
到dest
两种终止条件:
遇到
src
的 ‘\0’ 终止符达到最大字符数 n
7.2 strncpy函数使用示例
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[20] = { 0 };
char arr2[] = "hello,worldCCCCCCC";
char* p = strncpy(arr1, arr2, 11);
printf("%s\n", p);
printf("%s\n", arr1);
return 0;
}
7.3 strncpy函数模拟实现
#include<stdio.h> // 标准输入输出库
#include<string.h> // 字符串操作库
#include<assert.h> // 断言库
// 自定义的strncpy函数
// 参数:arr1 - 目标字符串,arr2 - 源字符串,num - 要拷贝的字符数
// 返回值:指向目标字符串的指针
char* my_strncpy(char* arr1, const char* arr2, size_t num)
{
// 使用断言确保目标指针和源指针都不为NULL
assert(arr1 && arr2);
// 保存目标字符串的起始地址,用于返回
char* p = arr1;
int i = 0;
// 循环拷贝字符,直到达到指定数量或遇到源字符串的结束符
for (i = 0; i < num && arr2[i]; i++)
{
arr1[i] = arr2[i];
}
// 如果拷贝的字符数少于指定数量,则在目标字符串后添加结束符
if (i < num)
{
arr1[i] = 0;
}
// 返回目标字符串的起始地址
return p;
}
int main()
{
char arr1[20] = { 0 }; // 初始化目标字符串数组,全部置为0
char arr2[] = "abcdefg"; // 源字符串
char* ret = my_strncpy(arr1, arr2, 5); // 调用自定义函数,拷贝前5个字符
printf("%s", ret); // 输出结果:abcde
return 0;
}
八. strncat函数的使用与模拟实现
8.1strncat函数理解
strncat
是 C 标准库中的一个字符串拼接函数,用于将源字符串的前 n
个字符追加到目标字符串的末尾,并自动添加终止符 \0
。
函数原型:
char *strncat(char *dest, const char *src, size_t n);
dest
:目标字符串(必须足够大以容纳追加后的结果)。src
:源字符串(不会被修改)。n
:最多追加的字符数(如果src
长度小于n
,则只追加src
的全部内容)。- 返回值:返回
dest
的指针。
8.2 strncat函数使用示例
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[20] = "hello";
char arr2[] = "world";
char*p=strncat(arr1, arr2,5);
printf("%s\n", p);
printf("%s\n", arr1);
return 0;
}
8.3 strncat函数模拟实现
#include<stdio.h> // 标准输入输出库
#include<assert.h> // 断言库
// 自定义的 strncat 函数
// 参数:arr1 - 目标字符串,arr2 - 源字符串,num - 要追加的字符数
// 返回值:指向目标字符串的指针
char* mystrncat(char* arr1, const char* arr2, size_t num)
{
assert(arr1 && arr2); // 确保目标指针和源指针都不为 NULL
char* p = arr1; // 保存目标字符串的起始地址,用于返回
// 找到目标字符串的末尾(即 '\0' 的位置)
while (*arr1)
{
arr1++;
}
// 从源字符串复制最多 num 个字符到目标字符串的末尾
int i = 0;
for (i = 0; arr2[i] && i < num; i++)
{
arr1[i] = arr2[i];
}
// 如果 num 小于 0,则在目标字符串后添加结束符(但 num 是 size_t,不可能小于 0)
if (num < 0)
{
arr1[i] = 0;
}
return p; // 返回目标字符串的起始地址
}
int main()
{
char arr1[20] = "hello "; // 目标字符串
char arr2[] = "worldCCCCC"; // 源字符串
char* ret = mystrncat(arr1, arr2, 5); // 调用自定义函数,追加前 3 个字符
printf("%s", ret); // 输出结果:hellowor
return 0;
}
九. strncmp函数的使用
9.1 strncmp函数理解
strncmp
是 C 标准库中的一个字符串比较函数,用于比较两个字符串的前 n
个字符。它的主要作用是判断两个字符串是否相等,或者在字典序(ASCII 码顺序)上的大小关系。
函数原型
int strncmp(const char *str1, const char *str2, size_t n);
str1
:第一个字符串(不会被修改)。str2
:第二个字符串(不会被修改)。n
:最多比较的字符数。- 返回值:
< 0
:str1
的前n
个字符在字典序上小于str2
。= 0
:str1
的前n
个字符与str2
完全相同。> 0
:str1
的前n
个字符在字典序上大于str2
。
strncmp
的工作原理:
- 逐个字符比较:
- 从
str1
和str2
的第一个字符开始比较,直到遇到不同的字符或比较完n
个字符。- 比较规则:
- 如果
str1
的字符 ASCII 码值 <str2
的字符,返回 负数。- 如果
str1
的字符 ASCII 码值 >str2
的字符,返回 正数。- 如果前
n
个字符完全相同,返回 0。- 提前终止条件:
- 遇到
\0
(字符串结束符)时停止比较。- 比较完
n
个字符时停止。
9.2 strncmp函数使用示例
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "abcdef";
char arr2[] = "abcggg";
int ret = strncmp(arr1, arr2, 5);
if (ret > 0)
printf("abcdef>abcggg\n");
else if (ret < 0)
printf("abcdef<abcggg\n");
else
printf("=\n");
return 0;
}
十. strstr函数的使用与模拟实现
10.1 strstr函数理解
strstr
是 C 标准库中的一个字符串查找函数,用于在一个字符串中查找另一个字符串的首次出现位置。
函数原型
char *strstr(const char *haystack, const char *needle);
- 参数:
haystack
:被搜索的主字符串needle
:要查找的子字符串- 返回值:
- 如果找到,返回指向主字符串中子字符串首次出现位置的指针
- 如果未找到,返回 NULL
功能说明:
strstr
函数会扫描haystack
字符串,查找needle
字符串的第一次出现。查找是区分大小写的。
10.2 strstr函数使用示例
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "I LOVE CHAIN";
char arr2[] = "LOVE";
char* p = strstr(arr1, arr2);
if (p != NULL)
printf("查找成功: %s\n", p);
else
printf("抱歉 查找失败\n");
}
10.3 strstr函数模拟实现
#include<stdio.h> // 标准输入输出库
#include<string.h> // 字符串操作库
#include<assert.h> // 断言库
// 自定义的 strstr 函数
// 参数:str1 - 被查找的字符串,str2 - 要查找的子串
// 返回值:如果找到,返回子串在 str1 中的起始地址;否则返回 NULL
char* my_strstr(const char* str1, const char* str2)
{
assert(str1 && str2); // 确保 str1 和 str2 都不为 NULL
char* p = (char*)str1; // 用于遍历 str1
char* s1 = NULL; // 用于临时记录 str1 的当前位置
char* s2 = NULL; // 用于遍历 str2
// 如果要查找的子串是空字符串,直接返回 str1
if (*str2 == '\0')
return (char*)str1;
// 遍历 str1
while (*p)
{
s1 = p; // 记录当前查找的起始位置
s2 = (char*)str2; // 每次从 str2 的开头开始匹配
// 逐个字符比较,直到字符不匹配或任一字符串结束
while (*s1 && *s2 && *s1 == *s2)
{
s1++;
s2++;
}
// 如果 str2 已经遍历完(即找到完整匹配),返回起始位置 p
if (*s2 == '\0')
return p;
p++; // 继续查找下一个位置
}
return NULL; // 遍历完 str1 仍未找到,返回 NULL
}
int main()
{
char arr1[] = "I LOVE CHINA"; // 被查找的字符串
char arr2[] = "LOVE"; // 要查找的子串
char* ret = my_strstr(arr1, arr2); // 调用自定义查找函数
if (ret != NULL)
{
printf("查找成功:%s", ret); //
}
else
{
printf("查找失败");
}
return 0;
}
十一. strtok函数的使用与模拟实现
11.1 strtok函数理解
strtok
是 C 标准库中的一个字符串分割函数,用于将一个字符串按照指定的分隔符(delimiters)拆分成多个子字符串(tokens)。
函数原型
#include <string.h> // 需要包含头文件 char *strtok(char *str, const char *delimiters);
str
:待分割的字符串(首次调用时传入,后续调用传NULL
)。
delimiters
:分隔符集合(如", \t \n"
表示按空格、逗号、制表符、换行符分割)。返回值:
成功时返回下一个子字符串(token)的指针。
如果没有更多子字符串,返回
NULL
。
strtok
的工作原理
首次调用:
传入待分割的字符串
str
,strtok
找到第一个分隔符,将其替换为\0
,并返回第一个子字符串的指针。后续调用:
传入
NULL
,strtok
会从上次结束的位置继续查找下一个分隔符,并返回下一个子字符串。结束条件:
当所有子字符串都被提取后,返回
NULL
。
为什么后续调用传入NULL?
原因如下:
1.
strtok
的工作原理
strtok
是一个状态ful(stateful)函数,它会记住上一次处理的位置。具体来说:
首次调用时,
strtok
接收一个字符串(如str
)和分隔符(如delimiters
),它会从该字符串的起始位置开始扫描,找到第一个不包含分隔符的子字符串(token),并返回它。后续调用时,
strtok
需要继续从上次结束的位置开始扫描剩余的部分。为了告诉strtok
继续处理同一个字符串,需要传入NULL
作为第一个参数。如果传入一个新的字符串,strtok
会重置内部状态,开始处理新的字符串。2. 为什么传入
NULL
?
内部静态指针:
strtok
内部使用一个静态指针(或全局变量)来记录当前处理的位置。首次调用时,这个指针被初始化为传入字符串的地址;后续调用时,传入NULL
表示“继续处理上次的字符串”。避免重置状态:如果后续调用传入一个新的字符串(非
NULL
),strtok
会重置内部指针,导致之前的分割状态丢失。
11.2 strtok函数使用示例
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "hello,world;this|is-a.test";
const char* delimiters = ",;|-."; // 分隔符可以是逗号、分号、竖线、横线、点
// 首次调用,传入 str
char* token = strtok(str, delimiters);
while (token != NULL) {
printf("Token: %s\n", token);
token = strtok(NULL, delimiters); // 后续调用传 NULL
}
return 0;
}
11.3 strtok注意事项
修改原字符串:
strtok
会直接修改传入的字符串,将分隔符替换为\0
。因此,不能对常量字符串(如"hello,world"
)使用strtok
,否则会导致段错误(Segmentation Fault)。✅ 正确:
char str[] = "hello,world";
(可修改)❌ 错误:
char *str = "hello,world";
(字符串常量,不可修改)连续分隔符:
如果字符串中有连续的分隔符(如
"a,,b"
),strtok
会跳过它们,不会返回空字符串。不能嵌套调用:
- 由于
strtok
使用静态存储,不能同时用于多个字符串的分割。例如:char str1[] = "a,b"; char str2[] = "1;2"; char *token1 = strtok(str1, ","); // 第一次调用 char *token2 = strtok(str2, ";"); // 会破坏 str1 的分割状态!
十二. strerror函数的使用与模拟实现
12.1 strerror函数理解
strerror
是 C 标准库中的一个函数,用于将错误代码(errno
)转换为可读的错误信息字符串。它定义在 <string.h>
头文件中,通常与 errno
(定义在 <errno.h>
)一起使用,以便在程序出错时提供更友好的错误提示。
函数原型
#include <string.h> char *strerror(int errnum);
参数:
errnum
:错误代码(通常是errno
的值)。返回值:
返回一个指向错误描述字符串的指针(静态存储区,不可修改)。
strerror
的用途
在不同的系统和C语言标准库的实现中都规定了⼀些错误码,⼀般是放在 errno.h 这个头文件中说明的,C语言程序启动的时候就会使用⼀个全局的变量 errno 来记录程序的当前错误码,只不过程序启动的时候errno是 0,表示没有错误,当我们在使用标准库中的函数的时候发生了某种错误,就会将对应的错误码,存放在 errno 中,而⼀个错误码的数字是整数很难理解是什么意思,所以每⼀个错误码都是有对应的错误信息的。strerror函数就可以将错误对应的错误信息字符串的地址返回
12.2 strerror函数使用
#include <errno.h>
#include <string.h>
#include <stdio.h>
//打印0~10这些错误码对应的信息
int main()
{
int i = 0;
for (i = 0; i <= 10; i++) {
printf("%d.%s\n",i, strerror(i));
}
return 0;
}
示例
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main()
{
//C语言可以打开文件
//fopen
//如果以读的形式打开文件,文件是必须要存在的,如果文件不存在,则打开文件失败
//fopen函数就会将错误码放在errno
//同时函数就会返回NULL
FILE* pFile;
pFile = fopen("5_20.text", "r");
if (pFile == NULL)
printf( %s\n", strerror(errno));
return 0;
}
12.3 perror函数
perror
是 C 标准库(<stdio.h>
)中的一个函数,用于打印与 errno
相关的错误信息。它的原型如下:
void perror(const char *s);
功能
- 根据全局变量
errno
(通常由系统调用或库函数设置)打印对应的错误描述。- 如果
s
不是NULL
或空字符串,perror
会先输出s
,后跟一个冒号:
和空格,然后输出errno
对应的错误信息。- 如果
s
是NULL
或空字符串,则只输出errno
的错误信息。
使用示例
int main() {
FILE* fp = fopen("nonexistent_file.txt", "r");
if (fp == NULL) {
perror("Failed to open file");
}
return 0;
}
与 strerror(errno)
的区别
perror
直接打印错误信息到stderr
(标准错误输出)。strerror(errno)
返回错误信息的字符串,可以自定义输出方式:
fprintf(stderr, "Error: %s\n", strerror(errno));
以上就是字符函数和字符串函数上篇的全部内容 希望能够为您提供帮助
往期回顾