文章目录
- 1. 图灵机与三种基本结构
 - 1. 顺序结构
 - 2. 分支结构
 - 自定义结构-枚举
 - 结构体与联合体
 - 结构体数据对齐问题
 
- 3. 循环结构
 - 三种循环结构
 - 反汇编查看三种结构效率
 - 实例:输出所有形如aabb的四位数的完全平方数
 - 方案1: 构造aabb数,再判断
 - 方案2:反向操作:先算出平方和,再判断是否为aabb结构
 
- 2. 函数
 - 1. 总览
 - 2. 函数组成
 - 3. 指向函数的指针与返回指针的函数
 - 4. 命名空间
 - 5. 函数体调用过程
 - 6. 内联函数
 - VS设置
 - 汇编过程
 
- 3. 递归
 - 1. 递归与数学归纳法
 - 基本法则
 - 递归的缺陷
 - 递归的优化
 - 循环迭代
 - 尾递归
 - 动态规划
 
慕课网c++课程
1. 图灵机与三种基本结构
1. 顺序结构

2. 分支结构

 
 
 
自定义结构-枚举

- 代码示例
 
// demo6-2.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
using namespace std;
int main()
{
	enum wT{Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday}; // 声明wT类型
	wT weekday;
	weekday = Monday;
	weekday = Tuesday;
	//weekday = 1;             // 不能直接给int值,只能赋值成wT定义好的类型值
	cout << weekday << endl;   // 1
	//Monday = 0;             // 类型值不能做左值
	int a = Wednesday;
	cout << a << endl;        // 2
    return 0;
}
 

结构体与联合体

- 示例
 
#include <string.h>
#include <iostream>
using namespace std;
int main()
{
	union Score 
	{
		double ds;
		char level;
	};
	struct Student
	{
		char name[6];                                 
		int age;                 
		Score s;               
	};
	cout << sizeof(Score) << endl;      // 8,取最大元素的字节作为联合体空间
	...
}
 
结构体数据对齐问题
- 原则1:小于等于4字节的变量,两个变量累加的空间大于4的整数倍,就分配4的整数倍+1,反之,没有超过4的整数倍,就分配4的整数倍(例如char:1, int :4,一个4字节分配不了,就开辟两个4字节空间)
 - 原则2:大于4字节的变量,以此变量为整数进行分配,原理与以4字节为整数进行分配一致

 - 内存布局的4字节的处理,即,每4字节1段,即使char,short分别占1字节和2字节,也要分配4字节

 - 最大元素的整数倍的处理:最大元素内存对齐,假如int类型改为占8字节的double类型,S2要共占16字节


 - 调试测试
 
Student s1;
	strcpy_s(s1.name, "lili");
	s1.age = 16;
	s1.s.ds = 95.5;
	s1.s.level = 'A';
	cout << sizeof(Student) << endl;    // 24     18 
 

 
 
- 总结:

 
// 设置成连续分配空间
#pragma pack(1)
 

3. 循环结构
三种循环结构

反汇编查看三种结构效率

- do-while循环代码相对效率较高,只有一个跳转
 
// do-while语句
	sum = 0;
002A1810  mov         dword ptr [sum],0  
	index = 1;
002A1817  mov         dword ptr [index],1  
	do 
	{
		sum += index;
002A181E  mov         eax,dword ptr [sum]  
002A1821  add         eax,dword ptr [index]  
002A1824  mov         dword ptr [sum],eax  
		index += 1;
002A1827  mov         eax,dword ptr [index]  
002A182A  add         eax,1  
002A182D  mov         dword ptr [index],eax  
	} while (index <= 100);
002A1830  cmp         dword ptr [index],64h  
002A1834  jle         main+7Eh (02A181Eh)  // 比较小于0,跳回原循环体
 
- while循环:两次跳转
 
// while语句
	int sum = 0;
002A17BE  mov         dword ptr [sum],0  
	int index = 1;
002A17C5  mov         dword ptr [index],1  
	while (index <= 100)
002A17CC  cmp         dword ptr [index],64h // 与100比较 
002A17D0  jg          main+46h (02A17E6h)   // g:大于0,就跳出循环到另个位置
	{
		sum += index;
002A17D2  mov         eax,dword ptr [sum]  
002A17D5  add         eax,dword ptr [index]  
002A17D8  mov         dword ptr [sum],eax  
		index += 1;
002A17DB  mov         eax,dword ptr [index]  
002A17DE  add         eax,1  
002A17E1  mov         dword ptr [index],eax  // 跳回到最初的位置
	}
002A17E4  jmp         main+2Ch (02A17CCh) 
 
- for循环:三次跳转,相对复杂些,但代码灵活些
 
	// for语句
	//index = 1;
	sum = 0;
002A17E6  mov         dword ptr [sum],0  
	for (index = 1; index <= 100; ++index)
