(欧) 第5章 程序设计基本概念

1 分析下列程序:

#include<iostream>
using namespace std;
int i=1;
int main() {
	int i=i;
	cout<<i<<endl;
}
输出结果是0.

分析:对于int i=i;这样的写法在C++中是完全合法的(但是不合理)。int i=i,i变量从声明的那一刻开始就是可见的了,main()里的i不是1,因为它和main()外的i无关,而是一个未定义值。

2 分析下列程序:

#include<iostream>
using namespace std;
int func(int x) {
	int count=0;
	while(x) {
		count++;
		x=x&(x-1);
	}
	return count;
}

int main() {
	cout<<func(9999)<<endl;
}
输出结果是8. 9999的二进制是10011100001111,计算一个数中的1的个数。


3 比较下述两个程序:

#include<iostream>
using namespace std;
int main() {
	int a,x;
	for(a=0,x=0;a<=1 && !x++;a++) {
		a++;
	}
	cout<<a<<x<<endl;
}
输出结果是21.

分析:a<=1, !x为1,符合循环条件,x++后x自增为1;进入循环体,a++,a自增为1;执行for循环中的a++,a自增为2;现在a已经是2,已经不符合小于等于1的条件了,所以&&后面的!x++不执行,x还是1,不执行循环体。


#include<iostream>
using namespace std;
int main() {
	int a,x;
	for(a=0,x=0;a<=1 && !x++;) {
		a++;
	}
	cout<<a<<x<<endl;
}
输出结果是12

分析:a<=1,!x为1,符合循环条件;x++后自增为1;进入循环体,a++,a自增为1;a现在是1,符合小于等于1的条件,所以&&后面的!x++被执行,x现在是1,x的非为0,不符合循环条件,不执行循环体,但x++依然执行,自增为2。


4 分析下列程序:

#include<iostream>
using namespace std;

int main() {
	int b=3;
	int arr[]={6,7,8,9,10};
	int *ptr=arr;
	*(ptr++)+=123;//这句话可以分成两句: *ptr=*ptr+123;ptr++; 
	printf("%d,%d\n",*ptr,*(++ptr));
	return 0;
}

输出结果是8,8.

注意:C中printf计算参数时是从右向左压栈的。

printf("%d\n",*ptr);此时ptr应指向第一个元素6.

*(ptr++)+=123;这句程序可以分成两句: *ptr=*ptr+123;ptr++; ,此时ptr应该指向第二个元素7.

printf("%d\n",*(ptr-1));此时输出第一个元素129,注意此时是经过计算的。
printf("%d\n",*ptr);此时输出第二个元素7,此时ptr还是指向第二个元素7.

printf("%d,%d\n",*ptr,*(++ptr));从右向左运算,第一个是(++ptr),也就是ptr++,*ptr=8,此时ptr指向第三个元素8,所以全部都是8.



5 分析下列程序:

if(‘A’==a)
 cout<<a++;

if(a=='A')
 cout<<a++;
第一种写法比较好,因为如果把==写成=的话,因为编译器不允许对常量赋值,就可以检查到错误。


6 分析下列程序:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<conio.h>
using namespace std;

int main() {
	float a=1.0f;
	cout<<(int)a<<endl;
	cout<<&a<<endl;
	cout<<(int&)a<<endl;
	cout<<boolalpha<<((int)a == (int&)a)<<endl;
	
	float b=0.0f;
	cout<<(int)b<<endl;
	cout<<&b<<endl;
	cout<<(int &)b<<endl;
	cout<<boolalpha<<((int)b == (int &)b)<<endl;	
	return 0;
}

发现12行 cout<<boolalpha<<((int)a == (int&)a)<<endl;输出结果是false,第18行 cout<<boolalpha<<((int)b == (int &)b)<<endl;输出结果是true。

这是因为浮点数在内存里和整数的存储方式不同,(int&)a相当于将该浮点数地址开始的sizeof(int)个字节当成int型的数据输出,因此这取决于float型数据在内存中的存储方式,而不是经过(int&)a显示转换的结果(1)。

因为float a=1.0f在内存中的表示都是3f800000,而浮点数和一般整形不一样,所以当(int&)a强制转换时,会把内存3f8000000当做int型输出,所以结果是1065353216,即

0x3f8000000的十进制。



7 分析下述程序:

#include<iostream>
using namespace std;

int main() {
	unsigned int a=0xFFFFFFF7;
	unsigned char i=(unsigned char)a;
	char *b=(char*)&a;
	printf("%08x,%08x",i,*b);
}

输出结果:000000f7,fffffff7.

