C_Language_11
C_Language_11
//int b1 = 5; //定义在主函数main前的变量存放于静态区,静态变量,作用域为所有文件
void testMemory(){ //存储在代码区
printf("代码区\n");
// printf("%d",b12); //b12在本函数中没有定义
}
在计算机的内存中,可以分为5个区,每个区都有各自的操作以及管理内存的方式
栈、堆、静态(全局)、常量、代码区是按照内存地址从大到小分配
// 打印各个存储区域
// 栈区
int a = 3;//3存放于常量区
// 堆区
int *p = malloc(10);
// 静态(全局)
static int b = 5;
// 常量
char *s = "iphone";
// 函数存储在代码区
printf("栈区:%p\n",&a);
printf("堆区:%p\n",p);
printf("静态:%p\n",&b);
printf("常量:%p\n",s);
printf("代码:%p\n",testMemory);
栈区:函数参数或者是全局变量存储的区域
栈区内存特点:
1.局部变量的存储空间,基本都在栈区,局部变量在函数、循环、分支中定义
2.栈区的存储空间由高到低分配,从低到高存储
3.栈区内存有系统负责分配和回收,开发者没有管理权限。
定义局部变量是由系统分配存储空间,局部变量被销毁时由系统回收存储空间,
但是存储空间中的数据没有被清空
4.当函数、循环、分支执行结束后,局部变量的生命周期结束,不能再被使用,由系统销毁并回收存储空间。
5.栈底、栈顶。栈底是栈区的起始位置,先定义的变量所占用的内存从靠近栈底开始分配,后定义的变量所占用的内存逐渐向栈顶分配
6.入栈、出栈。入栈:定义新的局部变量,分配存储空间;出栈:局部变量被销毁,存储空间被收回
7.栈的特点:先进后出,后进先出
8.栈区会存在安全问题:在函数中返回栈内存是不安全的
int a = 10;//高地址
char b = 'a';
double c = 3.4;//低地址
printf("a的地址:%p\n",&a);//a的地址:0x7fff5fbff7cc 高
printf("b的地址:%p\n",&b);//b的地址:0x7fff5fbff7cb |
printf("c的地址:%p\n",&c);//c的地址:0x7fff5fbff7c0 低
示例:
int a;
printf("a = %d\n",(a=3*5,a*4,a+5));//运行结果20 // 15 60 20 20后存储,先出
printf("a = %d\n",a=3*5,a*4,a+5);//运行结果15
常量区(文字常量区)
常量区的特点:
1.常量存储在常量区。常量 字符串等等
2.常量区存储空间是由系统分配和回收
3.程序运行结束后,常量区的存储空间被收回
4.常量区的数据只能被读取,不能被修改。修改会造成崩溃
char *p = "iphone";
p[0] = "a";//不能被修改,会崩溃
printf("%s",p);
静态区:全局变量和静态变量存储的区域
静态区的特点:
1.全局变量、使用static修饰的局部变量,都存储在静态区。
2.静态区的存储空间由系统分配和回收。
3.程序运行结束后,静态区的存储空间被回收。静态区变量的生命周期跟程序一样长。
4.静态变量只能初始化一次,在编译时进行初始化,
运行期可以修改。
5.静态变量如果没有设置初始值,默认值为0
static int b12 = 8;//静态变量,作用域是本文件,即本函数
代码区:所有语句编译的CPU指令存储的区域
代码区的特点:
1.由系统分配和回收
2.程序结束后,有系统回收分配过的存储空间
3.只能读,不能修改
堆区:由开发工者自主管理的区域(手动开辟,手动释放)
堆区特点:
1.由开发者负责分配和回收
2.忘记回收内存会造成内存泄露
3.程序结束后会回收堆区内存,但是如果不能及时回收堆内存,
程序运行期间可能会因为内存泄露,造成堆内存被全部占用,程序无法运行。
内存分配函数
malloc:
void *malloc(size)
void * 表示的是无类型指针,可以转化为任意类型指针。
函数的作用:在堆区开辟指定size个字节的空间,并把空间的首地址返回。
示例:
int *p = NULL;
p = malloc(sizeof(int));
*p = 4;
printf("%d\n",*p);
示例:
float *p = NULL;
p = malloc(sizeof(float));
*p = 5.4;
printf("%.2f\n",*p);
分配存储空间存储数组元素,即分配多个连续的存储空间
示例:分配1个字符数组的内存,8个元素 ”iphone“
char *p = NULL;
p = malloc(8*sizeof(char));
strcpy(p, "iphone");
printf("%s\n",p);
示例:分配一个整形的数组内存,10个元素,随机产生10个30~60之间的数,存储在分配的内存空间
int *p = NULL;
p = malloc(sizeof(int)*10);
for (int i = 0; i < 10; i++) {
*p = arc4random()%(60-30+1)+30;
printf("%d ",*p);
p++;
}
printf("\n");
typedef struct student{
char name[20];
int age;
}Student;
Student *p12 = malloc(sizeof(Student));
strcpy(p12->name, "hanzheng");
p12->age = 11;
printf("%s %d\n",p12->name,p12->age);
Student *p13 = malloc(sizeof(Student)*2);//结构体数组
释放开辟的空间:
void free(void *):将指定的地址所对应的空间释放
int *r = NULL;
r = malloc(sizeof(int)); //这一块开辟的内存找不到,造成内存泄露
r = malloc(sizeof(int));
printf("%p\n",r);
*r = 10;
printf("%p %d\n",r,*r);
free(r);//开辟空间记得释放,如果不释放,会出现内存问题,内存泄露
r = NULL;//当空间回收之后,将指针置null安全,避免出现野指针,野指针:指针指向不属于自己控制的存储单元
free(r);//内存问题:过度释放
calloc:
void *calloc(int n ,size_t size);//在堆区开辟n*size个字节空间,并把空间地址返回,该函数将空间进行清0操作,在效率上比malloc低
char *str = NULL;
str = (char*)calloc(10,sizeof(char));
strcpy(str, "hello");
printf("string is :%s\n",str);
free(str);
str = NULL;
realloc:
void *realloc(void*p,size_t newSize);在给定的地址空间基础上,如果当前指针空间足够,那么将地址扩大,如果空间不足,那么重新找一块新的地址按照newSize大小分配空间,将原有数据从头到尾拷贝到新分配的内存区域,然后自动释放原来指针指向的内存区域,不需要free
int *p_old = malloc(10);
int *p_new = realloc(p_old,150);
printf("%p\n%p\n",p_old,p_new);
如果返回的地址和新地址不一样。那么系统会将原来的地址进行一次free,对于realloc()操作,我们只需要释放我们新的地址空间即可
free(p_old);//过度释放
free(p_new);
内存操作函数:
memset(:
void *memset(void *p,int c,size_t size)
从给定地址开始size个字节直接重置为c,注意:该函数以字节单位进行操作。主要作用于清0
int *array = malloc(12);
for (int i = 0; i < 3; i++) {
array[i] = i;
printf("%d \n",array[i]);
}
全置为0
memset(array, 0, 12);
printf("\n");
for (int i = 0; i < 3; i++) {
printf("%d \n",array[i]);
}
char *p11 = malloc(10);
memset(p11, 'a', 10);
for (int i = 0; i < 10; i++) {
printf("%c ",p11[i]);
}
memcmp:
int memcmp(void *p,void *q,size_t count);
从给定的两个地址p和q开始比较count个字节,返回第一个不相等字节空间值的差值
int num1[3] = {1,2,3};
int num2[3] = {1,2,9};
int result = memcmp(num1, num2, 9);//运行结果-6
printf("%d\n",result);
memcpy:
void *memcpy(void *dest,const void*source , size_t n);
从指定scorce指向的地址向dest指向的地址单元拷贝n个字节
char wrongName[] = "bJS141148";
char rightName[] = "15";
memcpy(wrongName, "B", 1);
memcpy(wrongName+3, rightName, 2);
printf("%s\n",wrongName);

浙公网安备 33010602011771号