002A17ED  mov         dword ptr [index],1  
002A17F4  jmp         main+5Fh (02A17FFh)  // 跳到cmp比较操作
002A17F6  mov         eax,dword ptr [index]  
002A17F9  add         eax,1  
002A17FC  mov         dword ptr [index],eax  
002A17FF  cmp         dword ptr [index],64h  
002A1803  jg          main+70h (02A1810h) // 与while循环一样,跳出循环 
	{
		sum += index;
002A1805  mov         eax,dword ptr [sum]  
	{
		sum += index;
002A1808  add         eax,dword ptr [index]  
002A180B  mov         dword ptr [sum],eax  
	}
002A180E  jmp         main+56h (02A17F6h)  // 跳到index++操作
 
实例:输出所有形如aabb的四位数的完全平方数
方案1: 构造aabb数,再判断
	// aabb的完全平方数
	// 先构造aabb,再开方,判断开方后的数是否为整数,相差处理
	int n = 0;
	double m = 0;
	for (size_t a = 1; a < 10; a++) //  size_t 是一些C/C++标准在stddef.h中定义的,size_t 类型表示C中任何对象所能达到的最大长度,它是无符号整数
	{
		for (size_t b = 0; b < 10; b++)
		{
			n = a * 1100 + b * 11; //aabb
			// 难点是,开方后的数如何判断是整数:形如4.0, 5.0等
			m = sqrt(n);  
			// 方案1:相差
			if (m - int(m) < 0.00000001)
			{
				cout << n << endl;
			}
		}
	}
 
方案2:反向操作:先算出平方和,再判断是否为aabb结构
int high, low; // 高位aa, 地位bb
	// aabb的完全平方数
	for (size_t index = 31; ; index++) // 小于1000跳过
	{
		n = index*index;
		if (n < 1000)
			continue;   // 继续下一次循环
		if (n > 9999)
			break;        // 退出循环
		high = n / 100;   // 4567/100 = 45
		low = n % 100;   // 4567%100 = 67
		if ((high / 10 == high % 10) && (low / 10 == low % 10))   // 判断aa, bb
		{
			cout << n << endl;
		}
	}
 
2. 函数
1. 总览

2. 函数组成

 
3. 指向函数的指针与返回指针的函数

// demo6-7.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
using namespace std;
int MaxValue(int x, int y)
{
	return (x > y) ? x : y;
}
int MinValue(int x, int y)
{
	return (x < y) ? x : y;
}
int Add(int x, int y)
{
	return x+y;
}
bool ProcessNum(int x, int y, int(*p)(int a, int b))
{
	cout << p(x, y) << endl;
	return true;
}
int main()
{   
	int x = 10, y = 20;
	cout << ProcessNum(x, y, MaxValue) << endl; // 直接传递函数名称即可,指针可以指向
	cout << ProcessNum(x, y, MinValue) << endl;
	cout << ProcessNum(x, y, Add) << endl;
    return 0;
}
 

4. 命名空间

// stdafx.h : 标准系统包含文件的包含文件,
// 或是经常使用但不常更改的
// 特定于项目的包含文件
//
#pragma once
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
// TODO:  在此处引用程序需要的其他头文件
int test(int a);
int test(double a);
int test(int a=1, double b=2.0);
namespace quickzhao
{
	int test(int a);
}
 
#include "stdafx.h"
int main()
{
	int(*p)(int);
	p = test;
	int result = (*p)(1);
	result = quickzhao::test(1);
	result = test(2.0);
	result = test(1, 2.0);
    return 0;
}
 
5. 函数体调用过程
#include "stdafx.h"
int MaxValue(int a, int b)
{
	return (a > b) ? a : b;
}
int main()
{
	int x = 3, y = 4;
	MaxValue(x, y);
    return 0;
}
 
- main函数调用过程
 
// main函数处理过程
int main()
{
// 初始化栈
00C01690  push        ebp      // 放进栈-寄存器-edp在栈底,esp寄存器在栈顶
00C01691  mov         ebp,esp  // 将ebb数据放进esp中
00C01693  sub         esp,0C0h // 对esp信息做了一个减法 ,这样栈顶与栈底形成一个0C0h空间
00C01699  push        ebx      
00C0169A  push        esi      // 压栈后,esp地址会继续减少,保持在栈顶
00C0169B  push        edi   
00C0169C  lea         edi,[ebp-0C0h]  
00C016A2  mov         ecx,30h  
00C016A7  mov         eax,0CCCCCCCCh  
00C016AC  rep stos    dword ptr es:[edi]  
    return 0;
00C016AE  xor         eax,eax  
}
/ 清空栈
009C16D0  pop         edi  
009C16D1  pop         esi  
009C16D2  pop         ebx  
}
009C16D3  mov         esp,ebp  
009C16D5  pop         ebp  
009C16D6  ret  
 
- 自定义函数调用过程
 
