一、捕获异常函数
1. 代码示例
#include <stdlib.h>
#include <crtdbg.h>
#include <stdio.h>
// 自定义的无效参数处理函数
void my_invalid_parm_handler(const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t p_reserved) {
wprintf(L"Invalid parameter detected in function %s. File: %s Line %d\n", function, file, line);
wprintf(L"Expression: %s\n", expression);
}
int main() {
// 设置自定义的无效参数处理函数
_set_invalid_parameter_handler(my_invalid_parm_handler);
// 这里模拟一个可能触发无效参数的操作,比如除以0
int a = 10;
int b = 0;
int result = a / b;
return 0;
}
2. 说明
- 引用头文件:需要引用
stdlib.h
和crtdbg.h
头文件。 - 设置处理函数:在
main
函数中,使用_set_invalid_parameter_handler
函数设置自定义的无效参数处理函数my_invalid_parm_handler
。当程序中出现无效参数时,会调用该自定义函数进行处理。
二、strcpy_s
函数
1. 函数原型
errno_t strcpy_s(char * restrict dest, rsize_t destsz, const char * restrict src);
2. 参数解释
dest
- 类型:指向目标字符数组的指针。
- 作用:用于存储复制后的字符串。
destsz
- 类型:
rsize_t
类型,代表目标字符数组的大小。 - 意义:包括字符串结束符
'\0'
,指定了dest
所指向的缓冲区的最大容量。
- 类型:
src
- 类型:指向源字符串的指针。
- 作用:该字符串将被复制到
dest
数组中。
3. 返回值
- 成功情况:如果复制操作成功,函数返回 0。
- 错误情况
- 常见错误码:如果发生错误,函数返回一个非零的错误码。常见的错误情况包括以下两种。
EINVAL
错误:如果dest
或src
为空指针,或者destsz
为 0 或小于源字符串的长度(包括'\0'
)。ERANGE
错误:如果目标缓冲区太小,无法容纳源字符串及其结束符'\0'
。
三、strcat_s
函数
1. 函数原型
errno_t strcat_s(char *dest, rsize_t destsz, const char *src);
2. 参数
dest
- 类型:目标字符串缓冲区。
- 作用:连接后的字符串将存储在这里。
destsz
- 类型:
rsize_t
类型,代表目标缓冲区的大小。 - 意义:包括空字符
\0
。
- 类型:
src
- 类型:指向要追加到目标字符串的源字符串的指针。
3. 返回值
- 成功情况:成功时返回 0。
- 失败情况
- 错误码:失败时返回非零错误码,如
EINVAL
或ERANGE
。
- 错误码:失败时返回非零错误码,如
4. 注意事项
- 缓冲区检查:
strcat_s
会检查目标缓冲区是否有足够的空间容纳源字符串,避免溢出。 - 空指针检查:如果
dest
或src
是空指针,函数会返回错误。 - 缓冲区大小要求:
destsz
必须大于目标字符串的当前长度加上源字符串的长度再加 1(用于空字符)。
四、sprintf_s
函数
1. 函数原型
errno_t sprintf_s(char *restrict buffer, rsize_t sizeOfBuffer, const char *restrict format,...);
2. 参数解释
buffer
- 类型:指向用于存储格式化结果的字符数组的指针。
- 作用:存储格式化后的字符串。
sizeOfBuffer
- 类型:
rsize_t
类型,代表目标字符数组buffer
的大小。 - 意义:包括字符串结束符
'\0'
,用于确保不会发生缓冲区溢出。
- 类型:
format
- 类型:格式化字符串。
- 作用:指定了输出的格式,其中可以包含普通字符和格式说明符(如
%d
用于整数,%s
用于字符串等)。
...
- 类型:可变参数列表。
- 作用:根据
format
字符串中的格式说明符,提供相应的参数。
3. 返回值
- 成功情况:如果操作成功,返回写入到
buffer
中的字符数(不包括字符串结束符'\0'
)。 - 错误情况
- 错误码:如果发生错误,返回一个非零的错误码。常见错误情况及对应错误码如下。
EINVAL
错误:如果buffer
或format
为NULL
指针,或者sizeOfBuffer
为 0。ERANGE
错误:如果格式化后的字符串长度(包括'\0'
)超过了sizeOfBuffer
。
五、strncpy_s
函数
1. 函数原型
errno_t strncpy_s(char *restrict dest, rsize_t destsz, const char *restrict src, rsize_t count);
2. 参数解释
dest
- 类型:指向目标字符数组的指针。
- 作用:用于存储复制过来的字符串。
destsz
- 类型:
rsize_t
类型,代表目标字符数组的大小。 - 意义:要包含字符串结束符
'\0'
。
- 类型:
src
- 类型:指向源字符串的指针。
- 作用:要被复制的字符串。
count
- 类型:
rsize_t
类型,代表最多从src
复制到dest
的字符数量。
- 类型:
3. 返回值
- 成功情况:如果复制操作成功,函数返回 0。
- 错误情况
- 错误码:如果出现错误,函数会返回一个非零的错误码,常见错误及对应错误码如下。
EINVAL
错误:当dest
或src
为NULL
指针,或者destsz
为 0 或小于等于count
时返回该错误码。ERANGE
错误:如果src
的长度大于等于count
且destsz
不足以容纳count
个字符和字符串结束符'\0'
时返回此错误码。
六、strncat_s
函数
1. 函数原型
errno_t strncat_s(char *restrict dest, rsize_t destsz, const char *restrict src, rsize_t count);
2. 参数解释
dest
- 类型:指向目标字符数组的指针。
- 作用:该数组需要预先包含一个以
'\0'
结尾的字符串,新追加的内容将从这个'\0'
位置开始添加。
destsz
- 类型:
rsize_t
类型,代表目标字符数组的总大小。 - 意义:包括字符串结束符
'\0'
,用于确保不会发生缓冲区溢出。
- 类型:
src
- 类型:指向源字符串的指针。
- 作用:该字符串以
'\0'
结尾,其中部分内容会被追加到目标字符串末尾。
count
- 类型:
rsize_t
类型,指定从源字符串src
中最多追加到目标字符串dest
的字符数量。
- 类型:
3. 返回值
- 成功情况:如果操作成功,函数返回 0。
- 失败情况
- 错误码:如果出现错误,函数返回一个非零的错误码,常见的错误情况及对应错误码如下。
EINVAL
错误:当dest
或src
为NULL
指针,或者destsz
为 0 时返回该错误码。ERANGE
错误:若目标缓冲区没有足够的空间来容纳追加的字符和原有的内容(包括'\0'
),会返回此错误码。
七、gets_s
函数
1. 函数原型
char *gets_s(char *str, rsize_t n);
2. 参数解释
str
- 类型:指向用于存储读取字符串的字符数组的指针。
- 作用:接收读取的字符串。
n
- 类型:
rsize_t
类型,代表字符数组str
的大小。 - 意义:该数组能够容纳的最大字符数,包括字符串结束符
'\0'
。
- 类型:
3. 返回值
- 成功情况
- 返回值:如果读取成功,函数返回
str
指针。
- 返回值:如果读取成功,函数返回
- 失败情况
- 文件结束符情况:如果遇到文件结束符(EOF)且没有读取到任何字符,函数返回
NULL
并且str
数组内容保持不变。 - 错误情况:如果发生错误(例如读取的字符数超过了
n - 1
个,或者输入过程中出现错误),函数会调用无效参数处理程序(如果已设置),并将str
数组的第一个字符设置为'\0'
,然后返回NULL
。
- 文件结束符情况:如果遇到文件结束符(EOF)且没有读取到任何字符,函数返回
八、strtok_s
函数
1. 函数原型
char *strtok_s(char *restrict str, const char *restrict delimiters, char **restrict context);
2. 参数解释
str
- 类型:指向要分割的字符串的指针。
- 作用
- 首次调用:在第一次调用
strtok_s
时,传入要分割的原始字符串。 - 后续调用:传入
NULL
以继续分割同一个字符串。
- 首次调用:在第一次调用
delimiters
- 类型:指向包含分隔符字符的字符串的指针。
- 作用:这些字符用于指定分割字符串的位置。
context
- 类型:指向一个
char*
类型的指针的指针。 - 作用:用于存储函数内部的上下文信息,在后续调用
strtok_s
时会被使用,以记录分割的位置。
- 类型:指向一个
3. 返回值
- 成功情况:如果找到了一个有效的子字符串,函数返回指向该子字符串的指针。
- 失败情况:如果没有更多的子字符串可供分割,函数返回
NULL
。
九、strcmp
函数
1. 函数原型
int strcmp(const char *s1, const char *s2);
2. 参数解释
s1
- 类型:指向要比较的第一个字符串的指针。
s2
- 类型:指向要比较的第二个字符串的指针。
3. 返回值
- 相等情况:如果
s1
和s2
相等(即两个字符串的内容完全相同),函数返回 0。 - 大小比较情况
- 小于情况:如果
s1
按字典序小于s2
(即s1
中第一个不同字符的 ASCII 值小于s2
中对应字符的 ASCII 值),函数返回一个小于 0 的整数。 - 大于情况:如果
s1
按字典序大于s2
(即s1
中第一个不同字符的 ASCII 值大于s2
中对应字符的 ASCII 值),函数返回一个大于 0 的整数。
- 小于情况:如果
十、strncmp
函数
1. 函数原型
int strncmp(const char *s1, const char *s2, size_t n);
2. 参数解释
s1
- 类型:指向第一个要比较的字符串的指针。
s2
- 类型:指向第二个要比较的字符串的指针。
n
- 类型:
size_t
类型,代表指定要比较的最大字符数。
- 类型:
3. 返回值
- 相等情况:如果
s1
和s2
的前n
个字符完全相同,或者在比较到第n
个字符之前就已经到达某个字符串的末尾(遇到'\0'
)且之前的字符都相同,函数返回 0。 - 大小比较情况
- 小于情况:如果
s1
的前n
个字符按字典序小于s2
的前n
个字符,函数返回一个小于 0 的整数。 - 大于情况:如果
s1
的前n
个字符按字典序大于s2
的前n
个字符,函数返回一个大于 0 的整数。
- 小于情况:如果
十一、strchr
函数
1. 函数原型
char *strchr(const char *s, int c);
2. 参数解释
s
- 类型:指向要进行查找操作的字符串的指针,该字符串必须以
'\0'
结尾。
- 类型:指向要进行查找操作的字符串的指针,该字符串必须以
c
- 类型:要查找的字符,虽然参数类型是
int
,但实际上是将其作为char
类型来处理的,这主要是为了兼容EOF
(文件结束符)的处理。
- 类型:要查找的字符,虽然参数类型是
3. 返回值
- 查找成功情况:如果在字符串
s
中找到了字符c
,函数返回指向该字符首次出现位置的指针。 - 查找失败情况:如果在字符串
s
中没有找到字符c
,函数返回NULL
。
十二、strrchr
函数
1. 函数原型
char *strrchr(const char *str, int c);
2. 参数解释
str
- 类型:要搜索的字符串。
c
- 类型:要查找的字符(以
int
形式传递,但会被转换为char
)。
- 类型:要查找的字符(以
3. 返回值
- 查找成功情况:如果找到字符
c
,返回指向字符串中最后一个匹配字符的指针。 - 查找失败情况:如果未找到字符
c
,返回NULL
。
十三、strstr
函数
1. 函数原型
char *strstr(const char *haystack, const char *needle);
2. 参数解释
haystack
- 类型:指向要进行查找操作的主字符串的指针,该字符串必须以
'\0'
结尾。
- 类型:指向要进行查找操作的主字符串的指针,该字符串必须以
needle
- 类型:指向要查找的子字符串的指针,该字符串同样必须以
'\0'
结尾。
- 类型:指向要查找的子字符串的指针,该字符串同样必须以
3. 返回值
- 查找成功情况:如果在主字符串
haystack
中找到了子字符串needle
,函数返回指向needle
首次出现位置的指针。 - 查找失败情况
- 一般失败:如果在主字符串
haystack
中没有找到子字符串needle
,函数返回NULL
。 - 特殊情况:如果
needle
是一个空字符串(即只包含'\0'
),函数返回haystack
本身。
- 一般失败:如果在主字符串
十四、strspn
函数
1. 函数原型
size_t strspn(const char *s, const char *accept);
2. 参数解释
s
- 类型:指向要进行检查的字符串的指针,该字符串必须以
'\0'
结尾。
- 类型:指向要进行检查的字符串的指针,该字符串必须以
accept
- 类型:指向包含允许字符的字符串的指针,该字符串同样必须以
'\0'
结尾。
- 类型:指向包含允许字符的字符串的指针,该字符串同样必须以
3. 返回值
- 返回值类型:
size_t
类型,代表返回字符串s
中从开头开始连续包含accept
字符串中任意字符的字符数量。
4. 工作原理
strspn
函数从字符串s
的开头开始,逐个检查字符。只要当前字符存在于accept
字符串中,就继续检查下一个字符,并计数。一旦遇到不在accept
字符串中的字符,计数停止,函数返回之前统计的字符数量。
十五、strcspn
函数
1. 函数原型
size_t strcspn(const char *s, const char *reject);
2. 参数解释
s
- 类型:指向要进行检查的目标字符串的指针,该字符串必须以
'\0'
结尾。
- 类型:指向要进行检查的目标字符串的指针,该字符串必须以
reject
- 类型:指向包含要排除字符的字符串的指针,此字符串同样需以
'\0'
结尾。
- 类型:指向包含要排除字符的字符串的指针,此字符串同样需以
3. 返回值
- 返回值类型:
size_t
类型,代表返回字符串s
中从开头开始连续不包含reject
字符串中任意字符的字符数量。
4. 工作原理
strcspn
函数从字符串s
的起始位置开始,逐个检查字符。只要当前字符不在reject
字符串中,就继续检查下一个字符,并对字符数量进行计数。一旦遇到reject
字符串中包含的字符,计数停止,函数返回之前统计的字符数量。
5. 用处
用来检验输入的字符串是否合法,判断有没有违规字符。
十六、示例代码总结
- 基本操作示例
- 通过
strcpy_s
、strcat_s
、sprintf_s
等函数的示例,展示了字符串的复制、连接和格式化输出操作。 - 示例代码如下:
#include <stdio.h> #include <string.h> int main() { char dest[20]; const char *src = "Hello, World!"; // 使用strcpy_s进行字符串复制 errno_t err = strcpy_s(dest, sizeof(dest), src); if (err == 0) { printf("复制成功: %s\n", dest); } else { printf("复制失败,错误码: %d\n", err); } char dest2[20] = "Hello, "; const char *src2 = "World!"; // 使用strcat_s连接字符串 errno_t result = strcat_s(dest2, sizeof(dest2), src2); if (result == 0) { printf("连接后的字符串: %s\n", dest2); } else { printf("错误: 无法连接字符串\n"); } char buffer[20]; int num = 42; const char *str = "Hello"; // 使用sprintf_s进行格式化输出 err = sprintf_s(buffer, sizeof(buffer), "Number: %d, String: %s", num, str); if (err == 0) { printf("格式化成功: %s\n", buffer); } else { printf("格式化失败,错误码: %d\n", err); } return 0; }
- 通过
- 字符串比较示例
- 使用
strcmp
和strncmp
函数的示例,展示了字符串的比较操作,包括按字典序比较和指定字符数的比较。 - 示例代码如下:
#include <stdio.h> #include <string.h> int main() { const char *str1 = "apple"; const char *str2 = "banana"; const char *str3 = "apple"; int result1 = strcmp(str1, str2); int result2 = strcmp(str1, str3); if (result1 < 0) { printf("'%s' 在字典序上小于 '%s'\n", str1, str2); } else if (result1 > 0) { printf("'%s' 在字典序上大于 '%s'\n", str1, str2); } else { printf("'%s' 等于 '%s'\n", str1, str2); } if (result2 < 0) { printf("'%s' 在字典序上小于 '%s'\n", str1, str3); } else if (result2 > 0) { printf("'%s' 在字典序上大于 '%s'\n", str1, str3); } else { printf("'%s' 等于 '%s'\n", str1, str3); } const char *str4 = "apple"; const char *str5 = "applesauce"; const char *str6 = "banana"; // 比较前3个字符 int result3 = strncmp(str4, str5, 3); int result4 = strncmp(str4, str6, 3); if (result3 == 0) { printf("'%s' 和 '%s' 的前3个字符相同\n", str4, str5); } else { printf("'%s' 和 '%s' 的前3个字符不同\n", str4, str5); } if (result4 < 0) { printf("'%s' 的前3个字符在字典序上小于 '%s' 的前3个字符\n", str4, str6); } else if (result4 > 0) { printf("'%s' 的前3个字符在字典序上大于 '%s' 的前3个字符\n", str4, str6); } else { printf("'%s' 和 '%s' 的前3个字符相同\n", str4, str6); } return 0; }
- 使用
- 字符串查找示例
- 通过
strchr
、strrchr
和strstr
函数的示例,展示了在字符串中查找特定字符和子字符串的操作。 - 示例代码如下:
#include <stdio.h> #include <string.h> int main() { const char *str = "Hello, World!"; char target = 'o'; char *result = strchr(str, target); if (result!= NULL) { printf("字符 '%c' 首次出现在字符串中的位置是: %ld\n", target, result - str); } else { printf("在字符串中未找到字符 '%c'\n", target); } const char *str7 = "Hello, World!"; char ch = 'o'; // 查找字符 'o' 最后一次出现的位置 char *result2 = strrchr(str7, ch); if (result2!= NULL) { printf("找到字符 '%c',位置在: %ld\n", ch, result2 - str7); printf("从该位置开始的子字符串: %s\n", result2); } else { printf("未找到字符 '%c'\n", ch); } const char *haystack = "Hello, World! This is a test."; const char *needle = "World"; char *result3 = strstr(haystack, needle); if (result3!= NULL) { printf("子字符串 '%s' 首次出现在主字符串中的位置是: %ld\n", needle, result3 - haystack); } else { printf("在主字符串中未找到子字符串 '%s'\n", needle); } return 0; }
- 通过
- 字符串子串提取示例
strspn
和strcspn
函数的示例,展示了提取字符串中特定字符子集和排除特定字符子集的功能。- 示例代码如下:
#include <stdio.h> #include <string.h> int main() { const char *s = "123abc456"; const char *accept = "1234567890"; size_t result = strspn(s, accept); printf("字符串 '%s' 开头连续包含 '%s' 中字符的长度是: %zu\n", s, accept, result); const char *s2 = "abcdef123"; const char *reject = "1234567890"; size_t result2 = strcspn(s2, reject); printf("字符串 '%s' 开头连续不包含 '%s' 中字符的长度是: %zu\n", s2, reject, result2); char input[] = "filaname.txt"; char invaliChars[] = "/\\:*?\"<>|"; if (strcspn(input, invaliChars) < strlen(input)) { printf("Input contains invalid characters.\n"); } else { printf("Input is valid.\n"); } return 0; }
- 字符串分割示例
strtok_s
函数的示例,展示了字符串的分割操作,将一个字符串按照指定的分隔符分割成多个子字符串。- 示例代码如下:
#include <stdio.h> #include <string.h> int main() { char str[] = "Hello,World,How,Are,You"; char *token; char *context = NULL; // 第一次调用strtok_s分割字符串 token = strtok_s(str, ",", &context); while (token!= NULL) { printf("%s\n", token); // 后续调用strtok_s继续分割字符串 token = strtok_s(NULL, ",", &context); } return 0; }
from micro_frank