目录
一、动态内存管理
1.malloc
2.free
3.内存泄漏
4.calloc
5.realloc
二、C语言的内存布局规律
三、高级宏定义?
1.不带参数的宏定义
2.带参数的宏定义
一、动态内存管理
- malloc:申请动态内存空间
- free:释放动态内存空间
- calloc:中请并初始化一条列内存空间
- realloc:重新分配内存空间
1.malloc
- 函数原型:void *malloc (size_t size);
- malloc函数向条统申请分配 size 个字节的内存空间,并返回一个指向这块空间的指针。
- 如果函数调用成功,返回一个指向申请的内存空间的指针,由于返回类型是 void 指针(void*),所以它可以被转换成任何类型的数据;如果函数调用失败,返回值是NULL。另外,如果size参数设置为0,返回值也可能是NULL,但这并不意味着函数调用失败。
代码举例:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *ptr;
ptr = (int *)malloc(sizeof(int));
if(ptr == NULL)
{
printf("分配内存失败!\n");
exit(1);
}
printf("请输入一个整数:");
scanf("%d",ptr);
printf("你输入的整数是:%d\n",*ptr);
return 0;
}
运行结果:
- 初始化内存空间:以mem开头的函数被编入字符串标准库,函数的声明包含在string.h这个头文件中:(memset;-使用一个帝量字节填充内存空间;memcpy:拷贝内存空间;memmove:拷贝内存空间;memcmp:比较内存空间;memchr:在内存空间中搜秦一个字符。)
代码举例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 10
int main(void)
{
int *ptr = NULL;
int i;
ptr = (int *)malloc(N * sizeof(int));
if(ptr == NULL)
{
exit(1);
}
memset(ptr, 0, N * sizeof(int));
for(i = 0;i < N;i++)
{
printf("%d ",ptr[i]);
}
putchar('\n');
free(ptr);
}
运行结果:
?
2.free
- 函数原型:void free (void *ptr);
- free函数释放ptr参数指向的内存空间。该内存空间必须是由malloc、calloc或realloc函教申请的。否则,该函数将导致未定义行为。如果ptr参数是NULL,则不执行任何操作。注意:该函数并不会修改ptr参数的值,所以调用后它仍然指向原来的地方(变为非法空间)。
3.内存泄漏
- 隐式内存泄漏(即用完内存块没有及时使用free函数释放)
- 丢失内存块地址
4.calloc
- 函数原型:void *calloc (size_t nmemb,size_t size);
- calloc函数在内存中动态地申请nmemb个长度为size的连续内存空间(即申请的总空间尺寸为nmemb *size),这些内存空间全部被初始化为0。
- calloc函数与malloc函数的一个重要区别是:calloc函数在申请完内存后,自动初始化该内存空间为零;malloc函数不进行初始化操作,里边数据是随机的。
- 下面两种写法是等价的:
?代码举例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
int *ptr1 = NULL;
int *ptr2 = NULL;
//第一次申请的内存空间
ptr1 = (int *)malloc(10 * sizeof(int));
//进行若干操作之后发现ptr1申请的内存空间竟然不够用!
//第二次申请的内存空间
ptr2 = (int *)malloc(20 * sizeof(int));
//将ptr1的数据拷贝到ptr2中
memcpy(ptr2,ptr1,10);
free(ptr1);
//对ptr2申请的内存空间进行若干操作…
free(ptr2);
return 0;
}
5.realloc
- 函数原型:void *realloc(void *ptr,size_t size);
- realloc函数修改ptr指向的内存空间大小为size字节;
- 如果新分配的内存空间比原来的大,则旧内存块的数据不会发生改变;如果新的内存空间大小小于旧的内存空间,可能会导致数据丢失,慎用!
- 该函数将移动内存空间的数据并返回新的指针;
- 如果ptr参数为NULL,那么调用该函数就相当于调用malloc(size);
- 如果size参数为0,并且ptr参数不为NULL,那么调用该函数就相当于调用free(ptr);
- 除非ptr参数为NULL,否则ptr的值必须由先前调用malloc、calloc或realloc函数返回。
代码举例:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int i,num;
int count = 0;
int *ptr = NULL;//这里必须初始化为NULL
do
{
printf("请输入一个整数(输入-1表示结束):");
scanf("%d",&num);
count++;
ptr = (int *)realloc(ptr,count * sizeof(int));
if(ptr == NULL)
{
exit(1);
}
ptr[count-1] = num;
}while(num != -1);
printf("输入的整数分别是:");
for(i = 0;i < count;i++)
{
printf("%d ",ptr[i]);
}
putchar('\n');
free(ptr);
return 0;
}
运行结果:
二、C语言的内存布局规律
?
- 代码段(Text segment)通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。
- 数据段(Initialized data segment)通常用来存放已经初始化的全局变量和局部静态变量。
- BSS段(Bss segment/Uninitialized data segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。BSS是英文Block Started by Symbol的简称,这个区段中的数据在程序运行前将被自动初始化为数字0。
- 堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩展或缩小。当进程调用malloc等玉数分配内存时,新分配的内存就被动态添加到堆上;当利用free等函数释放内存时,被释放的内存从堆中被剔除。
- 栈是函数执行的内存区域,通常和堆共享同一片区域。
堆和栈的区别:
(1)申请方式:
(2)释放方式:
(3)生存周期:
- 堆的生存周期由动态申请到程序员主动释放为止,不同函数之间均可自由访问
- 栈的生存周期由函数调用开始到函数返回时结束,函数之间的局部变量不能互相访问
(4)发展方向:
- 堆和其它区段一样,都是从低地址向高地址发展
- 栈则相反,是由高地址向低地址发展
代码举例:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int *ptr1 = NULL;
int *ptr2 = NULL;
ptr1 = (int *)malloc(sizeof(int));
ptr2 = (int *)malloc(sizeof(int));
printf("stack: %p -> %p\n",&ptr1,&ptr2);
printf("heap: %p -> %p\n",ptr1,ptr2);
return 0;
}
运行结果:
三、高级宏定义?
1.不带参数的宏定义
- 为了和普通的变量进行区分,宏的名字通常我们约定是全部由大写字母组成
- 宏定义只是简单地进行替换,并且由于预处理是在编译之前进行,而编译工作的任务之一就是语法检查,所以编译器不会对宏定义进行语法检查
- 宏定义不是说明或语句,在末尾不必加分号
- 宏定义的作用域是从定义的位置开始到整个程序结束
- 可以用 #undef 来终止宏定义的作用域
- 宏定义允许嵌套
代码举例:
#include <stdio.h>
#define R 6371
#define PI 3.14
#define V PI * R * R * R * 4/3
int main(void)
{
int r;
float s;
printf("请输入圆的半径:");
scanf("%d",&r);
s = PI * r * r;
printf("圆的面积是:%.2f\n",s);
printf("地球的体积大概是:%.2f\n",V);
return 0;
}
运行结果:
2.带参数的宏定义
代码举例:
#include <stdio.h>
#define MAX(x,y)(((x) > (y)) ? (x) : (y))
int main(void)
{
int x,y;
printf("请输入两个整数:");
scanf("%d%d",&x,&y);
printf("%d 是较大的那个数!\n",MAX(x,y));
return 0;
}
运行结果:
|