数据类型的本质:固定大小内存块的别名
- 数组b中b和&b所代表的数据类型不一样
int main(){
int a ;//告诉c编译器分配4个字节的内存
int b[10];//告诉c编译器分类40个字节的内存
printf("b:%d,b+1:%d,&b:%d,&b+1:%d\n",b,b+1,&b,&b+1);
}
image.png
发现b和b+1刚好相差4个字节,但是&b和&b+1相差甚远
b代表的数组首元素的地址
&b代表整个数组的地址
发现b和&b都是数组数据类型,那么,数组数据类型的三个重要指标
数组类型
数组指针
数组类型和数组指针类型的关系
- 数据类型的大小
printf("sizeof(b):%d\n",sizeof(b));
printf("sizeof(a):%d\n",sizeof(a));
image.png
- 数据类型别名
用关键字typedef对数据类型进行重命名
typedef struct Teacher2
{
char name[64];
int age;
}Teacher2;
typedef int u32;
如下图不用typedef就会在数据的使用过程中出错
image.png
变量:既能读又能写的内存对象
变量一旦初始化后不能修改即为常量
变量的本质是内存空间的别名,
- 修改变量的方式:
直接:a = 20
间接:直接通过内存,就是通过指针 p = &a ,*p = 20 ((int)地址)=20 -
变量的生命周期
内存四区
操作流程:
1,操作系统把物理硬盘代码load到内存
2,操作系统把c代码分为四个区
3,操作系统找到main函数入口执行 - 各区元素分析
栈区:由编译器自动分配释放,存放函数的参数值、局部变量的值等
堆区:一般由程序员分配释放(动态内存申请与释放)。若程序员不释放,程序结束时可能由操作系统回收
全局区(静态区):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域,该区域在程序结束后由操作系统释放字符串常量和其他常量的存储位置也在全局区,在程序结束后由操作系统释放。
程序代码区:存放函数体的二进制代码 - 静态存储区的理解
//#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
char * getStr1(){
char *p1 = "abcdefg";
return p1;
}
char *getStr2()
{
char *p2 = "abcdefg2";
return p2;
}
int main()
{
char *p1 = NULL;
char *p2 = NULL;
p1 = getStr1();
p2 = getStr2();
//打印p1和p2内存空间的数据
printf("p1:%s,p2:%s \n",p1,p2);
//打印p1和p2的值
printf("p1:%d,p2:%d \n",p1,p2);
printf("hello...\n");
//system("pause");
//return 0;
}
打印结果如下所示:
image.png
因为p1和p2对应不同的字符串和存储单元,故此时打印出的p1和p2都是不一样。但如果把p1 = "abcdefg2",那么p1和p2指向的值会是一样的嘛?
此时会发现p1和p2的值是一样的。为什么呢?
从内存角度理解:程序从main()开始执行,先执行p1和*p2的初始化。
char *p1 = NULL; char *p2 = NULL;这个过程发生在栈区中,在栈区中分配四个字节给p1,分配四个字节给p2。
char *p1 = "abcdefg2";char *p2 = "abcdefg2";这个过程发生在全局区,因为进入子函数getStr1()和getStr2()中,发现子函数中给p1和p2赋值一个字符串常量,该字符串常量应该放在全局区,所以在使用完子函数getStr1()和getStr2()之后字符串常量不会被直接析构掉,故在主函数中还是可以用的即p1和p2所指向内存空间的值在主函数中是已知的。
ps:此时子函数中又出现p1和p2,和主函数中的p1和p2是不一样的。也放在栈区中,
假设字符串首地址为0xaa11,那么p1的值为0xaa11,返回到主函数中p1的值为0xaa11,对应内存空间的数据为abcdefg。具体示意图如下所示:
内存四区图
- 栈的生长方向和buf的生长方向不是同一个概念,buf的生长方向永远向上,而栈的生长方向因编译器的不同而不同,具体自测。
网友评论