c taskspawn 需要申请堆栈的大小 怎么设置_C提高讲义 程序内存模型

84f14f1833ae709b8514416dd7d1f0a5.gif

1.1.1问题引出

企业需要能干活的人

ØC学到什么程度可以找工作?

Ø 对于C/C++初级开发者,怎么达到企业的用人标准

Ø就业问题 

问:   老师,有没有一个框框?

有没有一个标准啊?

我们学什么哪?

C工程开发需要什么(培养什么能力)

成熟的、商业化的信息系统在分区、分层

a408bc946b8ac0a0e88957f7e72d2288.png

信息系统的技术模型在分层

6a6d848e1e64ec897c72ed0dc692aeeb.png

找出对我们初学者最近的那一层(哪些能力是你入行前,必须要掌握的)

C项目开发的套路(一套接口)

Ø//socket_client pool api 设计与实现

Øint sckClient_poolinit(void **handle);

Øint sckClient_getConnet(void *handle, void **hConnect);

Øint sckClient_sendData(void *hConnect, unsigned char *data, int dataLen);

Øint sckClient_getData(void *hConnect, unsigned char **data, int *dataLen);

Øint sckClient_getData_Free(void *hConnect, unsigned char *data);

Øint sckClient_putConnet(void *handle, void **hConnect);

Øint sckClient_pooldestory(void **handle);

总结:寻找到学习的标准

培养两种能力

Ø接口的封装和设计(功能抽象和封装)

Ø接口api的使用能力

Ø接口api的查找能力(快速上手)

Ø接口api的实现能力

Ø建立正确程序运行内存布局图(印象图)

Ø内存四区模型图

Ø函数调用模型图

1.3内存四区专题讲座

1.3.1数据类型本质分析

数据类型概念

Ø“类型”是对数据的抽象

Ø 类型相同的数据有相同的表示形式、存储格式以及相关的操作

Ø 程序中使用的所有数据都必定属于某一种数据类型

8e3ac8daefb58d8d3bdd90fb1561c7ca.png

数据类型的本质思考

Ø 思考数据类型和内存有关系吗?

Ø C/C++为什么会引入数据类型?

数据类型的本质

Ø数据类型可理解为创建变量的模具(模子);是固定内存大小的别名。

Ø数据类型的作用:编译器预算对象(变量)分配的内存空间大小

Ø程序举例,如何求数据类型的大小sizeof(int *)

Ø 请问:数据类型可以有别名吗?数据类型可以自定义吗?

数据类型大小

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测量的实体大小为编译期间就已确定

数据类型别名

Ø数据类型可以理解为固定大小内存块的别名,请问数据类型可以起别名吗?

int main()

{

       //Teacher t1;

       printf("Teacher:%d \n", sizeof(Teacher));

       printf("u32:%d \n", sizeof(u32));

       printf("u8:%d \n", sizeof(u8));

       printf("hello.....\n");

       getchar();

       return 0;

}

数据类型的封装

Ø1、void的字面意思是“无类型”,void *则为“无类型指针”,void *可以指向任何类型的数据。

Ø2、用法1:数据类型的封装

                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、扩展阅读《void类型详解.doc》

数据类型总结与扩展

Ø1、数据类型本质是固定内存大小的别名;是个模具,c语言规定:通过数据类型定义变量。

Ø2、数据类型大小计算(sizeof)

Ø3、可以给已存在的数据类型起别名typedef

Ø4、数据类型封装概念(void 万能类型)

思考1:

C一维数组、二维数组有数据类型吗?int array[10]。

若有,数组类型又如何表达?又如定义?

若没有,也请说明原因。

抛砖:数组类型,压死初学者的三座大山

1、数组类型

2、数组指针

3、数组类型和数组指针的关系

思考2:

C语言中,函数是可以看做一种数据类型吗?

a)若是,请说明原因

并进一步思考:函数这种数据类型,能再重定义吗?

b)若不是,也请说明原因。

抛砖:

1.3.2变量本质分析

变量概念

Ø概念:既能读又能写的内存对象,称为变量;若一旦初始化后不能修改的对象则称为常量。