/ 自定义函数处理过程
int MaxValue(int a, int b)
{
009C1690  push        ebp  
009C1691  mov         ebp,esp  
009C1693  sub         esp,0C4h  
009C1699  push        ebx  
009C169A  push        esi  
009C169B  push        edi  
009C169C  lea         edi,[ebp-0C4h]  
009C16A2  mov         ecx,31h  
009C16A7  mov         eax,0CCCCCCCCh  
009C16AC  rep stos    dword ptr es:[edi]  
	return (a > b) ? a : b;
009C16AE  mov         eax,dword ptr [a]  
009C16B1  cmp         eax,dword ptr [b]  
009C16B4  jle         MaxValue+31h (09C16C1h)  
009C16B6  mov         ecx,dword ptr [a]  
009C16B9  mov         dword ptr [ebp-0C4h],ecx  
009C16BF  jmp         MaxValue+3Ah (09C16CAh)  
009C16C1  mov         edx,dword ptr [b]  
009C16C4  mov         dword ptr [ebp-0C4h],edx  
009C16CA  mov         eax,dword ptr [ebp-0C4h]  
}
	int x = 3, y = 4;  // 压栈方式,从右往左
00CC166E  mov         dword ptr [x],3  
00CC1675  mov         dword ptr [y],4  
	MaxValue(x, y);
00CC167C  mov         eax,dword ptr [x]  
00CC167F  cmp         eax,dword ptr [y]  
00CC1682  jle         main+3Fh (0CC168Fh)  
00CC1684  mov         ecx,dword ptr [x]  
00CC1687  mov         dword ptr [ebp-0DCh],ecx  
00CC168D  jmp         main+48h (0CC1698h)  
00CC168F  mov         edx,dword ptr [y]  
00CC1692  mov         dword ptr [ebp-0DCh],edx  
    return 0;
00CC1698  xor         eax,eax  
 
6. 内联函数
- 只处理核心逻辑,不处理堆栈,寄存器等其他处理过程,提高效率
 - 内联只是建议,不一定有效,编译器会有自己的优化

 
VS设置

 
汇编过程
- 将核心过程映射到函数调用处
 
	MaxValue(x, y);
00CC167C  mov         eax,dword ptr [x]  
00CC167F  cmp         eax,dword ptr [y]  
00CC1682  jle         main+3Fh (0CC168Fh)  
00CC1684  mov         ecx,dword ptr [x]  
00CC1687  mov         dword ptr [ebp-0DCh],ecx  
00CC168D  jmp         main+48h (0CC1698h)  
00CC168F  mov         edx,dword ptr [y]  
00CC1692  mov         dword ptr [ebp-0DCh],edx  
 
	Fib(5);
011238A8  mov         eax,5  
011238AD  test        eax,eax  
011238AF  jne         main+55h (011238B5h)  
011238B1  jmp         main+85h (011238E5h)  
011238B3  jmp         main+85h (011238E5h)  
011238B5  mov         ecx,5  
011238BA  cmp         ecx,1  
011238BD  jne         main+63h (011238C3h)  
011238BF  jmp         main+85h (011238E5h)  
011238C1  jmp         main+85h (011238E5h)  
011238C3  mov         edx,5  
011238C8  sub         edx,1  
011238CB  push        edx  
011238CC  call        Fib (0112132Ah)       // 当函数复杂时,还是call了内联函数
011238D1  add         esp,4  
011238D4  mov         eax,5  
 
3. 递归
1. 递归与数学归纳法

 
基本法则

递归的缺陷

递归的优化
循环迭代
// 循环
int Fib3(int n)
{
	if (n < 2)
	{
		return n;
	}
	int n0 = 0, n1 = 1;
	int temp; 
	for (int i = 2; i <= n; i++)
	{
		temp = n0; 	    // temp记录f(n-2)
		n0 = n1;        // n1记录f(n-1),用n0传递,是下轮的f(n-2)
		n1 = temp + n1; // n1记录这轮的f(n),是下轮的f(n-1)
	}
	return n1;
}
 
尾递归
- 最后一步递归调用,之前的栈和寄存器都没有变化
 
// 尾递归
int Fib2(int n, int ret0,  int ret1)
{
	if (n == 0)
	{
		return ret0;
	}
	else if (n == 1)
	{
		return ret1;
	}
	return Fib2(n - 1, ret1, ret0 + ret1);
}
 
动态规划
int g_a[1000]; // 全局的数组,记录斐波那契数列的前1000个值
// 动态规划
int Fib4(int n)
{
	//assert(n >= 0);
	g_a[0] = 0;
	g_a[1] = 1;
	for (int i = 2; i <= n; i++)
	{
		if (g_a[i] == 0) // 用表记录斐波拉系数,没有就计算,有的话直接用
		{
			g_a[i] = g_a[i - 1] + g_a[i - 2];
		}
	}
	return g_a[n];
}
                


















