首先我想说下为啥我会在这里讲内存分布这一概念呢,因为在实际应用场景中,我们其实常常会遇到内存如何分配的问题,举个例子,在程序中定义的变量,程序会自动为这些变量分配内存空间,并且如果清楚内存分布后,会对后面学习操作系统有所帮助。
并且在讲解内存分布之前,我想先引入几个概念,分别如下:
作用域: 指的是变量起作用的范围,即在程序运行中,该变量的作用时间周期。
普通局部变量: 一般是 在{}
范围之内定义的变量,该变量的作用域一般是在定义变量的{}
之内有效。生命周期是程序运行至变量定义处开辟空间,所在的函数结束之后释放空间。
静态局部变量: 在{}
范围之内定义的变量,前面加上static
修饰变量。 该变量的作用域一般是在定义变量的{}
之内有效。生命周期是执行main
函数之前就已经开辟空间,程序结束之后才释放空间。
全局变量: 在函数之外定义的变量。 该变量的作用域是整个工程,所有文件。生命周期是执行main
函数之前就已经开辟空间,程序结束之后才释放空间。
静态全局变量: 在函数之外定义的变量 ,加上static
修饰的变量。该变量的作用域是当前文件。生命周期是执行main
函数之前就已经开辟空间,程序结束之后才释放空间。
静态函数: 在函数定义时加上static
修饰的函数,静态函数只可以被当前文件函数调用。
那在之前我们也讲到了程序里的这些变量都会提前内存分配好,那这些变量的内存分布具体是什么样子的呢?为了让大家更加直观的理解,特意画了一张图供大家观看。
首先假如我们在程序中有这么一段代码,定义了不同类型的代码,代码如下:
int e;
static int f;
int g= 10;
static int h = 10;
int main ()
{
int a;
int b = 10;
static int c;
static int d = 10;
char *i = "test";
char *k = NULL;
}
“test”
,所以就会存放在文字常量区。bss
区。另一部分是初始化的静态全局,一般称之为data
区。同时静态全局一般包括普通静态局部变量、全局变量和静态全局变量。在上述代码中,变量g
是在函数{}
外面定义的,所以为全局变量,变量h
也是在函数{}
外面定义的,并且前面加了关键字static
,所以为静态全局变量。变量d
是在函数{}里面定义的,并且前面加了关键字static
,所以为普通静态局部变量。同时变量g
,h
,d
都是已近初始化的值,值为10
。e
,f
,c
都是未初始化的变量,所以就放在了bss
区。malloc
函数来申请堆区空间。具体使用方法会在下一讲中提到,敬请关注。1.memset函数:
#include
void *memset(void *s, int c, size_t n);
功能:将s的内存区域的前n个字节以参数c填入
参数:
s:需要操作内存s的首地址
c:填充的字符,c虽然参数为int,但必须是unsigned char , 范围为0~255
n:指定需要设置的大小
返回值:s的首地址
举个例子:
int main()
{
int a = 10;
memset(&a,0,sizeof(a));
printf("a=%d\n",a);
system("pause");
return 0;
}
运行结果如下:
对上述代码分析如下:
首先我们定义了一个整型变量a
,并且赋值为10
。此时我们想要通过memset
函数来修改a
的值为0
。从上述的memset
函数的定义说明来看,需要操作的内存地址为&a
,填充的字符为0
,并且需要设置的大小为a
的字节大小。并且字节大小为sizeof(a)
。
2.memcpy函数:
#include
void *memcpy(void *dest, const void *src, size_t n);
功能:拷贝src所指的内存内容的前n个字节到dest所值的内存地址上。
参数:
dest:目的内存首地址
src:源内存首地址,注意:dest和src所指的内存空间不可重叠,可能会导致程序报错
n:需要拷贝的字节数
返回值:dest的首地址
举个例子:将数组a
中前5
个元素拷贝至数组b
中
int main()
{
int a[10] = {1,2,3,4,5,6,7,8,9,10};
int b[10] = { 0 };
memcpy(b,a,sizeof(int)*5);
for (int i = 0; i < sizeof(b) / sizeof(b[0]); i++)
{
printf("%d ",b[i]);
}
system("pause");
return 0;
}
对上述代码分析如下:
在这里想要特别说明memcpy(b,a,sizeof(int)*5);
这个部分,如果我们把这个函数部分需要拷贝的字节数修改成5
会怎样,结果如下:
结果如上所述,结果并不是我们想要的结果。因为我们定义的数组a
的数组类型为int
类型。int
类型的字节大小是4
个字节,所以最多也就能打印数组a
中的1
和2
。所以如果我们想要使用memcpy
函数将将数组a
中前5
个元素拷贝至数组b
中,所以自然而然需要拷贝的总字节数为4* 5 = 20
。那正如上述分析,我们再次试试,如果我们把这个函数部分需要拷贝的字节数修改成20
会怎样,结果如下:
3.memcmp函数:
#include
int memcmp(const void *s1, const void *s2, size_t n);
功能:比较s1和s2所指向内存区域的前n个字节
参数:
s1:内存首地址1
s2:内存首地址2
n:需比较的前n个字节
返回值:
相等:=0
大于:>0
小于:<0
举个例子:
int main()
{
char num1[] = {
1,0,3,4,5,6,7 };
char num2[] = {
1,0,3,6,5,6,7 };
printf("%d\n", memcmp(num1,num2,7*sizeof(char)));
system("pause");
return 0;
}
如果觉得这篇文章还不错的话,记得点赞 ,支持下!!!