C/C++小知识点速记(笔试面试)

 1.指针与数组要注意的点:

●数组:生命数组变量时,一定要写出申请空间,可以使宏常量,但不能是变量,就算变量已经被赋值;

●指针:指针变量声明时的*只是一个指针类型说明符;而在非变量声明语句中,*才是指针运算符;

●指针和变量:数组名a代表数组的首地址;

a=&a[0];

*a=a[0];

a+i=&a[i];

*a+i=a[i];

若整形指针变量p指向整形数组a的首地址,那么可以通过指针变量p访问数组a的元素;此时p+1p++不同,p+1不改变原来指针变量p的值,而p++则使指针变量p的指向放后移了一位;

2. C++类构造函数初始化列表

构造函数初始化列表以一个冒号开始,接着是以逗号分隔的数据成员列表,每个数据成员后面跟一个放在括号中的初始化式。例如: 

class CExample {
    public:
    int a;
    float b;
    //构造函数初始化列表
    CExample(): a(0),b(8.8){}
    //构造函数内部赋值
    CExample()
    {
        a=0;
        b=8.8;
    }
};
    1. 内置类型的自身对齐模数(有符号无符号相同) 
      char 1 
      short 2 
      int 4 
      float 4 
      double 8

指针即为地址,指针几个字节跟语言无关,

而是跟系统的寻址能力有关,

譬如以前是16位地址,指针即为2个字节,

现在一般是32位系统,所以是4个字节,

以后64位,则就为8个字节。

*指针指向的地址长度与主机字长相同32:4;64:8;位除8;

字节对齐三规则:其实字节对齐的细节和具体编译器实现相关,但一般而言,满足三个准则:

1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;

2) 结构体每个成员相对于结构体首地址的偏移量都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节;例如上面第二个结构体变量的地址空间。

3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节。

C++的类

class Test
{
    int a;
    char b;
}
Sizeof(Test)=8;

对齐规则:aint类型占4字节;bchar类型占1字节;相加为5,比5大且为4的倍数值为8

  1. 将公共基类指定为虚基类,就可以使该基类的成员在派生类中只有一份拷贝。

3.运用后缀表达式进行计算的具体做法:

建立一个栈S 。从左到右读表达式,如果读到操作数就将它压入栈S中,如果读到n元运算符(即需要参数个数为n的运算符)则取出由栈顶向下的n项按操作符运算,再将运算的结果代替原栈顶的n项,压入栈S中 。如果后缀表达式未读完,则重复上面过程,最后输出栈顶的数值则为结束。

例 : 6 5 2 3 + 8 * + 3 + *

转换成中缀表达式:6*(3+5+(3+2)*8)

4.前缀表达式的计算机求值

从右至左扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(栈顶元素 op 次顶元素),并将结果入栈;重复上述过程直到表达式最左端,最后运算得出的值即为表达式的结果

  • 例如:- × + 3 4 5 6
    • 从右至左扫描,将6、5、4、3压入堆栈
    • 遇到+运算符,因此弹出3和4(3为栈顶元素,4为次顶元素,注意与后缀表达式做比较),计算出3+4的值,得7,再将7入栈
    • 接下来是×运算符,因此弹出7和5,计算出7×5=35,将35入栈
    • 最后是-运算符,计算出35-6的值,即29,由此得出最终结果
    • 注意:遇到 前缀表达式:/ab其运算过程为b入栈,a入栈,/来,栈顶的数a为被除数(被别人除的那个数),所以转换成中缀表达式就是a/b;

5.设计原则

我们一共介绍了 7 种设计原则,它们分别为

开闭原则、里氏替换原则、依赖倒置原则、单一职责原则、接口隔离原则、迪米特法则和合成复用原则。
这 7 种设计原则是软件设计模式必须尽量遵循的原则,各种原则要求的侧重点不同。其中,开闭原则是总纲,它告诉我们要对扩展开放,对修改关闭;里氏替换原则告诉我们不要破坏继承体系;依赖倒置原则告诉我们要面向接口编程;单一职责原则告诉我们实现类要职责单一;接口隔离原则告诉我们在设计接口的时候要精简单一;迪米特法则告诉我们要降低耦合度;合成复用原则告诉我们要优先使用组合或者聚合关系复用,少用继承关系复用。

