腾讯、百度、阿里、微软面试题精选(不断更新)
1、for(i=0;i<10;++i,sum+=i); 循环结束时 i 和sum的值分别是多少?
分析:循环结束时 i=10应该没有问题,sum计算的位置不是很常见,每次sum+=i 时,i 的值都是先自加1,即 i(从0到9),计算sum时是从1加到10,结果55;
如果是:for(i=0;i<10;++i) sum+=i; 循环结束时 i 和sum的值分别是多少?
这次 i 依然是10,但是sum就是0到9的加和,结果45。
2、请定义一个宏,比较两个数a、b的大小,不能使用大于、小于、if语句。
#define Max(a,b) ((a-b)&(0x80))? b:a
#define Max(a,b) ((a-b)&(1<<31))? b:a 两种写法是等价的。
注意:#define Max(a,b) (a/b)?a:b 这个答案是不全面的,只适用于正整数。
3、不使用额外空间,将 A,B两链表的元素交叉归并。
代码使用了递归的方式实现合并两个链表:
1 #include <iostream> 2 using namespace std; 3 4 typedef struct node 5 { 6 int val; 7 struct node *next; 8 }node; 9 10 node* createList(int n) 11 { 12 node *head; 13 node *pHead;//永远指向最新的节点 14 node *pNext;//指向新添加的节点 15 for(int i=0;i<n;i++) 16 { 17 if(i==0) 18 { 19 head=new node; 20 cout<<"请输入第1个元素(头结点)的值:"; 21 cin>>head->val; 22 head->next=NULL; 23 pHead=head; 24 } 25 else 26 { 27 pNext=new node; 28 cout<<"请输入第"<<i+1<<"个元素的值:"; 29 cin>>pNext->val; 30 pNext->next=NULL; 31 pHead->next=pNext; 32 pHead=pNext; 33 } 34 } 35 return head; 36 } 37 38 void mergeTwoList(node *headA,node *headB)//headA的长度大于等于headB的 39 { 40 if(headA==NULL||headB==NULL) 41 { 42 return; 43 } 44 mergeTwoList(headA->next,headB->next);//递归实现 45 headB->next=headA->next; 46 headA->next=headB; 47 } 48 49 int main() 50 { 51 node *headA; 52 node *headB; 53 node *newList; 54 cout<<"新建链表A:\n"; 55 headA=createList(5); 56 cout<<"新建链表B:\n"; 57 headB=createList(3); 58 newList=headA; 59 mergeTwoList(headA,headB); 60 cout<<"合并后的新链表:"<<endl; 61 while(newList!=NULL) 62 { 63 cout<<newList->val<<" "; 64 newList=newList->next; 65 } 66 return 0; 67 }
4、*p=NULL *p=new char[100] sizeof(p)各为多少?(一般都指的32位计算机)只要是指针变量都是4字节的,也就是计算机寻址空间是0到(2^32-1),即32位。
5、C语言中的内存泄漏:
动态内存的意思是程序运行时在堆上申请的内存。
而静态内存是程序编译时,在静态存储区申请的内存。
动态内存泄露指的是程序运行时,使用的new malloc realloc等函数没有与之匹配的delete free等函数。
造成程序不断的同操作系统申请内存,而又不还给操作系统,申请的多了,操作系统本身也就没内存可用了。
而应用程序,一旦退出,那么操作系统是会自动回收该应用程序所在进程的全部资源的,所以,泄露的内存也就会被操作系统全部回收。
应用程序的内存分为四块:堆区,栈区,全局数据区,代码区
其中堆区需要程序员自己管理,我们申请的动态变量就存放在堆区,用完后需要程序员自己手动释放。
若申请了一块动态内存,未释放,却丢失了指向性,这就叫内存泄露,会导致程序的可用内存减少,严重的话会拖垮操作系统。
6、
32位机上根据下面的代码,问哪些说法是正确的?() signed char a = 0xe0; unsigned int b = a; unsigned char c = a; A. a>0 && c>0 为真 B. a == c 为真 C. b 的十六进制表示是:0xffffffe0 D.上面都不对
有符号数和无符号数之间的转换:c
首先,a=1110 0000,首位是1,signed是有符号数,所以是负的;unsigned int 是4个字节的,无符号数,把a转换成b时,负数前面补1,正数补0,所以b的16进制表示0xffffffe0;
c是无符号数,单字节的,c=0xe0,是正数。
转一篇很好的博客,看了就懂了:
#include <stdio.h>
int main(int argc, char *argv[])
{
unsigned char a = -1;
char b = a;
printf("%d %d",a,b);
return 0;
}
//结果:255 -1
#include <stdio.h>
int main(int argc, char *argv[])
{
unsigned short a = -1;
short b = a;
printf("%d %d",a,b);
return 0;
}
//结果:65535 -1
这是两段很简单的代码,我就以第二段代码为例。
在计算机中,负数是以补码来存储的。 转载请注明出处http://www.cnblogs.com/stonehat/archive/2011/10/14/2212141.html
C语言中常量整数 -1的补码表示为0xFFFFFFFF。截取后面16位FFFF赋值给 变量a(unsigned short)。此时 a = 0xFFFF(a没有符号位,0xFFFF转换为十进制为65535)。
a又将0xFFFF,直接赋值给short b。 此时 b = 0xFFFF(但是要注意,b是有符号的,0xFFFF转换为十进制为-1)。
执行printf("%d %d",a,b);的时候,要将 a和b的值先转换为int型:(这里是重点!!!)
a没有符号所以转为int型为0x0000FFFF,
b有符号转换为int型为0xFFFFFFFF。
十进制输出值 65535 -1. 转载请注明出处http://www.cnblogs.com/stonehat/archive/2011/10/14/2212141.html
#include <stdio.h>
int main(int argc, char *argv[])
{
unsigned int a = -1;
int b = a;
printf("%d %d",a,b);
return 0;
}
//结果 -1 -1
转载请注明出处http://www.cnblogs.com/stonehat/archive/2011/10/14/2212141.html
a在内存中值为0xFFFFFFFF,b的值为0xFFFFFFFF,都已经32位,
a转换为int型的时候就是0xFFFFFFFF,所以输出-1.
其实,记住两点就行了
1.unsigned 类型转换为 signed类型的时候是直接复制到低位,高位为0.如果signed类型位数不够,只直接装载unsigned低位。
2.signed类型转换为unsigned类型的时候,也是将补码直接复制到低位,高位为符号位。如果unsigned位数不够,只直接装载signed低位。
7、
1 下面哪些选项能编译通过? 2 int i; 3 char a[10]; 4 string f(); 5 string g(string &str); 6 7 A. if(!!i){f();} 8 B. g(f()); 9 C. a=a+1; 10 D. g("abc");
解析:c、c++会给未初始化的变量随机赋值,所以A是可以的;B是错误的,因为一个函数的返回值是一个临时变量,g函数参数是一个引用变量,应该传入一个定义好的变量作为参数,例如 string a="abc";g(a);所以D也是错误的,如果是g(string str)函数,B、D都是对的。C是错的,因为a是指向数组a[10]的首地址的指针,是个常量,不能赋值的,就像5=5+1是不可能的。但是 char *p; p=a;p++;这就可以了,因为p是变量了。
8、
问下面的数据都存放在哪些存储区? int main() { char *p = "hello,world"; return 0; } A. 堆和静态数据区 B. 栈和静态数据区 C. 栈和常量区 D. 栈和堆
解析:根据C语言中的特性和定义p是一个局部变量,而C语言中局部变量存在于栈中,"hello wrold"是一个字符串常量,因此存储于程序的只读存储区中,p在这里其实只是指向了"hello wrold"在只读存储区中的地址而已。
12、问题:在一个二维数组中,每行的元素从左到右是递增的,每列元素从上到下是递增的。写一个函数,查找一给定的元素是否在此数组中
输入:一个二维数组,和一个待查找的数
输出:待查找的数在数组中输出“YES",否则输出”NO"
原始思路:最简单思路就是暴力搜索,遍历一遍数组中的元素时间复杂度为O(n2)。但是这样就没有用问题的已知条件(从左到右、从上到下递增),因此不是个好的解法
改进1:从第一行开始找,找到待查元素大的,如果还没找到,接着从第二行开始找,直到找到或到最后一个元素为止(如图),但是如果带查找的元素在最后,还得遍历到最后,时间复杂度还是O(n2)
改进2:上来在随机在里面挑一个,如果正好逮住,那就结束了;如果比待查找的元素大,那么他的左边和上边;否则在右边和下边。如下图。这样下来可以减少一部分元素的比较。在寻找1时,会话费反而很多时间,并不是个好的解决办法。
改进3:看两个比较关键的两个点——左下角和右上角。以右上角为例(如下图)。如果右上角元素等于带查找元素,那就返回真;如果右上角元素大于待查找元素,那就删除右上角元素所在列;否则删除其所在行。依次进行下去。
举例说明:
参考代码一:
#include <stdio.h> int find_value(int a[][4], int value, int x, int y)//(x,y)表示右上角坐标 { if ((x >= 0) && (y < 4)) { if (a[x][y] == value) return 1; else if (a[x][y] > value) return find_value(a, value, x-1, y); else return find_value(a, value, x, y+1); } return 0; } int main() { int a[4][4] = {{1, 2, 8, 9}, {2, 4, 9, 12}, {4, 7, 10, 13}, {6, 8, 11, 15}}; int val; printf("Enter your number:"); scanf("%d", &val); if(find_value(a, val, 3, 0)) printf("Yes, find it\n"); else printf("No, not find it\n"); return 0; }