上一篇文章讲了长度受限制的字符串函数介绍
strncpy
strncat
strncmp
以及字符串查找的两个函数
strstr
strtok
今天这篇这个文章就是这个系列的完结了,接下去的是动态内存管理和结构体的内容,后面就转到用c语言的初阶数据结构了。
strerror
strerror 是 C 语言标准库中的一个函数,用于将系统错误码转换为相应的错误消息字符串。这个函数在处理系统调用返回的错误码时非常有用,因为它可以提供更具可读性的错误信息。
一眼看过去,是不是懵了,什么意思啊,系统错误码不就是我们之前写代码编译的时候的运行的时候的报错吗,为什么要转化为字符串错误消息呢?我们首先分析一下他的输入和输出
char *strerror(int errnum);
errnum:要转换的系统错误码,通常是通过 errno 变量获取的。
返回值的话是返回指向包含错误消息的字符串的指针。
也就是说,strerror这个函数要同时完成捕获和显示错误信息这两个操作,那我们上代码探索一下。
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>//必须包含的头文件
#include <string.h>
int main() {
FILE *file;
const char *filename = "nonexistent_file.txt";
// 尝试打开一个不存在的文件
file = fopen(filename, "r");
if (file == NULL) {
// 获取并打印错误信息
perror("Error opening file");
printf("Error number: %d\n", errno);
printf("Error message: %s\n", strerror(errno));
} else {
// 如果文件成功打开,关闭文件
fclose(file);
}
return 0;
}
那他到底返回什么呢?
如果nonexistent_file.txt 文件不存在,输出可能如下:
Error opening file: No such file or directory
Error number: 2
Error message: No such file or directory
什么意思呢?
打开文件时出错: No such file or directory
错误号: 2
错误信息: No such file or directory 无此文件或目录
所以就要比我们去调试运行的时候更加明确错误出在哪里,还有一个就是系统调用和库函数通常返回错误码(存储在 errno 中),这些错误码是整数,对开发者来说是不够直观的。或者说,如果你不用他也是可以的,只不过系统报错的时候就不会这么简洁了,而是一长串的错误码,如果你记不住,还得去查,那么用一下strerror就会很轻松,也方便自己代码的调试。
好,我们来拓展一下字符的分类
字符分类函数
看着就通俗易懂,也很好记,就拆分为is和后缀去记。,这里我们再用isupper来举个例子。
/* isupper example */
#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;
}
这里我把思路放一下,还要注意一下使用的头文件不能省略。
定义一个整数变量 i 作为索引。
定义一个字符数组 str,包含要处理的字符串 "Test String.\n"。
定义一个字符变量 c 用于存储当前字符。
使用 while (str[i]) 循环遍历字符串,直到遇到空字符 \0。
将当前字符 str[i] 赋值给 c。
使用 isupper(c) 检查 c 是否是大写字母。
如果是大写字母,使用 tolower(c) 将其转换为小写字母。
使用 putchar(c) 输出当前字符。
增加索引 i,继续处理下一个字符。
memcpy
memcpy 是 C 语言标准库中的一个函数,用于将一块内存的内容复制到另一块内存。它是一个非常基础且常用的内存操作函数,适用于各种数据类型的内存复制。
void *memcpy(void *dest, const void *src, size_t n);
dest:指向目标内存区域的指针。
src:指向源内存区域的指针。
n:要复制的字节数。
返回指向目标内存区域 dest 的指针。
include <stdio.h>
#include <string.h>
int main() {
char src[] = "Hello, World!";
char dest[50];
// 使用 memcpy 复制字符串
memcpy(dest, src, sizeof(src));
// 打印结果
printf("Source: %s\n", src); // 输出: Source: Hello, World!
printf("Destination: %s\n", dest); // 输出: Destination: Hello, World!
return 0;
}
这里比较简单就过一下,我们这里照样要注意一下。
memcpy 会从 src 指向的内存区域复制 n 个字节到 dest 指向的内存区域。
如果 dest 和 src 有重叠的内存区域,memcpy 的行为是未定义的。
在这种情况下,应该使用 memmove 函数。
memmove
和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
如果源空间和目标空间出现重叠,就得使用memmove函数处理。
void *memmove(void *dest, const void *src, size_t n);
基本都和memcpy一样,那接下来我们就看看memmove是怎么正确处理重复的空间的。
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "Hello, World!";
size_t len = strlen(str) + 1; // 包括结尾的空字符
// 将字符串向前移动 7 个字节
memmove(str, str + 7, len - 7);
// 打印结果
printf("Modified string: %s\n", str); // 输出: Modified string: World!
return 0;
}
在这里看到memmove(str, str + 7, len - 7) 将 str 从第 8 个字符开始的部分向前移动 7 个字节,覆盖前面的字符。但是我还是不懂怎么办,那我们来模拟实现一下。
void *my_memmove(void *dest, const void *src, size_t n) {
char *d = (char *)dest;
const char *s = (const char *)src;
// 检查是否需要从后向前复制
if (d < s) {
// 从前向后复制
for (size_t i = 0; i < n; ++i) {
d[i] = s[i];
}
} else {
// 从后向前复制
for (size_t i = n; i > 0; --i) {
d[i - 1] = s[i - 1];
}
}
return dest;
}
这里我们就可以得出
内存重叠处理方法
从前向后复制:如果 src 的地址小于 dest 的地址(即 src 在 dest 之前),则从前往后复制。
从后向前复制:如果 src 的地址大于或等于 dest 的地址(即 src 在 dest 之后或与 dest 重叠),则从后往前复制。
memcmp
再来看这个
memcmp 是 C 语言标准库中的一个函数,用于比较两个内存区域的内容。它逐字节比较两个内存区域,并返回它们之间的差异。memcmp 可以用于比较任意类型的数据,只要你知道要比较的字节数。
int memcmp(const void *s1, const void *s2, size_t n)
s1:指向第一个内存区域的指针。
s2:指向第二个内存区域的指针。
n:要比较的字节数。
返回值
如果 s1 和 s2 的前 n 个字节完全相同,返回 0。
如果 s1 的前 n 个字节小于 s2 的前 n 个字节(即 s1 中的第一个不同字节的值小于 s2 中对应字节的值),返回一个负数。
如果 s1 的前 n 个字节大于 s2 的前 n 个字节(即 s1 中的第一个不同字节的值大于 s2 中对应字节的值),返回一个正数。
老规矩上代码
/* memcmp example */
#include <stdio.h>
#include <string.h>
int main ()
{
char buffer1[] = "DWgaOtP12df0";
char buffer2[] = "DWGAOTP12DF0";
int n;
n=memcmp ( buffer1, buffer2, sizeof(buffer1) );
if (n>0) printf ("'%s' is greater than '%s'.\n",buffer1,buffer2);
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;
}
好了,写到这想必你也看累了,如果你能看到这里的话,真的很感谢你,同时你真的很棒,因为这些东西真的很枯燥,感谢你们的付出。这个系列到这里就完结了。我们下一篇文章见。