一.数据类型本质分析
1. 数据类型的概念
2. 数据类型的本质
-
数据类型可理解为创建变量的模具(模子); 是固定内存大小的别名。 -
数据类型的作用: 编译器预算对象(变量)分配的内存空间大小 -
程序举例,如何求数据类型的大小 sizeof(int *) ? 请问: 数据类型可以有别名吗?数据类型可以自定义吗?
3. 数据类型大小
int main()
{
int a = 10;
int b[10] ;
printf("int a:%d \n", sizeof(a))
;
printf("int a:%d \n", sizeof(int *))
;
printf("int b:%d \n", sizeof(b))
;
printf("int b:%d \n", sizeof(b[0]))
;
printf("int b:%d \n", sizeof(*b))
;
printf("hello...\n")
;
getchar()
;
return 0;
}
sizeof是操作符,不是函数; sizeof测量的实体大小为编译期间就已确定
4. 数据类型别名
用typedef
5. 数据类型的封装
int InitHardEnv(void **handle);
典型的如内存操作函数memcpy和memset的函数原型分别为
void * memcpy(void *dest, const void *src, size_t len);
void * memset ( void * buffer, int c, size_t num );
- 3、用法2:void修饰函数返回值和参数,仅表示无。
如果函数没有返回值,那么应该将其声明为void 型 如果函数没有参数,应该声明其参数为void
int function(void)
{return 1;}
- 4、void指针的意义
C语言规定只有相同类型的指针才可以相互赋值 void* 指针作为左值用于“接收”任意类型的指针 void* 指针作为右值赋值给其它指针时需要强制类型转换
int *p1 = NULL;
char *p2 = (char *)malloc(sizoeof(char)*20);
- 5、不存在void类型的变量
C语言没有定义void究竟是多大内存的别名
6. 数据类型总结与扩展
二、变量本质分析
2.1 变量概念
- 概念:
既能读又能写的内存对象,称为变量; 若一旦初始化后不能修改的对象则称为常量。 - 变量定义形式:
类型 标识符, 标识符, … , 标识符 ; - 例如:
int x ;
int wordCut ,Radius , Height;
double FlightTime , Mileage , Speed;
2.2 变量本质
-
程序通过变量来申请和命名内存空间 int a = 0 -
通过变量名访问内存空间 (一段连续)内存空间的别名(是一个门牌号) -
修改变量有几种方法? 1、直接 2、间接。内存有地址编号,拿到地址编号也可以修改内存; 于是横空出世了!(编程案例)
int main()
{
通过变量直接操作内存
通过内存编号操作内存
int i = 0;
printf("&i:%d\n", &i)
;
*((int *)
(1245024)) = 10;
printf("i:%d", i);
printf("hello....\n");
getchar();
return 0;
}
3、内存空间可以再取给别名吗?
- 数据类型和变量的关系
?通过数据类型定义变量 - 总结
1 对内存,可读可写; 2 通过变量往内存读写数据; 3 不是向变量读写数据,而是向变量所代表的内存空间中写数据。
问: 变量跑哪去了? 思考1: 变量三要素(名称、大小、作用域),变量的生命周期? 思考2: C++编译器是如何管理函数1,函数2变量之间的关系的? ====》 引出两个重要话题:
三、程序的内存四区模型
3.1 内存四区的建立流程
流程说明
- 操作系统把物理硬盘代码load到内存
- 操作系统把c代码分成四个区
- 操作系统找到main函数入口执行
各区元素分析
静态存储区(全局区)案例
void main(){
char buf[100];
int a = 10;
int *p;
p = &a;
*p = 20;
{
char *p = NULL;
p = (char *)malloc(100);
if (p != NULL){
free(p);
}
}
system("pause");
}
全局区代码测试
char * getstring1(){
char *p1 = "abcde";
return p1;
}
char * getstring2(){
char *p2 = "abcde";
return p2;
}
void main()
{
int i= 0;
char *p1 = getstring1();
char *p2 = getstring2();
char ******* p3 = NULL;
strcmp(p1, p2);
system("pause");
}
指针指向谁就把谁的地址赋给指针 指针变量 和 它所指向的内存空间变量是两个不同的概念
堆栈案例
char *getMun(int num){
char *p1=NULL;
p1=(char*)malloc(sizeof(char)*num);
if(p1==NULL)return NULL;
retrun p1;
}
char *getMum2(){
char buf[64];
strcpy(buf,"123456");
return buf;
}
void main(){
char *tep = NULL;
tep = getMum(10);
if(tmp == NULL)return;
strcpy(tmp,"111111");
tmp = getMem2();
printf("tmp:%s \n",tmp);
return;
}
如何改正呢?
return不是把内存块64个字节给return出来,而是把内存块的首地址(内存的编号如0xaa11),返回给tmp
char *getMum2(){
char buf[64];
strcpy(buf,"123456");
printf("buf:%s\n",buf);
return buf;
}
void main(){
char *tep = NULL;
tep = getMum(10);
if(tmp == NULL)return;
strcpy(tmp,"111111");
tmp = getMem2();
return;
}
理解指针的关键是内存,没有内存哪来的指针
栈的属性和buf的内存生长方向
一般栈开口向下
不管栈向上还是向下,一般buf的内存地址buf+1永远是向上的
四、函数调用模型
4.1 主调函数和被调用函数
4.2 内存四区模型和函数调用模型变量传递分析
- 一个主程序有 n 函数组成,c++编译器会建立有几个堆区?有几个栈区?
- 函数嵌套调用时,实参地址传给形参后,C++编译器如何管理变量的生命周期?
分析:函数 A,调用函数 B,通过参数传递的变量(内存空间能用吗?)
4.3 提示学好 C 语言的关键
4.4 如何建立正确的程序运行内存布局图
? 内存四区模型&函数调用模型 ? 函数内元素
? 函数间
- 主调函数分配内存,还是被调用函数分配内存
- 主调函数如何使用被调用函数分配的内存(技术关键点:指针做函数参数)
======》学习指针的技术路线图
五、内存四区强化训练
01 全局区训练
? char *p1= “abcdefg”;
02 堆栈区生命周期训练
? Char p1[]= “abcdefg”; ? 返回基本类型 ? 返回非基本类型
03 堆栈属性训练
? 测试 heap 生长方向 ? 测试 stack 生长方向
- Heap、stack 生长方向和内存存放方向是两个不同概念
- 野指针
- Malloc 得到指针释放问题测试
? free( p ) ? free(p+1),深入理解
六、作业强化
训练 1 划出内存四区
|