C/C++复习大总结(持续更新ing)

1.数据类型和存储

1.1数据类型

类型字节范围个数
char1-128~127256
short2-32768 ~ 3276765536
int4-2的31次方~ 2的31次方 -143亿多数
long4/8 (32位/64位)-2的31次方~ 2的31次方 -1 或-2的63次方 ~ 2的63次方 -1
float4小数点后6位
double8小数点后15位
指针4/8 (32位/64位)
unsigned char10 ~ 255256
unsigned short20 ~ 6553565536
unsigned int ( unsigned )40 ~ 43亿多43亿多
unsigned long4/82的32次方/2的64次方

float a = 2.0; a*2 3.999999
int16_t 2字节 long long 8个字节

1.2类型转换

在c语言中主要分为显示类型转换隐式类型转换
(1)显示转换:显示转换即代表强制转换即:(类型)(量),这样既可以将后面的量转换为括号中对应的类型。
(2)隐式转换:隐式转换主要指程序运行时自动发生的类型转换。
在c++中在这两个转换的基础上添加了4个转换运算符:

  • static_cast (编译阶段检查)
    用法:static_cast <类型>()
    主要应用:
    1)向上转换:将Derived*(衍生类指针)转换为Base*(基类指针)称之为向上转换。(父类指针指向子类–强转子类)
    注意:在这里不使用任何显示转换即可进行
    eg:
Derived* objDerived;
Base *pBase = &objDerived;	//ok!
//这里即相当于Base *pBase = static_cast<Base*>&objDerived
//即父类指针可以指向子类

2)向下转换:将Base*(基类指针)转换为Derived*(衍生类指针)称之为向下转换,(子类指针指向父类-强转父类)
注意:在这里一定要使用显示转换才可进行
eg:

Derived* objDerived;
Base *pBase = &objDerived;	//ok!
Derived* pDerived = pBase;// Error:Downcast needs explicit cast
//修改更正:
Derived* pDerived = static_cast<Derived*>(pBase);
//即子类指针指向父类需要显示转换

3)隐式类型转换转换为显示类型转换:

double dPi = 3.14;
int Num = static_cast<int>(dPi);
//这里可以不用,使用后更易于理解

与强制类型转换一样并不能保证安全,同时其不会改变变量的固有属性,如:static 、const等

  • dynamic_cast (运行阶段检查)
    用法:dynamic_cast<类型>(变量)
    主要应用:基本同于静态转换,其更主要应用于向下转换中(父类指针转换为子类),调用子类特有的方法,动态转换更安全。
    dynamic_cast会做类型的检查, 假如父类的指针pF, 指向的是一个子类的对象, 那么 返回一个非空的值, 如果不是, 会返回空
CFather *pF = new CSon;
CSon* pS = dynamic_cast< CSon *>( pF) ; //将父类指针转换为子类
//dynamic_cast中的判断
if( pS )// pS非空
pS->Func(); 
//eg:
CFather *pF1 = new CSon1;
CSon* pS = dynamic_cast< CSon *>( pF1) ;
//pS 就是一个空的
CSon* pS = static_cast< CSon *>( pF1) ;
//pS 是一个非空的
if(pS)
pS->Func();

意义: 很多时候父类指针, 没有办法调用子类成员函数, 子类有特有的虚函数, 可以通过上面dynamic_cast安全的调用子类特有方法. (拿到那个对象)

  • reinterpret_cast(重解释类型转换)
    用法:reinterpret_cast<类型>(变量)
    主要应用:万能转换 但是会不会出问题他不管.
    意义: 编程很多时候因为类型编译不过, 可以用
    reinterpret_cast<>(); 转换
    eg:
AA a;
int val = reinterpret_cast<int>(a);
  • const_cast(去常转换)
    用法:const_cast<类型>(变量)
    主要应用:将常函数转换为普通函数
    eg:
void fuc( const AA & a)
//a.常函数();
AA aa = const_cast<AA>(a);
//aa.一般函数();

注意

  1. 赋值操作 a , b 的类型不可能变. b的表达式结果类型变
  2. 如果b是小类型 char b; int a = b; 转换过程值不变,a的值和b的相等,小类型保持值不变
  3. 如果b是一个大类型 , int b; char a = b; 会发生截断.
  • 3.1 b的值可以+或- a的表示数的个数的整数倍. a可以表示是
    256个数 , b = 300 ,a = 300 - 256*n = 300 - 256 = 44
    char a = 127 + 1 --> -128 a = 127 + 1 -256 = -128
  • 3.2 可以转成补码计算 , 取低8位. 300 --> 0000 0001 0010 1100 --> 0010 1100

1.3进制转换

进制转换主要包括:二进制、十进制 、16进制、 8进制
二进制:主要是计算机使用的进制
二进制与十进制转换
25十进制转换二进制:
25/2=12余1
12 / 2 = 6 余数0
6 / 2 = 3 余数0
3/2 = 1 余数1
1/2 = 0 余数1
每次拿商/2 直到除尽 将余数串起来 11001 对应25的二进制
二进制与八进制转换:每三位 一个八进制数 011001(31)
二进制与十六进制转换: 每4位 一个16进制数 0x19

1.4原码、补码、反码