Ø 变量定义形式:    类型  标识符, 标识符, … , 标识符 ;

Ø例如:

int   x ;

       int   wordCut ,  Radius ,  Height  ; 

       double   FlightTime ,  Mileage ,  Speed  ;

变量本质

1、程序通过变量来申请和命名内存空间 int a = 0

2、通过变量名访问内存空间

(一段连续)内存空间的别名(是一个门牌号)

3、修改变量有几种方法?

1、直接

2、间接。内存有地址编号,拿到地址编号也可以修改内存;于是横空出世了!(编程案例)

3、内存空间可以再取给别名吗?

4、数据类型和变量的关系

Ø       通过数据类型定义变量

5、总结及思考题

1 对内存,可读可写;2通过变量往内存读写数据;3 不是向变量读写数据,而是向变量所代表的内存空间中写数据。问:变量跑哪去了?

思考1:变量三要素(名称、大小、作用域),变量的生命周期?

思考2:C++编译器是如何管理函数1,函数2变量之间的关系的?

====》引出两个重要话题:

内存四区模型

函数调用模型

重要实验:

int  main333()

{

       //

       //2种方法,通过变量直接操作内存

       //       通过内存编号操作内存

       int i = 0;

       printf("&i:%d\n", &i);

       *((int *)(1245024)) = 10;

       printf("i:%d", i);

       printf("hello....\n");

       getchar();

       return 0;

}

1.3.3程序的内存四区模型

内存四区的建立流程

c1a994c5067221d8bfe00d4ac33c7bbf.png

流程说明

1、操作系统把物理硬盘代码load到内存

2、操作系统把c代码分成四个区

3、操作系统找到main函数入口执行

各区元素分析

37ae62aa91dedaa3ca8c1d0529fb632d.png

1.4函数调用模型

1.4.1基本原理

cd3466e8ab654dd02cf9a3ceaa24749e.png

4dc31ffbdf5be3d7773bce09330a9cd6.png

1.4.2内存四区模型和函数调用模型变量传递分析

1、一个主程序有n函数组成,c++编译器会建立有几个堆区?有几个栈区?

2、函数嵌套调用时,实参地址传给形参后,C++编译器如何管理变量的生命周期?

分析:函数A,调用函数B,通过参数传递的变量(内存空间能用吗?)

b2bbbf031c9651bece5d38bd7cdc50fe.png

1.4.3提示学好C语言的关键

c79f903b30c68a7c20f2582c0a40a124.png

1.4.4如何建立正确的程序运行内存布局图

Ø内存四区模型&函数调用模型

Ø函数内元素

Ø深入理解数据类型和变量“内存”属性

Ø一级指针内存布局图(int *,char*)

Ø二级指针内存布局图(int ** char **)

Ø函数间

Ø主调函数分配内存,还是被调用函数分配内存

Ø主调函数如何使用被调用函数分配的内存(技术关键点:指针做函数参数)

======》学习指针的技术路线图

1.5内存四区强化训练

01全局区训练

Øchar *p1= “abcdefg”;

02 堆栈区生命周期训练

ØChar p1[]= “abcdefg”;

Ø返回基本类型

Ø返回非基本类型

03堆栈属性训练

Ø测试heap生长方向

Ø测试stack生长方向

ØHeap、stack生长方向和内存存放方向是两个不同概念

Ø野指针

ØMalloc得到指针释放问题测试

Øfree(p)

Øfree(p+1),深入理解

ea73351b882319e6ac3880c257602760.png

1.6作业强化

训练1划出内存四区

void main26()

