程序员面试宝典学习笔记 第5章 程序设计基本概念

目录

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++定义了一组内置类型之间的标准转换,在必要的时候他们会被编译器隐式的应用在对象上。
典型情况:

  1. 混合类型的算数表达式中
    最宽的数据类型为目标转换类型
  2. 用一种类型的表达式赋值给另一种类型
    目标转换类型为被赋值对象的类型
  3. 把一个表达式传递给一个函数,调用表达式的类型和形参类型不相同
    转化为形参类型
  4. 从一个函数返回一个表达式类型和返回类型不相同
    转换为函数返回类型

两个转换原则:

  1. 为防止精度损失,如果必要,类型总会被转换为较宽的类型
  2. 如果有小于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++程序设计,首先考虑如何构造一个对象模型,让这个模型能够契合与之相应的问题域。这样就可以通过获取对象的状态信息获取得到输出或实现过程控制。


5.8 程序设计的其余问题

面试题1:考点,switch case后面语句不加break,会继续执行后面的

面试题2:考点,设计程序健壮性,例如过滤异常值,除法除数不为0等。

猜你喜欢

转载自blog.csdn.net/weixin_42219542/article/details/108311082
今日推荐