6.ftp默认端口为21

7.补码

正数

正整数的补码是其二进制表示,与原码相同 [2]  

负数

求负整数的补码,将其原码除符号位外的所有位取反(0110,符号位为1不变)后加

同一个数字在不同的补码表示形式中是不同的。比如-15的补码,在8位二进制中是11110001,然而在16位二进制补码表示中,就是1111111111110001。以下都使用82进制来表示。

【例2】求-5的补码。

-5对应正数500000101所有位取反(111110101(11111011)

所以-5的补码是11111011

【例3】数0的补码表示是唯一的。

[+0]=[+0]=[+0]=00000000

[ -0]=11111111+1=00000000

转化为原码

已知一个数的补码,求原码的操作其实就是对该补码再求补码:

如果补码的符号位为“0”,表示是一个正数,其原码就是补码。

如果补码的符号位为“1”,表示是一个负数,那么求给定的这个补码的补码就是要求的原码。

【例4】已知一个补码为11111001,则原码是10000111-7)。

因为符号位为“1”,表示是一个负数,所以该位不变,仍为“1”

其余七位1111001取反后为0000110

再加1,所以是10000111

补码的绝对值

【例5-65的补码是10111111

若直接将10111111转换成十进制,发现结果并不是-65,而是191

事实上,在计算机内,如果是一个二进制数,其最左边的位是1,则我们可以判定它为负数,并且是用补码表示。

若要得到一个负二进制补码的数值,只要对补码全部取反并加1,就可得到其数值。

如:二进制值:10111111-65的补码)

各位取反:01000000

101000001+65

关于补码有个小技巧:例如长度为一个字节(8bit)时,-1补码2^8-1=255,即负数的补码等于对应长度的模减当前值

8. 子类对象可以隐式的转换为父类对象。

9.使用sort排序:需要头文件#include

sort(vec.begin(),vec.end());(默认是按升序排列,即从小到大).

可以通过重写排序比较函数按照降序比较,如下:

定义排序比较函数:

bool Comp(const int &a,const int &b)
{
    return a>b;
}

 

调用时:sort(vec.begin(),vec.end(),Comp),这样就降序排序。 

9.前序遍历,中序遍历,后序遍历

例图: https://gss0.bdstatic.com/94o3dSag_xI4khGkpoWK1HF6hhy/baike/s%3D220/sign=cf18e0e28735e5dd942ca2dd46c7a7f5/4034970a304e251f1510e448a586c9177e3e539e.jpg

前序遍历:(根左右)ABDECF

中序遍历:(左根右)DBEAFC

后序遍历:(左右根)DEBFCA

10.哈希表-散列存储(拉链法)

哈希表装填因子定义为:α= 填入表中的元素个数 / 哈希表的长度

α是哈希表装满程度的标志因子。由于表长是定值,α与“填入表中的元素个数”成正比,所以,α越大,填入表中的元素较多,产生冲突的可能性就越大;α越小,填入表中的元素较少,产生冲突的可能性就越小。

例题

C/C++小知识点速记(笔试面试)_第1张图片

查找成功时的平均查找长度:

ASL = (1*6+2*4+3*1+4*1)/12 = 7/4

查找不成功时的平均查找长度:

ASL = (4+2+2+1+2+1)/13

注意:查找成功时,分母为哈希表元素个数,查找不成功时,分母为哈希表长度。

11函数指针*fun

函数指针的赋值直接引用函数名和在函数名上取地址符号是等价的。

12.vector二维动态数组初始化

//1初始化m*n的二维数组,初始值为0
vector> vec(m,vector(n,0));
//1初始化m*n的二维数组
vector> vec(m,vector(n));
//2 获取一维数组的长度  
int size = vec.size();  
//3 获取二维数组的长度  
int size_row = vec.size(); //获取行数  
int size_col = vec[0].size(); //获取列数  
//4 给vector二维数组赋值  
//简单的就直接赋值  
ans[0][0]=1;  
ans[0][1]=2;  
ans[1][0]=3;  
ans[1][1]=4;  

 