分析:在X86系列的机器中,数据的存储是“小端存储”,小端存储的意思是,对于一个跨多字节的数据,其低位存放在低地址单元,其高位存放在高地址单元。比如一个int型的数据0x12345678,假如存放在0x00000000,0x00000001,0x00000002,0x00000003这四个内存单元中,那么0x00000000中存放的是低位的0x78,而0x00000003中存放的是高位的0x12,依此类推。

分析第二个为什么输出fffffff7. &a可以认为是个指向unsigned int类型数据的指针,(char *)&a把&a强制转换成char *类型的指针,并且这个时候发生了截断!截断后,指针b只指向0xf7这个数据。(为什么 b指向最低位的0xf7而不是最高位的oxff?想想上面刚刚讲过的小端存储,低地址单元存放低位数据),又由于指针b是char*型,属于有符号数,所以有符号数0xf7在printf()的作用下输出fffffff7.


8 分析下列程序:

#include<iostream>
using namespace std;

int main() {
	unsigned char a=0xA5;
	unsigned char b=~a>>4+1;
	//cout<<b<<endl;;
	printf("b=%d\n",b);
}

输出结果是:250.

对于第一个问题:unsigned char b=~a>>4,在计算这个表达式的时候,编译器会先把a和4的值转换为int类型(即所谓整数提升)后再进行计算,当计算结果出来后,再把结果转换成unsigned char赋值给b。

对于第二个问题:因为"~"优先级高于“>>”和“+”,本题过程是这样的:先对1010 0101取反0101 1010,再右移;因为+的优先级高于>>,所以直接右移5位,结果是0000 0010.

~a操作时,会对a进行整形提升,a是无符号的,提升时左边补0,(一般机器32位,char是8位,左边24个1;16位int则左边补8个0),取反后左边为1,右移就把左边的1都移动到右边(注意是算术移位),再按照无符号读取,才有250这个结果。


https://zhidao.baidu.com/question/1948282626282180428.html

https://zhidao.baidu.com/question/1692154523174105708.html

(~a) 这是个比较困扰人的地方,如果你的编译环境中将char升为int处理的话,答案就是

(~ 0000 0000 1010 0101) = (1111 1111 0101 1010)

(~ a) >> 5 就是 0000 0111 1111 1010

但是的b也是unsigned char类型,所以赋值后b = 0000 0000 1111 1010 = 250(10进制)

9 用一个表达式,判断一个数X是否是2^N次方(2,4,8,16……),不可用循环语句。

分析:2,4,8,16转化成二进制是10,100,1000,10000。如果X减一后与X做运算,答案若是0,则X是2^N次方。  !(X&(X-1))

10  分析下列程序:

#include<iostream>
using namespace std;
int f(int x,int y) {
	return (x&y)+((x^y)>>1);
}
int main() {
	cout<<f(729,271)<<endl;
	return 0;
}


输出结果500. 分析:x&y是取相同的位与,这个结果是x和y相同位的和的一半,x^y是取x和y的不同位,右移相当于除以2,所以这个函数功能是取两个数的平均值、

11 利用位运算实现两个整数的加法运算。

int Add(int a,int b) {
	if(b==0) return a;//没有进位的时候完成运算 
	int sum,carry;
	sum=a^b;//完成第一步没有进位的加法运算 
	carry=(a&b)<<1;//完成第二步进位并且左移运算 
	return Add(sum,carry); //进行递归,相加 
}


12 有两个变量a和b,不准用while,if,for,switch或其他语句,找出最大值?

int max=((a+b)+abs(a-b))/2;


13 C++和C的关系

(1)在C++程序中调用被C编译器编译后的函数,为什么要加extern ”C“?

答案:C++语言支持函数重载,C语言不支持重载。函数被C++编译后再库中的名字与C语言不同。假设某个函数的原型是void foo(int x,int y),该函数被C编译器编译后再库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字。

C++提供了C连接交换指定符号extern "C"解决名字匹配问题。

(2)头文件中的ifdef/define/endif是干什么用?

答案:头文件中的ifdef/define/endif是条件编译的一种,除了头文件被防止重复引用(整体),还可以防止重复定义(变量、宏或者结构)。

(3)如何评价C、C++各自特点?

答案:C是一种结构化语言,重点在于算法和数据结构。C程序的设计首先考虑的是如何通过一个过程,对输入进行运算处理得到输出。而对于C++首先考虑的是如何构造一个对象模型,让这个模型能够契合与之对应的问题域,这样就可以通过获取对象的状态信息得到输出或实现过程控制。

对于大规模数值运算,C/C++和Java/.NET没有明显性能差异,不过,如果运算设计向量计算,矩阵计算,可以使用FORTRAN或者MATLAB编写计算组件。

大规模用户界面相关的软件可以考虑使用.NET进行开发(windows环境下),而且.NET同COM之间的互操作十分容易,同时.NET对数据库访问的支持也好。

《程序员面试宝典》 欧立奇 P30~P45


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值