C++基础句法

A man provided with paper,pencil,and rubber and subject to strict discipline,is effect a universal Turing Machine. ——Alan Mathison Turing

1.图灵机与三种基本结构

三种基本的程序结构

  • 顺序,分支和循环
    在这里插入图片描述

2.if语句基础和例子

  • 复合语句:
    单一语句:在任何一个表达式后面加上分号(😉
    复合语句:用一对花括号{}括起来的语句块,在语法上等效于一个单一的语句。

  • if语句:
    if语句是最常见的一种分支语句,也称为条件语句。
    如:

if(p != NULL)
{
	cout<<*p<<endl;
}else{
	;
}

在这里插入图片描述

在这里插入图片描述

3.switch分支基础

  • switch的一般形式:
switch(表达式)
{	case 常数1:语句1;break;
	case 常数2:语句2;break;
	................
	case 常数n:语句n;break;
	default:语句n+1
}

4.switch和if的对比

  • 使用场景:
  1. switch只支持常量值固定相等的分支判断;
  2. if还可以判断区间范围;
  3. 用switch能做的,用if都能做,但反过来则不行
  • 性能比较:
  1. 分支少时,差别不是很大,分支多时,switch性能较高;
  2. fi开始处几个分支效果高,之后效率递减;
    3.switch所有case的速度几乎一样;

5.自定义类型——枚举

  • 使用#define和const创建符号常量,使用enum不仅能够创建符号常量,还能定义新的数据类型;
  • 枚举类型enum(enumeration)的声明和定义:
    例如:
enum WT{
	Monday,
	Tuesday,
	Wedesday,
	Thursday,
	Friday,
	Saturday,
	Sunday
};
wT weekday;
weekday = Monday;
//weekday = 1;	//错误,不能直接给int值,只能赋给成wT定义好的类型值
weekday = wT(1);//强制类型转化就可以
cout<<weekday<<endl;//1
//Monday = 0; 	//类型值不能做左值
int a = Wednesday;
cout<<a<<endl;	//可以
  • 使用细节:
  1. 枚举值不可以做左值;
  2. 非枚举变量不可以赋值给枚举变量;
  3. 枚举变量可以赋值给非枚举变量;

6.自定义类型——结构体与联合体

  • 使用struct定义的是结构体:
    例如:
struct Student
{
	char name[6];
	int age;
	Score s;
}
  • 使用union定义的是联合体:
    例如:
union Score
{
	double fs;
	char level;
}
sizeof(Student);	//24
sizeof(Score);		//8

7.结构体的内存布局

结构体数据对齐问题

  • 结构体的尺寸:
struct s1
{
	char x;
	int z;
	short y;
};				//sizeof(s1) = 12
struct s2
{
	char x;
	short y;
	int z;
};				//sizeof(s1) = 8

结构体的内存布局

32位CPU眼中的内存布局(32位系统中以4个字节为整体来看!)
在这里插入图片描述
在这里插入图片描述
将int改成double类型,上面是24,下面是16。面试经常考这个!!!!!

结构体数据对齐——缺省对齐原则

  • 32位CPU
    char:任何地址
    short:偶数地址
    int:4的整数倍地址
    double:8的整数倍地址
  • 修改默认编译选项
    Visual C++:
#pragma pack(1)	//以1位整数倍地址

g++:

__attribute__(aligned(n))
__attribute__(__packed__)

在这里插入图片描述
建议:如果没有编译选项,要考虑内存布局,要尽量将小的sizeof放在一起,这样可以凑够大的sizeof的整数倍,不需要两边都进行扩充。当然最好的方法还是修改编译选项。

8.三种循环的基本使用与比较

  • while,do…while和for
  • 三个循环的编写方式:
    在这里插入图片描述

9.函数基础

int main()
{
	return 0;
}

函数的所有组成部分:

  1. 返回类型:一个函数可以返回一个值;
  2. 函数名称:这是函数的实际名称,函数名和参数列表一起构成了函数签名;
  3. 参数:参数列表包括函数参数的类型、顺序、数量。参数是可选的,也就是说,函数可能不包含参数;

10.函数重载overload与Name Mangling

  • 函数重载overload与C++ Name Mangling:
int test(int a);
int test(double a);
int test(int a,double d);

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

  • 每一个函数都占用一段内存单元,它们都有一个起始地址,指向函数入口地址的指针称为函数指针。
    一般形式:数据类型(*指针变量名)(参数表);
    举例:int(*p)(int)
  • 注意与返回指针的函数之间区别:
    如:
int(*p)(int);	//是指针,指向一个函数入口地址
int* p(int);	//是函数,返回的值是一个指针

再如:

bool processNum(int i,int j,int(*p)(int a,int b));//int(*p)(int a,int b)回调函数
char *strcpy(char *dest,const char *src);
#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;
}

