规定:
C语言库函数如果出现运行错误,会将对应错误信息的错误码保存到全局变量errno(头文件为errno.h)中.
我们先来看strerror函数的原型:
char *strerror( int errnum );
向函数传入错误代码,他可以将错误码翻译为错误信息并将信息字符串的首元素地址返回。
这里我们引入文件管理的函数来演示strerror函数的效果:
FILE *fopen( const char *filename, const char *mode );
如果打开文件成功则返回有效的指针,否则返回空指针。
演示代码如下:
#include
int main()
{
//打开文件
FILE* pf = fopen("test.txt", "r");//只读文件
if (pf == NULL)
{
printf("%s\n", strerror(errno));
return 1;
}
fclose(pf);//关闭文件
return 0;
}
在我创建的项目下并没有test.txt,这个错误会转换为错误码并且存在errno变量中,strerror函数则可以解析这个错误码。
打印结果如下:
除strerror函数外还要介绍一个函数:perror直接打印错误信息,打印之前会先打印自定义信息(头文件stdio)。
对比上文:
int main()
{
//打开文件
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fclose(pf);
return 0;
}
在之前我们学习过strcpy和strncpy函数,他们是专门针对字符串拷贝的函数。而其他类型则不能使用,为了能够拷贝多种数据类型,C语言有这样的内存函数memcpy,memcpy函数则是以字节为单位拷贝数据。
函数原型:
void *memcpy( void *dest, const void *src, size_t count );
注意事项:
void* my_memcpy(void* p1, const void* p2, size_t num)
{
assert(p1 && p2);
void* ret = p1;
while (num--)
{
*(char*)p1 = *(char*)p2;
p1 = (char*)p1 + 1;
p2 = (char*)p2 + 1;
}
}
int main()
{
int arr1[] = { 1,2,9,4,8 };
int arr2[20] = { 0 };
my_memcpy(arr2, arr1, 12);
return 0;
}
函数原型:
void *memmove( void *dest, const void *src, size_t count );
注意事项:
void* my_memmove(void* p1, const void* p2, size_t num)
{
void* ret = p1;
if (p2 > p1)//前--->后
{
while (num--)
{
*(char*)p1 = *(char*)p2;
p1 = (char*)p1 + 1;
p2 = (char*)p2 + 1;
}
}
else//后--->前
{
while (num--)
{
*((char*)p1 + num) = *((char*)p2 + num);
}
}
return ret;
}
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9};
int arr2[20] = { 0 };
my_memmove(arr1, arr1 + 2, 16);
return 0;
}
讲解内存对齐之前我们先看一个小问题:
#include
struct AB{
int a;
char b;
short c;
short d;
};
int main()
{
printf("%d\n", sizeof(struct AB));
return 0;
}
上面的代码结果是多少,很多人会这样算:4+1+2+2=9.
但是其实结果是:
这里就需要学习关于结构体的内存对齐问题,结构体在内存的存储并不是想数组那样连续的内存存放。而是与编译环境的对齐数有关而且结构体在内存中的存放有偏移量的概念偏移量从起始地址开始从0开始一字节加一。
有如下规定:
举几个例子: