本篇文章送上5道c/c++面试题目,并附上答案、解题思路以及扩展知识。ios
#include <stdio.h> int func(int x) { int iCnt = 0; while(x) { iCnt++; x = x&(x-1); } return iCnt; } int main() { printf("cnt = %d\n", func(9999)); return 0; }
这题问的是函数的返回值,而经过代码咱们能看到返回值的多少取决于x何时变为0,而x的值又取决于x&(x-1)
这个表达式,在c++中有一个规则,凡是看到&或者|这样的符号,那就把它左右两边的值转换为二进制去计算,假设x是7,转换为二进制是00000111,x-1那就是00000110,那x&(x-1)
就变成00000110了,再减一个1,变成00000101,那x&(x-1)
就是00000100,因此实际上这个表达式每执行一次,二进制就少一个1,这样的话,这篇题目就转换成了,输入的数字转换为二进制有多少个1,那么返回值就是多少。c++
9999转换为二进制是10011100001111,因此本道题目答案:cnt = 8
。面试
给一段代码,以下:函数
#include <stdio.h> void testputs() { unsigned int a = 6;//无符号整型 int b = (-20);//有符号整型 (a+b) > 6 ? puts(">6"):puts("<6"); } int main() { testputs(); return 0; }
初一看,6+(-20)应该是-14,那就应该输出<6
,可是这么简单的话,就不会有这么一道题了,咱们编译后实际上输出了>6
的结果,这是为何呢,由于在c语言中,无符号和有符号进行运算或者比较的时候,都会直接把有符号的转换为无符号,而后再进行运算或者比较。spa
如今让咱们增长一行代码,看看输出结果,以下:code
#include <stdio.h> void testputs() { unsigned int a = 6; int b = (-20); (a+b) > 6 ? puts(">6"):puts("<6"); printf("%u\n", b);//%u输出无符号整型 } int main() { testputs(); return 0; }
编译后输出以下结果:对象
>6 4294967276
也就是说-20
转换为无符号整型之后变成了4294967276,这个数字是怎么来的呢,首先这里涉及到int和unsigned int的取值范围,以下:进程
那有符号转换为无符号是什么样的一个规则呢,有符号的0转换为无符号也是0,而后有符号的-1转换为无符号其实就是unsigned int的最大值2^32-1,也就是4294967295,那-20的话,再减19那就是4294967276,这样就获得了咱们先前输出的结果。内存
固然上面这是字面上的转换规则,还有一种办法,咱们能够根据内存的存储二进制去进行计算,本质上这个转换只是转换了类型,但并不会去动内存中存储的内容,那负数是怎么存储的呢,分三步:字符串
那么20的二进制是00000000000000000000000000010100,而后按位取反11111111111111111111111111101011,加1之后变成11111111111111111111111111101100,转换为无符号就是:4294967276。
看下面这段代码:
#include <unistd.h> #include <sys/types.h> int main() { fork(); fork()&&fork()||fork(); fork(); //while(1); return 0; }
这题的关键有两点:
&&
和||
的用法,对于&&
,若是它左边的表达式值为真,则执行右边的表达式,不然再也不执行后面的表达式,而对于||
,若是它左边的表达式为真,则右边的表达式再也不执行,不然继续执行右边的表达式。下面咱们用一张图来描述一下进程产生的过程:
下面咱们用文字对图进行解说,以下:
&&
,只有左边值不为0,才会继续调用,因此只有1号进程和2号进程调用了第三个fork进程,分别产生了5号进程和6号进程,此时对于fork函数返回值,1号进程返回5号进程id,2号进程返回6号进程id,5号进程和6号进程都返回0;||
,它左边为假,才会执行右边的表达式,而||
的左边是fork()&&fork()
,因此只要第二个fork函数和第三个fork函数的调用有任意一个返回值为0,它都要执行第四个fork函数,而根据上面的第二点和第三点,三、四、五、6这四个进程都要执行第四个fork函数,继而产生了七、八、九、10这四个进程;因此答案是:20,咱们能够把代码里面的while循环注释放开,而后查看进程数量,就是20个进程。
代码以下:
#include <stdio.h> int main() { char *szName = "shengzhenjiayou"; printf("%s %5.3s %3.5s %3.4s\n", szName, szName, szName, "aa"); return 0; }
先看输出结果:shengzhenjiayou she sheng aa
这就很疑惑了,不少时候咱们只有在输出浮点数的时候格式里面才会带小数点,这里输出字符串带小数点是什么意思呢?
其实这里%5.3s这样的格式,小数点前面的表示至少要输出的总宽度(其实就是对齐宽度),小数点后面的表示从左边开始字符串输出的最大宽度,因此%5.3s输出了' she'这样的数据,它总共输出5列,但只取字符串前面3列,不足的部分补空格,之因此空格在左边,那是由于默认是右对齐的,那若是是%-5.3s这样的,就会变成左对齐。
得出结论以下:对于%5.3s这样的格式而言,小数点前面的表示最少要输出这个宽度,小数点后面的表示只能从字符串中截取这个宽度的数据,不够也不会进行补充。
首先看一下下面的代码:
#include <iostream> class A { }; int main() { printf("sizeof(A)=%d\n", sizeof(A)); return 0; }
输出结果以下:sizeof(A)=1
这题通常不了解的人就会很疑惑,咱们通常计算一个类占用多大空间,其实就是计算它的成员变量所占用的空间,而类A没有任何成员变量,那为何长度会为1呢。
这是由于c++标准规定,类实例化对象占用内存的大小不能为0,为何这么规定呢。
咱们来看,不管是标准c++类型仍是咱们自定义的类型(这里剔除包含纯虚函数的类),它都是能够实例化产生一个变量的,而变量都是要存储在内存中的,若是变量没有大小,是没有存储的,也没有办法得到一个地址,那若是类型A实例化了不少对象,没有地址的话,咱们就没有办法区分各个对象了,因此编译器才会给空类一个字节的空间,这样咱们每个对象都会拥有一个独一无二的地址。
这里延伸一下,空类大小是1,那空结构体呢,基于以上一样的缘由,空结构体实际上也是1。
本篇是c/c++题解第一期,后续会不按期发布更多的题解,若是文章对你有用,麻烦分享和再看哦!