12.命名空间

  • 同一个班级,同一个公司,很容易出现同名的人;
    在C++程序中也会出现这样的问题。

  • 命名空间这个概念,可作为附加信息来区分不同库中相同名称的函数、类、变量等,命名空间即定义了上下文。
    本质上,命名空间就是定义了一个范围。

  • 关键词:usingnamespace的使用;(在之后做项目之中一定会用到)
    注:如果有多个命名空间,不能再头部直接引入命名空间,则在每次使用时加入命名空间即可。

13.函数体的Hack过程

函数的所有组成部分:
4.函数主体:函数主体包含一组定义函数执行任务的语句;

int Fib(int n)
{
	if(n==0)
	{return 0;}
	else if(n==1)
	{return 1;}
	else
	{return Fib(n-1}+Fib(n-2);}
}

进程,线程,携程,(#^.^#)
查看汇编代码来分析C++的函数运行栈信息

14.内联函数

如果一个函数是内联的,那么在编译时,编译器会把该函数的代码副本放置在每个调用该函数的地方。

inline int MaxValue(int x,int y)//求最大数
{
	return (x>y)
}

C/C+±>高级->调用约定:
_cdecl(/Gd):从右向左传参
C/C+±>高级->内联函数是否扩展:
只适用于__inline(Ob1)
注意:内联是空间换时间,有时候会失效。复杂的循环和递归不适合内联操作。

15.数学归纳法与递归

递归与数学归纳法

  • 从数学归纳法说起
    数学归纳法是证明当n等于任意一个自然数时某命题成立。
    证明步骤分两步:
    1.证明当n=1时命题成立;
    2.假设n=m时命题成立,那么可以推导出在n=m+1时命题也成立(m代表任意自然数);

  • 证明世界上所有的人都是秃子:
    我们知道:
    1)0根头发的人是秃子,有1根头发的人也是秃子;
    2)假设有n根头发的人是秃子,那么有n+1根头发的人也是秃子;
    所以,所有人都是秃子;

  • 斐波那契数列:1,1,2,3,5,8,13,21,34,…
    F i b ( n ) = { 1 , n = 1 , 2 F i b ( n − 1 ) + F i b ( n − 2 ) , n > 2 Fib(n)=\begin{cases} 1, n=1,2\\ Fib(n-1)+Fib(n-2),n>2\\ \end{cases} Fib(n)={1,n=1,2Fib(n1)+Fib(n2),n>2
    程序实现:
    见标题:函数体的Hack过程

  • 斐波那契数列递归处理的问题:
    在这里插入图片描述
    重复运算,时间和空间大量浪费

递归(recursion)

  • 递归的四个基本法则:
    1)基准情形:无须递归就能解出;
    2)不断推进:每一次递归调用都必须使求解状况朝接近基准情形的方向推进;
    3)设计法则:假设所有的递归调用都能运行;
    4)合成效益法则(compound interest rule):求解一个问题的同一个实例时,切勿在不同的递归调用中做重复性的工作;

由此可见,使用递归来计算诸如菲波那切数列并不是一个好主意;

  • 递归是一种重要的编程思想:
    1)很多重要的算法都包含递归的思想;
    2)递归最大的缺陷:
    A.空间上需要开辟大量的栈空间;
    B.时间上可能需要有大量重复运算;

  • 递归的优化:
    1)尾递归:所有递归形式的调用都出现在函数的末尾;
    2)使用循环替代;
    3)使用动态规划,空间换时间;

16.递归的特点和Hack过程

  • 循环优化递归
int Fib(int n)
{
	if(n <2)
	{
		return n;
	}
	int n0 = 0,n1 = 1;
	int temp;
	for(int i = 2;i <= n;++i)
	{
		temp = n0;
		n0 = n1;
		n1 = temp+n1;
	}
	return n1;
}
  • 尾递归优化递归
    (尾递归只需要保存一个递归信息,普通的递归需要保存两个函数的递归信息),尾递归迭代写法阔以!
int Fib(int n,int ret0,int ret1)
{
	if(n == 0)
	{
		return ret0;
	}else if(n == 1){
		return ret1;
	}
	return Fib(n-1,ret1,ret0+ret1);
}

17.尾递归的优化

在编译器中C/C+±>优化->优化->使大小最小化(/O1)
C/C+±>代码生成->基本运行时检查->默认值

18.递归的动态规划思路

#include<assert.h>
int a[1000];	//全局数组
int Fib(int n)
{
	a[0] = 0;
	a[1] = 1;
	for(int i <=2;i <= n;++i)
	{
		a[i] = a[i-1]+a[i-2];
	}  
	return a[n];
}
assert(Fib(10)==55);
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值