【转载】易被遗忘的C/C++要点总结

Posted on Posted in 计算机1,226 views

访问原文

1460336999678630.png

1460340451609230.png

一、 数据类型及运算

1.1、求补码

    原码的基础上, 符号位不变, 其余各位取反, 最后+1

    原码转补码不考虑符号位

    补码转原码,符号位不参与运算

    取反后 + 1 == 取反前 – 1

1.2、科学计数法表示

    1.8 * 10^11  –> 1.8E11

    9.34 * 10^-3 –> 9.34E-3

1.3、相关细节

    sizeof()是一个运算,而非函数

    ++运算不能用在实数上

    判断一个整数是否是2^n(2,4,6,8,16…)     !(x & (x – 1))

    三目条件运算符代码更优

        编译器能产生比if…else…更优的代码

1.4、运算符优先级、结合方向规则

    单目 > 双目

    算术 > 关系 > 位  > 逻辑  > 条件(三目)> 赋值 > 逗号

        算术: + – * /

        关系: > < >= <=

        位: & | ^

        单目: ~

        逻辑: && ||

        单目: !

    自右向左的三种运算符

        单目

        赋值

        条件

1.5、数据输入与输出

    printf()语句从右向左计算输出表达式的值

i = 1;  
printf("%d, %d\\\\n", i++, i--);  
//res: 0,1
//先执行i--,再执行i++

1.5、常用输出函数

    printf()

    putchar()

        输出一个字符

        必须是字符型变量或常量

    puts()

        输出一个字符串

        必须是字符串或常量

1.6、常用输入函数

    scanf()

    gets()

        每次读取一个字符串

    getche()

        conio.h中

        读取字符不用按回车

    getchar()

        stdio.h中

        完成后须按回车

    getche() & getchar():

        每次读取一个字符

    scanf() & gets()区别:

        scanf不能输入含空格字符串,gets可以

二、选择语句和循环语句

2.1、switch:case 常量表达式

    常量表达式只能为整型、字符型

    不允许浮点型

三、数组

3.1、定义

    定义数组未赋初值

        Turbo C会给数组置0

        VC则取随机值

    定义静态数组,则系统自动赋0

3.2、比较字符串数组中的值

    C: strcmp(str1,str2)

    C++:  str1 == str2

    JAVA:str1.equals(str2)

        java中,str1 == str2 比较的是地址

四、指针

4.1、指针运算

    指针相减: 表示两指针所指地址之间的数据个数

    指针相加: 没有意义,错误

4.2、数组与指针

1、一维数组首地址

int a[10], *p;
p = &a[0];
p = a            //等价,将数组首元素的首地址赋给指针p

    表示:

       &a[0],  a:数组首元素的首地址

       &a: 数组首地址

     对比:

a == &a[0]
a != &a    //地址值相同,含义不同

2、二维数组首地址

int a[10][10];

    地址值相同,含义不同:

    a:

        二维数组首元素首地址

        代表一维数组元素的首地址

    &a: 

        数组首地址

    &a[0]:

        二维数组首元素首地址

    &a[0][0]:

        &a[0][0] != a

        a[0] == &a[0][0]

3、二维数组指针

    int (*p)[3]:

        指向含3个元素的二维数组的行指针

        数组每列有3个元素

    int p[3] & int (p[3]):

        指针数组,每个元素均是一个指针

4.3、指针与引用的区别

    非空区别

        不能使用指向空值的引用

        不存在指向空值的引用

        效率比使用指针高

        引用必须总是指向某些对象

        指针可以指向空值

    合法性区别

        使用引用前,无需测试其合法性

        使用指针总是需要判空

    可修改区别

        总指向初始化时被指定的对象

        以后都不能改变

        但指定对象的内容可以改变

        指针可被重新赋值,以指向另一对象

        引用

    应用区别

        指向一个对象后就不会改变指向的情况

        存在不指向任何对象的情况

        不同的时刻指向不同对象的情况

        指针场景

        引用场景

    ps:声明引用 const常量 的同时,必须初始化

4.4、函数指针

    float(**def)[10];

        二级指针

        指向一个一维数组的指针

        数组元素都是float

    double(gh)[10];

        指针gh,指向一个一维数组

        该数组元素的类型均为double *

    double(*f[10])();

        没有参数

        返回double类型的值

        元素都是函数指针

        f是一个数组,含10个元素

        指向的函数

    int ( (b)[10] );

        和int (b)[10]一样

    Long (* fun)(int)

        函数指针

五、类型转换