{

      char buf[100];

      //byte b1 = new byte[100];

      int a = 10; //分配4个字节的内存 栈区也叫临时区

      int *p;//分配4个字节的内存

      p = &a; //cpu执行的代码,放在代码区

      *p = 20; //

      {

            char *p = NULL; //分配4个字节的内存 栈区也叫临时区

            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; //p3 是个变量

      //指针变量和它所执行的内存空间变量是两个不同的概念

      strcmp(p1, p2);

      system("pause");

}

训练2 划出内存四区

void main01()

{

      char buf[100];

      //byte b1 = new byte[100];

      int a = 10; //分配4个字节的内存 栈区也叫临时区

      int *p;//分配4个字节的内存

      p = &a; //cpu执行的代码,放在代码区

      *p = 20; //

      {

            char *p2 = NULL; //分配4个字节的内存 栈区也叫临时区

            p2 = (char *)malloc(100); //内存泄露概念

            if (p2 != NULL)

            {

                  free(p2);

                  //p2 = NULL;  若不写,实验效果,分析原因

            }

            if (p2 != NULL)

            {

                  free(p2);

            }

      }

      system("pause");

}

2指针知识体系搭建

2.1前言

       先从整体上把握指针的知识体系。然后突破1级指针、二级指针、多级指针。

2.2指针强化

铁律1:指针是一种数据类型   

1)指针也是一种变量,占有内存空间,用来保存内存地址

测试指针变量占有内存空间大小

2)*p操作内存

在指针声明时,*号表示所声明的变量为指针

在指针使用时,*号表示 操作 指针所指向的内存空间中的值

       *p相当于通过地址(p变量的值)找到一块内存;然后操作内存

       *p放在等号的左边赋值(给内存赋值)

       *p放在等号的右边取值(从内存获取值)

3)指针变量和它指向的内存块是两个不同的概念

//含义1 给p赋值p=0x1111; 只会改变指针变量值,不会改变所指的内容;p = p +1; //p++

//含义2 给*p赋值*p='a'; 不会改变指针变量的值,只会改变所指的内存块的值 

//含义3 =左边*p 表示 给内存赋值, =右边*p 表示取值 含义不同切结!

//含义4 =左边char *p

//含义5 保证所指的内存块能修改

4)指针是一种数据类型,是指它指向的内存空间的数据类型 

含义1:指针步长(p++),根据所致内存空间的数据类型来确定

p++=è(unsigned char )p+sizeof(a);

结论:指针的步长,根据所指内存空间类型来定。

注意:   建立指针指向谁,就把把谁的地址赋值给指针。图和代码和二为一。  

              不断的给指针变量赋值,就是不断的改变指针变量(和所指向内存空间没有任何关系)。

铁律2:间接赋值(*p)是指针存在的最大意义

1)两码事:指针变量和它指向的内存块变量

2)条件反射:指针指向某个变量,就是把某个变量地址否给指针

3)*p间接赋值成立条件:3个条件

a)2个变量(通常一个实参,一个形参)

b) 建立关系,实参取地址赋给形参指针

c) *p形参去间接修改实参的值

Int iNum = 0; //实参

int *p = NULL;

p = &iNum;

iNum = 1;

*p =2 ; //通过*形参 == 间接地改变实参的值

*p成立的三个条件:

4)引申: 函数调用时,用n指针(形参)改变n-1指针(实参)的值。

//改变0级指针(int iNum = 1)的值有2种方式

//改变1级指针(eg char *p = 0x1111 )的值,有2种方式

//改变2级指针的(eg char **pp1 = 0x1111 )的值,有2种方式

//函数调用时,形参传给实参,用实参取地址,传给形参,在被调用函数里面用*p,来改变实参,把运算结果传出来。

//指针作为函数参数的精髓。

铁律3:理解指针必须和内存四区概念相结合

1)主调函数 被调函数

a)主调函数可把堆区、栈区、全局数据内存地址传给被调用函数

b)被调用函数只能返回堆区、全局数据

2)内存分配方式

a)指针做函数参数,是有输入和输出特性的。

铁律4:应用指针必须和函数调用相结合(指针做函数参数)

编号

指针函数参数

内存分配方式(级别+堆栈)

主调函数

实参

被调函数

形参

备注

01

1级指针

(做输入)

分配

使用

一般应用禁用

分配

使用

常用

Int showbuf(char *p);  

int showArray(int *array, int iNum)

02

1级指针

(做输出)

使用

结果传出

常用

int geLen(char *pFileName, int *pfileLen);

03

