5.1 赋值语句
面试题1:考点,局部变量会屏蔽全局变量
因为变量定义即可见,int i = i 的操作并不会报错 ,i是随机值
int i = 1;
void main()
{
int i = i;
}
详见:https://blog.csdn.net/weixin_42219542/article/details/108309305
面试题2:考点,运算符执行顺序及返回状态
注意:==返回状态是0或者1。&和|是按位与和、或,返回值为具体计算后数据。&&和||是变量进行与、或,返回值为真假,是0或者1。
int main()
{
int x = 2, y, z;
x *=(y=z=5);
cout << x << endl; // 10
z = 3;
x == (y=z);
cout << x << endl; // 10,不变
x = (y ==z);
cout << x << endl; // 1,true
x = (y&z);
cout << x << endl; // 3, 位与
x = (y && z);
cout << x << endl; // 1, 变量与
y = 4;
x = (y | z);
cout << x << endl; // 7, 位或
x = (y || z);
cout << x << endl; // 1, 变量或
return 0;
}
面试题3:考点,x&(x-1)每次会将x中一位1转化成0,因此下面代码中count就是x转换二进制后1的个数。
int count = 0;
while(x)
{
count++;
x = x&(x-1);
}
x = 9999, 转化为2进制10 0111 0000 1111,8个1,因此count输出为8
5.2 i++
面试题1:考点,循环语句的执行顺序,还有一个考点,就是符号优先级,!x++是先执行!x,然后执行x++,返回值是!x
int i;
int a = 0;
for(i = 0; i < 10; i++)
{
a++;
}
执行顺序为i = 0 ==> 判断 i < 10(重要) ==> 执行循环内容 a++ ==> 执行i++ ==> 判断i<10 ==> 执行循环内容 ==> i++ ==> i<10 …
面试题2:考点,print语句的执行顺序
printf倒是挺正常,记住从右往左执行就好。cout有坑 https://editor.csdn.net/md?not_checkout=1&articleId=108313013
int arr[] = {6,7,8,9,10};
printf("%d, %d\n", *ptr, *(++ptr))
输出7,7
5.3 编程风格
面试例题:考点,1. 进行==判断要把变量放左面,这样要是误将 == 写成 =,编译器会报错 2. 能放在循环外的运算要放在循环外,可以提高性能
5.4 类型转换
c++定义了一组内置类型之间的标准转换,在必要的时候他们会被编译器隐式的应用在对象上。
典型情况:
- 混合类型的算数表达式中
最宽的数据类型为目标转换类型 - 用一种类型的表达式赋值给另一种类型
目标转换类型为被赋值对象的类型 - 把一个表达式传递给一个函数,调用表达式的类型和形参类型不相同
转化为形参类型 - 从一个函数返回一个表达式类型和返回类型不相同
转换为函数返回类型
两个转换原则:
- 为防止精度损失,如果必要,类型总会被转换为较宽的类型
- 如果有小于int的有序类型,都会被转化为int
宽度比较:long double > double > float > long int > int > short int > char > bool
5.5 运算符问题
面试题1:考点,类型转换和运算符优先级
#include<iostream>
using namespace std;
// int i = 1;
int main()
{
unsigned char a = 0xA5;
unsigned char b = ~a>>4+1;
for (int i=7;i>=0;i--) {
std::cout << ((b >> i) & 1); // 11111010
}
cout << endl;
cout << b << endl; // ?
cout << (int)b << endl; // 250
printf("%d\n", b); // 250
printf("%c\n", b); // ?
return 0;
}
首先注意,c++对于算数表达式,在运算之前会将其中小于整型的类型都转化成整型,其中char就是小于整型的,因此在运算前a会被转化成int,占4个字节。
然后考虑运算符优先级,~ 高于 + 高于 >>。
转化为(unsigned char)(~(int)a)>>(4+1)
运算步骤:a转int 0000 0000 0000 0000 0000 0000 1010 0101 ==> 进行~操作,结果 1111 1111 1111 1111 1111 1111 0101 1010 ==> 进行>>5操作,得到 0000 0111 1111 1111 1111 1111 1111 1010 ==> 转化成unsigned char,截断后8位 1111 1010 ,转换成unsigned int 就是250,转化成字符是 “?”,不知道大于128的时候十进制和ascii码之间是怎么转化的,这里没仔细研究。
面试题2, 面试题3,面试题4的考点都为位运算
面试题2:考点,x&(x-1)可以判断整数转化为二进制数后1的个数的变形
用一个表达式,判断一个数X是否为2的n次方。
!(X&(X-1))
若数是2的n次方,则其二进制中只有一个1,X&(X-1)=0
面试题3:考点,用位运算模拟求平均值
下面代码
int f(int x, int y)
{
return (x&y) + ((x^y)>>1)
}
x&y为x和y转化为二进制后相同位和的一半,(x^y)为x和y转化为二进制后不同位和,>>1是也取一半,则上面代码为求得x和y的平均值
面试题4:考点,用位运算实现两个数的和
int sum(int a, int b)
{
if (b == 0) return a;
int s, c;
s = a ^ b;
c = (a & b) << 1;
return sum(s, c);
}
转化为二进制加法运算,其运算可分为两部分考虑,一部分是位和,一部分是进位。
位和运算 1 + 0 = 1, 0 + 1 = 1, 1 + 1 = 0, 0 + 0 = 0,符合异或运算规律
进位运算 1 + 1 = 1,其余都是0,符合位与运算规律,因为进位是加给前一位的,因此位与运算后需要往前移动一位(a & b) << 1
当进位为0时,说明当前位和结果即为最终结果,递归结束。
5.6 a、b交换与比较
面试题1,2:考点,不用if,?等判断语句实现两个数对比
bool fun(int a, int b)
{
return a>b;
}
int max(int a, int b)
{
bool flag = fun(a, b);
return flag * a + (1-flag) * b;
}
面试题3:考点,数据交换
针对整数
void swap(int &a, int &b)
{
a = a ^ b;
b = a ^ b; // (a^b)^b,转化后b=a
a = a ^ b; // (a^b)^a
}
针对浮点数,采用内存交换
#define swap(a, b) \
{
char tempBuf[10];
memcpy(tempBuf, &a, sizeof(a));
memcpy(&a, &b, sizeof(b));
}
5.7 c和c++的关系
面试题1:考点,重载是c++中独有概念
为什么在c++程序中用c编译器编译出来的函数要加extern c
答:c中没有重载概念,在c中某函数原型为void foo(int x, int y)被c编译器编译后在库中名字是_foo,被c++编译器编译完后期名字为_foo_int_int。extern C解决名字匹配问题。
面试题2:考点,头文件中#ifndef,#define,#endif作用
防止头文件被重复引用,或者防止重复定义(变量,宏或者结构)
面试题3:考点,c和c++各自的特点
c语言为面向过程的结构化语言,c++在c基础上扩展了面向对象的部分。c语言程序设计,首次考虑如何通过一个过程,对输入进行计算处理得到输出。c++程序设计,首先考虑如何构造一个对象模型,让这个模型能够契合与之相应的问题域。这样就可以通过获取对象的状态信息获取得到输出或实现过程控制。