13. 迭代器可以看成一个指针,指针没有移位运算

14.物理地址与IP地址转换的协议

ARPIP->MAC

RARPMAC->IP

15. 作业调度只能创建进程将其调入内存,进程调度才能获取CPU。

16. #include包含了C/C++的所有头文件

17.牛客代码编译器报段错误时,解决方案:

不要惰性申请a[1000]这样的空间,太浪费了,换成vector容器。

18.

如果系统只有用户态线程,则线程对操作系统是不可见的,操作系统只能调度进程;

如果系统中有内核态线程,则操作系统可以按线程进行调度;

19. 按记录的逻辑结构分

文件分为堆文件、索引文件、索引顺序和顺序文件

20.结构体定义

C中定义一个结构体类型要用typedef:
    typedef struct Student
    {
    int a;
    }Stu;
    于是在声明变量的时候就可:Stu stu1;(如果没有typedef就必须用struct Student stu1;来声明)
    这里的Stu实际上就是struct Student的别名。Stu==struct Student
    另外这里也可以不写Student(于是也不能struct Student stu1;了,必须是Stu stu1;

21.vector查找元素

#include   
#include   
#include   
int main( )  
{  
    using namespace std;   
    vector L;  
    L.push_back( 1 );  
    L.push_back( 2 );  
    L.push_back( 3 );  
    L.push_back( 4 );  
    L.push_back( 5 );  
    vector::iterator result = find( L.begin( ), L.end( ), 3 ); //查找3  
    if ( result == L.end( ) ) //没找到  
        cout << "No" << endl;  
    else //找到  
        cout << "Yes" << endl;  
}  

 

22.字符串长度,数组长度,数组指针长度

int main() {  
    char str[6] = "hello";  
    getStrSize(str);  
    cout << "数组大小:" << sizeof(str) << endl;  
    return 0;  
}  
void getStrSize(char* str) {  
    cout <<"字符长度:"<< strlen(str)<

 

输出结果:

字符长度:5

指针大小:4

数组大小:6

23.结构体,类,共用体所占内存字节数

typedef struct test1 {  
    int a;  
    short b;  
    char c;  
}TEST;  
class test2 {  
    int a;  
    short b;  
    char c;  
};  
union test3  
{  
    int a;  
    short b;  
    char c;  
};  
int main() {  
    cout << "结构体的内存大小:" << sizeof(TEST) << endl;  
    cout << "类的内存大小:" << sizeof(test2) << endl;  
    cout << "共用体的内存大小:" << sizeof(test3) << endl;  
    return 0;  
}  

 

输出结果:

结构体的内存大小:8

类的内存大小:8

共用体的内存大小:4

计算方法:

结构体内存大小和类的内存大小一样算:三个变量大小相加4+2+1=7比7的三个数的最小公倍数是8;而共用体就看最长的那一个。

plus1:果类中有虚函数对齐后再加上虚指针大小(系统位/8===普通指针大小的计算相同);

plus2:对于有数组的数据成员,先不管数组大小计算公倍数先,然后大于计算数组的总大小后的大小的最小公倍数就是了

23.运算符优先级(看API稳一手)

优先级 

   操作符

1

()

[]

->

.

 

::

     
 

!

~

++

--

2

- (unary),sizeof

* (解引用)

 

& (address of)

sizeof

3

->*

.*

   

4

* (multiply)

/

%

5

+

-

6

<<

>>

7

<

<=

>

>=

8

==

!=

9

& (bitwise AND)

10

^

11

|

12

&&

13

||

14

? :

15

=

+=

-=

etc.

16

,

24.各种查找和排序算法的时间复杂度

https://uploadfiles.nowcoder.com/images/20190313/311436_1552474444160_93CF294B0FB45C83DC616C5700184F2E

C/C++小知识点速记(笔试面试)_第2张图片

C/C++小知识点速记(笔试面试)_第3张图片

斐波那契查找 时间复杂度 O(logn)

25.稳定的排序算法

基数排序、冒泡排序、直接插入排序、折半插入排序、归并排序

26.数组长度求法

*关于strlen的用法,碰到字符数组中’\0’立马停止计算,且不把’0’记入长度

//整形数组
int a[] = { 0,1,5,2,4,3,5 };
int len = end(a) - begin(a);

或者是sizeof(a)/sizeof(a[0])

//字符数组
#include
int len=strlen(a)-1;
//向量数组
int len=a.size();

27.数组的值初始化

int a[6];
memset(a, 0, sizeof(a));

28.递归公式的时间复杂度

master公式的使用】

T(N) = a*T(N/b) + O(N^d)

T(N)是样本量为N的情况下的时间复杂度,a是子过程的部分,N/b是子过程的运行次数,N^d剩余其他的过程。

1) log(b,a) > d -> 复杂度为O(N^log(b,a))

2) log(b,a) = d -> 复杂度为O(N^d * logN)

