【C语言进阶】内存函数和结构体内存对齐

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

目录

一.strerror函数

1.错误码变量errno

规定:
C语言库函数如果出现运行错误会将对应错误信息的错误码保存到全局变量errno头文件为errno.h中.

2.strerror函数的使用

我们先来看strerror函数的原型:

char *strerror( int errnum );

向函数传入错误代码他可以将错误码翻译为错误信息并将信息字符串的首元素地址返回
这里我们引入文件管理的函数来演示strerror函数的效果

FILE *fopen( const char *filename, const char *mode );

如果打开文件成功则返回有效的指针否则返回空指针。
演示代码如下

#include <errno.h>

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函数则可以解析这个错误码。
打印结果如下
在这里插入图片描述

3.perror函数

除strerror函数外还要介绍一个函数perror直接打印错误信息打印之前会先打印自定义信息头文件stdio。
对比上文

int main()
{
	//打开文件
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	fclose(pf);

	return 0;
}

在这里插入图片描述

二.memcpy函数

1.函数介绍

在之前我们学习过strcpy和strncpy函数他们是专门针对字符串拷贝的函数。而其他类型则不能使用为了能够拷贝多种数据类型C语言有这样的内存函数memcpymemcpy函数则是以字节为单位拷贝数据。
函数原型:

void *memcpy( void *dest, const void *src, size_t count );

注意事项:

  1. 函数memcpy从src的位置开始向后复制count个字节的数据到dest的内存位置.
  2. 这个函数在遇到 ‘\0’ 的时候并不会停下来。(因为不是字符串函数
  3. 如果dest和src有任何的重叠则可能会出现错误。

2.模拟实现

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;
}

三.memmove函数

1.函数介绍

函数原型

void *memmove( void *dest, const void *src, size_t count );

注意事项

  1. 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的
  2. 如果源空间和目标空间出现重叠就得使用memmove函数处理。
2.模拟实现
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 <stdio.h>

 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开始一字节加一
有如下规定

  1. 结构体的第一个成员对齐到结构体在内存中存放位置的0偏移处
  2. 从从第二个成员开始每个成员都要对齐到(一个对齐数) 的整数倍处对齐数: 结构体成员自身大小和默认对齐数的较小值默认对齐
  3. 结构体的总大小必须是所有成员的对齐数中最大对齐数的整数倍
  4. 如果结构体中嵌套了结构体成员要将嵌套的结构体成员对齐到自己的成员中最大对齐数的整数倍处。结构体的总大小必须是最大对齐数整数倍这里的最大对齐数是: 包含嵌套结构体成员中的对齐数的所有对齐数中的最大值。

举几个例子

eg1对齐数为4的环境下
在这里插入图片描述
eg2对齐数为8的环境下
在这里插入图片描述

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6