5.1、(int &)相关

    float a = 1.0f;

    (int)a实际上是以浮点数a为参数构造了一个整型数,该整数的值是1。

    (int&)a则是告诉编译器将a当作整数看(并没有做任何实质上的转换)。

5.2、unsigned int 

    unsigned int  a = 0xFFFFFFF7;

    unsigned char i = (unsigned char)a;

        i:   000000f7

    char b = (char )&a;

        *b:  fffffff7

5.3、隐式类型转换

    算术运算式中,低类型能够转换为高类型

    赋值运算式

        右边表达式的值自动隐式转换为左边变量的类型,并赋值给他

    函数调用中参数传递时,系统隐式地将实参转换为形参的类型后,赋给形参

    函数有返回值时,系统将隐式地将返回表达式类型转换为返回值类型,赋值给调用函数

六、位运算相关

6.1、取两数的平均值:

(x & y) + [(x ^ y) >> 1]

6.2、另类取两数较大值:

max = [(a + b) + abs(a - b)] / 2

6.3、三数取中间数:

t1 = max(a, b);
t2 = max(b, c);
t3 = max(a, c);
min( t1, min(t2, t3) )

6.4、交换变量:

x=x^y;
y=x^y;
x=x^y;
//或者:
x=x+y;
y=x-y;
x=x-y;

七、函数

7.1、静态函数: 

    不可被其他文件调用的函数

7.2、函数重载:

    参数类型不同

    参数个数不同

    对返回类型没有要求

八、#define & const & sizeof

8.1、#define实例

* #define SEC (60 * 60 * 24 * 365)UL
* #define MIIN(A, B)    ( (A) <= (B) ? (A) : (B) )

8.2、const,#define的区别

    const

        有数据类型

        可进行类型安全检查

        可对其进行调试

    #define

        没有数据类型

        仅进行字符替换,没有类型安全检查

        无法调试

    c中const

        被当做一个不能被改变的普通变量

    error

const bufsize = 100;  
char buf[bufsize];

8.3、字节对齐

    数据对齐规则

        结构的首地址必须是结构内最宽类型的整数倍地址

        结构体的每一个成员起始地址必须是自身类型大小的整数倍

    结构体的整体大小必须可被对齐值整除

    结构体的整体大小必须可被本结构内的最宽类型整除

8.4、sizeof

    结构体或类内的静态变量

struct s{
      int a;
      static int b;
  };
s ss;  
sizeof(ss)
// 结果:4

    静态变量存放在全局数据区

    sizeof计算栈中分配的大小

    任何类型指针大小相同:4(32位)

    对函数使用sizeof

    在编译阶段会被函数返回值的类型取代

    空类大小

        单继承:1

        多继承:1

        虚继承:4

        涉及虚表(虚指针)

8.5、内联函数 vs. 宏

    内联

        相比普通函数: 加快程序运行速度

        直接嵌入目标代码

        要做参数类型检查

    宏

        简单的替换

        不做参数类型检查

九、 C++面向对象

9.1、类和对象

    类对象的存储空间

        只为每个对象的数据成员和函数地址分配内存空间

        类中所有成员函数只生成一个副本

        该类每个对象执行相同的函数成员

    拷贝构造函数

        功能:用一个已知的对象来初始化一个被创建的同类的对象

        特点:函数只有一个参数,并且是对某个对象的引用

           每个类都必须有一个拷贝初始化构造函数

        格式:类名::拷贝初始化构造函数名(const 类名 &引用名)

    静态成员

        静态数据成员

        类名::静态数据成员名

        类的所有对象共享

        必须初始化,且要在类外初始化

        特点

        引用格式

    静态成员函数

        类名::静态成员函数名

        类的所有对象共享

        只能使用类的静态成员和非数据成员

        特点

        引用格式

    类成员指针

        const成员函数

        定义: 任何不修改成员数据的函数都应声明为const函数

        原型: int GetY() const;

        细节:

            const函数想修改成员变量

            在相应变量定义处加上mutable

            mutable int m_Count;

9.2、友元函数  

    定义

        需在类体内声明

        可访问类的私有成员

        不是类的成员函数

    优点:提高程序运行效率

    缺点:破坏类的封装性和隐藏性

    特点:可以是多个类的友元

9.3、继承和派生

    公有继承

        派生类成员函数可访问基类中的公有成员和保护成员

        派生类的对象仅可访问基类中的公有成员

    派生类

        构造函数执行顺序

            基类构造函数

            子对象类的构造函数(如果有的话)

            派生类构造函数

        析构函数执行顺序

            派生类的析构函数

            基类的析构函数

9.4、虚基类


转载标明出处:https://blog.evanxia.com/2016/04/380