3) log(b,a) < d -> 复杂度为O(N^d)

例题:

https://uploadfiles.nowcoder.com/images/20190829/826546_1567049407915_38C076F48371BE26D704273AE1B35592

答:a=4,b=2,d=1;log(b,a)=2>d;复杂度为n^log(4,2)=n^2;

快速记忆: a,b,d;

log(b,a)>=

n^log(b,a);n^d*logn;n^d;

 

29.二叉树度与节点的计算关系

1.深度为h的二叉树最多有n^h-2个节点;

2.二叉树终端节点为n0,度为1的节点为n1,度为2的节点为n2,节点总数为n;

则有n0=n2+1;n=n0+n1+n2;树枝总条数=2*n2+n1;因此n=2*n2+n1+1;

因此n0=n2+1;

30.出栈序列存在多少种可能的问题

C/C++小知识点速记(笔试面试)_第4张图片

C/C++小知识点速记(笔试面试)_第5张图片

31. 计算机算法指的是:解决问题的步骤序列

32.自定义构造函数后,还会生成默认构造函数吗

void XX();        1

void XX(...);     2

 

XX xx;没有自定义1,就还是用的默认的

XX xx(...); 即使定义了1,还是会调用默认的构造函数

33.多维数组的元素与地址的关系

int a[2][2][3]= { {{1,2,3},{4,5,6}},{{7,8,9},{10,11,12}}};

1. &a+i = a + i*sizeof(a); 

2. a+i = a +i*sizeof(a[0]);

34.宏定义中##的作用

分隔符

#define A1(name, type)  type name_##type##_type 

#define A2(name, type)  type name##_##type##_type

A1(a1, int);  /* 等价于: int name_int_type; */

A2(a1, int);  /* 等价于: int a1_int_type;   */

35. 首先使用scanf读取键盘输入,因scanf在读取字符串时,遇到空白字符(空格、制表符和回车等)会结束输入

36.16 位机器中int占2字节

37.关于指针的按值传递

void swap(int *p, int *q) {
    int t;
    t = *p;
    *p = *q;
    *q = t;
}

p,q指针指向对象的值会进行交换,但p,q的地址不会发生交转。

38.非零数值的条件判断

#include
using namespace std;
int main() {
	int  x = 23;  
	do
	{ 
		cout << x--;
	} while (!x);
	return 0;
}

输出:23

这么理解吧:第一次循环肯定执行一次,输出23,然后!22怎么看,22非零,n那么!22就是零,所以条件为假,跳出循环;

39.关于连等以及i++和++i的运算顺序问题

#include
using namespace std;
int main() {
	int a = 0, b = 0,x=0;
	x = a++, b++;
	cout << x;//x=0
	x = a += 1;
	cout << x;//x=2
	x = a += b;
	cout << x;//x=3
	return 0;
}

输出:023

连等的话,从右往左算,中途对应的变量值会变化;

但是x=a++相当于x=a;a=a+1;

而x=++a就相当于x=a=a+1;

你可能感兴趣的:(C++,笔试面试,小知识点,C++)