2级指针

(做输入)

分配

使用

一般应用禁用

分配

使用

常用

int main(int arc ,char *arg[]); 指针数组

int shouMatrix(int [3][4], int iLine);二维字符串数组

04

2级指针

(做输出)

使用

分配

常用,但不建议用,转化成02

int getData(char **data, int *dataLen);

Int getData_Free(void *data);

Int getData_Free(void **data); //避免野指针

05

3级指针

(做输出)

使用

分配

不常用

int getFileAllLine(char ***content, int *pLine);

int getFileAllLine_Free(char ***content, int *pLine);

指针做函数参数,问题的实质不是指针,而是看内存块,内存块是1维、2维。

1)如果基础类int变量,不需要用指针;

2)若内存块是1维、2维。

铁律5:一级指针典型用法(指针做函数参数)

一级指针做输入

int showbuf(char *p)

int showArray(int *array, int iNum)

一级指针做输出

int geLen(char *pFileName, int *pfileLen);

理解

主调函数还是被调用函数分配内存

被调用函数是在heap/stack上分配内存

铁律6:二级指针典型用法(指针做函数参数)

二级指针做输入

int main(int arc ,char *arg[]); 字符串数组

int shouMatrix(int [3][4], int iLine);

二级指针做输出

int Demo64_GetTeacher(Teacher **ppTeacher);

int Demo65_GetTeacher_Free(Teacher **ppTeacher);

int getData(char **data, int *dataLen);

Int getData_Free(void *data);

Int getData_Free2(void **data); //避免野指针

理解

主调函数还是被调用函数分配内存

被调用函数是在heap/stack上分配内存

铁律7: 三级指针输出典型用法

三级指针做输出

int getFileAllLine(char ***content, int *pLine);

int getFileAllLine_Free(char ***content, int *pLine);

理解

主调函数还是被调用函数分配内存

被调用函数是在heap/stack上分配内存

铁律8:杂项,指针用法几点扩充

1)野指针 2种free形式

int getData(char **data, int *dataLen);

int getData_Free(void *data);

int getData_Free2(void **data);

2)2次调用

主调函数第一次调用被调用函数求长度;根据长度,分配内存,调用被调用函数。

3)返回值char */int/char **

4)C程序书写结构

商业软件,每一个出错的地方都要有日志,日志级别

铁律9:一般应用禁用malloc/new

2.3接口封装设计思想引导

基于socketclient客户端接口设计与实现(仿真模拟)

2.4附录

【王保明老师经典语录】

1)指针也是一种数据类型,指针的数据类型是指它所指向内存空间的数据类型

2)间接赋值*p是指针存在的最大意义 

3)理解指针必须和内存四区概念相结合 

4)应用指针必须和函数调用相结合(指针做函数参数)

指针是子弹,函数是枪管;子弹只有沿着枪管发射才能显示它的威力;指针的学习重点不言而喻了吧。接口的封装和设计、模块的划分、解决实际应用问题;它是你的工具。

5)指针指向谁就把谁的地址赋给指针 

6)指针指向谁就把谁的地址赋给指针,用它对付链表轻松加愉快

7)链表入门的关键是分清楚链表操作和辅助指针变量之间的逻辑关系

8)C/C++语言有它自己的学习特点;若java语言的学习特点是学习、应用、上项目;那么C/C++语言的学习特点是:学习、理解、应用、上项目。多了一个步骤吧。

9)学好指针才学会了C语言的半壁江山,另外半壁江山在哪里呢?你猜,精彩剖析在课堂。

10) 理解指针关键在内存,没有内存哪来的内存首地址,没有内存首地址,哪来的指针啊。

3字符串和一级指针内存模型专题

3.1字符串基本操作

字符数组初始化方法

int main11()

{       

       //1 大{}号法 初始化列表

       //数组初始化有2种方法 默认元素个数、指定元素个数

       char buf1[] = {'a', 'b', 'c', 'd', 'e'};       //若没有指定长度,默认不分配零

       //若指定长度,不够报错;buf长度多于初始化个数,会自动补充零

       char

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值