补码:计算机存储的是补码。
正数的原码是补码一样。
原码–>补码:符号位不变,其他按位取反加一。
原码–>反码:符号位不变,其他按位取反。
反码–>补码:反码加一。
eg: 25原码0001 1001 补码=原码 反码 0110 0110
-25原码1001 1001 反码 1110 0110 补码 1110 0111
~叫按位取反 -i -叫做取负 !i !叫做取非

1.5大端小端

(1)小端存储:window存储 低地址存在低字节
(2)大端存储:交换机 网络字节序 低地址存高字节
eg: 0000 0000 0101 1010
小端存储:0000 0000 0101 1010
大端存储:0101 1010 0000 0000
常见问题:写一个判断大小端存储的函数

unsigned int fun()
{
	int i = 1;
	return *(char*)&i == i;
}
//*(char*)从低地址取一个字节 如果为1 代表小端存储  如果为0 代表大端存储

1.6 scanf 和 printf

scanf( “%d” , &a ): 间接引用 地址传递 a 值传递
%s --> 遇到空格结束 Hello World --> Hello
gets( 缓冲区 ) : 功能:主要完成输入字符串,完成 Hello World
printf ():%d %p %u %f %lf --> int 地址 uint float double
%02d --> 0 补位0 2代表2位 %02d , a = 1 --> 01

1.7位运算

左移:<< 左移一定补0
右移:>> 根据符号位 和类型补位
(1)无符号类型一定补0
(2)有符号 根据符号位 符号位1 补1 符号位0 补0
~ **:按位取反
^:异或 相异为1 相同为0
&:按位与
| :按位或

1.8优先级

在这里插入图片描述
注意:短路语句
&& 与 || 涉及短路语句
0 && 语句1
1 || 语句2
语句1, 语句2 是不执行的 , 发生短路语句会屏蔽掉后面的内容.
A = B =C = 1 ;
A++ || B++ && C++;
B,C 结果? 短路语句 BC不会++ , 短路语句 , 有一种称呼叫做上帝之手 , 凌驾于优先级之上的.

2.流程结构

switch( 变量或变量表达式) {
case 常量或常量表达式1:
case 常量或常量表达式2:
break;
}
遇到break跳出, 不然自上而下依次执行
default

switch( month ) {
day = 31;
case 1: case 3: case 5: case 7:
break;
}

if()else//存在临近性原则
if(){}
else if(){}
elseif(){}
else {}

if(表达式2)
	a =b;
	else
	a=c;

3.预处理

预处理指令类型:
(1)宏定义:#define–定义宏 #undef–删除宏

  • 宏定义的重点在于替换
#define F(x)  x*x//写法不安全可能不准确
//(2+5)  2+5*2+5
//改
#define F(x) (x)*(x) //安全准确
//注意宏的指针问题也是替换 -- 不同于typedef
  • NULL的定义:
#ifdef NULL
	#ifdef _cpluscplus
		#define NULL 0 //C++中NULL与0相同
	#else
		#define NULL ((void*)0)//C中NULL为一带类型的0
	#endif
#endif

(2)文件包含:#include–文件包含

(3)条件编译:#if #ifdef #elif #else #else #endif

  • 主要作用:一般是用来防止头文件被重复包含,提高编译效率的。

(4)特殊指令:#error #line #pragma

  • pragma
  1. pragma pack:是结构体( struct ),联合体(union),类(class)等的成员变量按指定的内存字节边界对齐的一种预处理指令。
    在32位上,这些类型默认使用一个机器字(4字节)对齐。
    在64位上,这些类型默认使用最大两个机器字(8×2=16字节)对齐
  2. pragma once:保证头文件只被编译一次
  3. pragma comment(…):引入库文件

4.数组、二维数组、指针

(1)数组
数组定义:相同类型的元素存储在连续空间里,这样的数据结构就是数组。
用法

  • 1)a表示数组名,首元素的地址,当a与sizeof()结合时表示整个数组大小,sizeof(a)=元素所占空间大小*元素个数。
  • 2)a+1,不存在a++,a的类型int * ,所以偏移指向元素的大小偏移,故为4个字节。
  • 3)&a &怎么理解?由于a是一个int * 类型,我们可知&a的类型即为int * [4],同时a与&a表示的地址相同,&a+1—>0x10+4 * sizeof(int) = 0x20,表示在a的基础上偏移a数组的大小的单位。
    (2)二维数组
    二维数组定义:二维数组是一维数组的一个扩展,如同套娃数组中带一个数组。
    用法:eg:a[3][10]
    1) a:数组名表示该数组首元素的地址,他的类型为int * [10],a+1表示的偏移量为10 * sizeof(int)。
    2)&a:&a 代表整个数组的地址, 他类型是指向整个数组 &a 的类型 就是 int ( * )[3][10]。&a +1 是多少? &a 的类型 就是 int ( * )[3][10] &a+1 是在a的基础上 移动 3 * 10个int。
    3)&a[0] :类型也是 int( * )[10] … 求 &a[0] + 1 与上面a+1相同
    4)a[0] :是第一个元素的名字, 也就是数组名, 也就是首元素地址 , 也就是 &a[0][0] 那么 a[0]的类型是 int*。

5.函数和指针

持续更新ing

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值