这个简单的问题很少有人能回答完全。在C语言中,关键字static有三个明显的作用:
大多数应试者能正确回答第一部分,一部分能正确回答第二部分,同是很少的人能懂得第三部分。这是一个应试者的严重的缺点,因为他显然不懂得本地化数
据和代码范围的好处和重要性。
2、“引用”与指针的区别是什么?
1)引用必须被初始化,指针不必。
2)引用初始化以后不能被改变,指针可以改变所指的对象。
3)不存在指向空值的引用,但是存在指向空值的指针。
指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作。程序中使用指针,程序的可读性差;而引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作。
流操作符<<和>>、赋值操作符=的返回值、拷贝构造函数的参数、赋值操作符=的参数、其它情况都推荐使用引用
3、.h头文件中的ifndef/define/endif的作用?
答:防止该头文件被重复引用。
4、#include
答:前者是从StandardLibrary的路径寻找和引用file.h,而后者是从当前工作路径搜寻并引用file.h。
答:O(n^2)
6、不能做switch()的参数类型
答:switch的参数不能为实型。
7、局部变量能否和全局变量重名?
答:能,局部会屏蔽全局。要用全局变量,需要使用"::"
局部变量可以与全局变量同名,在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量。对于有些编译器而言,在同一个函数内可以定义多个同名的局部变量,比如在两个循环体内都定义一个同名的局部变量,而那个局部变量的作用域就在那个循环体内
8、如何引用一个已经定义过的全局变量?
9、全局变量可不可以定义在可被多个.C文件包含的头文件中?为什么?
10、语句for(;1;)有什么问题?它是什么意思?
答、和while(1)相同,无限循环。
11、解释堆和栈的区别
答:堆(heap)和栈(stack)的区别
(2)申请后系统的响应栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。
(3)申请大小的限制栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。
(4)申请效率的比较:栈:由系统自动分配,速度较快。但程序员是无法控制的。堆:是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便.另外,在WINDOWS下,最好的方式是用VirtualAlloc分配内存,他不是在堆,也不是在栈,而是直接在进程的地址空间中保留一块内存,虽然用起来最不方便。但是速度快,也最灵活。
(5)堆和栈中的存储内容栈:在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容由程序员安排。
(6)存取效率的比较
chars1[]="aaaaaaaaaaaaaaa";char*s2="bbbbbbbbbbbbbbbbb";aaaaaaaaaaa是在运行时刻赋值的;而bbbbbbbbbbb是在编译时就确定的;但是,在以后的存取中,在栈上的数组比指针所指向的字符串(例如堆)快。比如:#includevoidmain(){chara=1;charc[]="1234567890";char*p="1234567890";a=c[1];a=p[1];return;}对应的汇编代码10:a=c[1];004010678A4DF1movcl,byteptr[ebp-0Fh]0040106A884DFCmovbyteptr[ebp-4],cl11:a=p[1];0040106D8B55ECmovedx,dwordptr[ebp-14h]004010708A4201moval,byteptr[edx+1]004010738845FCmovbyteptr[ebp-4],al第一种在读取时直接就把字符串中的元素读到寄存器cl中,而第二种则要先把指针值读到edx中,在根据edx读取字符,显然慢了。
12、关键字const是什么含意?
constinta;
intconsta;
constint*a;
int*consta;
intconst*aconst;
前两个的作用是一样,a是一个常整型数。第三个意味着a是一个指向常整型数的指针(也就是,整型数是不可修改的,但指针可以)。第四个意思a是一个指向整型数的常指针(也就是说,指针指向的整型数是可以修改的,但指针是不可修改的)。最后一个意味着a是一个指向常整型数的常指针(也就是说,指针指向的整型数是不可修改的,同时指针也是不可修改的)。如果应试者能正确回答这些问题,那么他就给我留下了一个好印象。顺带提一句,也许你可能会问,即使不用关键字const,也还是能很容易写出功能正确的程序,那么我为什么还要如此看重关键字const呢?我也如下的几下理由:
2).通过给优化器一些附加的信息,使用关键字const也许能产生更紧凑的代码。
3).合理地使用关键字const可以使编译器很自然地保护那些不希望被改变的参数,防止其被无意的代码修改。简而言之,这样可以减少bug的出现
13、结构与联合有和区别?
答:(1).结构和联合都是由多个不同的数据类型成员组成,但在任何同一时刻,联合中只存放了一个被选中的成员(所有成员共用一块地址空间),而结构的所有成员都存在(不同成员的存放地址不同)。(2).对于联合的不同成员赋值,将会对其它成员重写,原来成员的值就不存在了,而对于结构的不同成员赋值是互不影响的
14、描述内存分配方式以及它们的区别
答:1)从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。2)在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集。3)从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由程序员决定,使用非常灵活,但问题也最多
15、请说出const与#define相比,有何优点?
答:Const作用:定义常量、修饰函数参数、修饰函数返回值三个作用。被Const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。
1)const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误。2)有些集成化的调试工具可以对const常量进行调试,但是不能对宏常量进行调试。
16、简述数组与指针的区别?
答:数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。指针可以随时指向任意类型的内存块。(1)修改内容上的差别chara[]=“hello”;a[0]=‘X’;char*p=“world”;//注意p指向常量字符串p[0]=‘X’;//编译器不能发现该错误,运行时错误(2)用运算符sizeof可以计算出数组的容量(字节数)。sizeof(p),p为指针得到的是一个指针变量的字节数,而不是p所指的内存容量。C++/C语言没有办法知道指针所指的内存容量,除非在申请内存时记住它。注意当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针。chara[]="helloworld";char*p=a;cout< 17、分别写出BOOL,int,float,指针类型的变量a与“零”的比较语句。 答:BOOL:if(!a)orif(a)int:if(a==0)float:constEXPRESSIONEXP=0.000001if(a 18、如何判断一段程序是由C编译程序还是由C++编译程序编译的? 答:#ifdef__cpluspluscout<<"c++";#elsecout<<"c";#endif 19、访问固定的内存位置(Accessingfixedmemorylocations) 答:嵌入式系统经常具有要求程序员去访问某特定的内存位置的特点。在某工程中,要求设置一绝对地址为0x67a9的整型变量的值为0xaa66。编译器是一个纯粹的ANSI编译器。写代码去完成这一任务。这一问题测试你是否知道为了访问一绝对地址把一个整型数强制转换(typecast)为一指针是合法的。这一问题的实现方式随着个人风格不同而不同。典型的类似代码如下:int*ptr;ptr=(int*)0x67a9;*ptr=0xaa66;Amoreobscureapproachis:一个较晦涩的方法是:*(int*const)(0x67a9)=0xaa55;即使你的品味更接近第二种方案,但我建议你在面试时使用第一种方案。 20、用变量a给出下面的定义 a)一个整型数(Aninteger) b)一个指向整型数的指针(Apointertoaninteger) c)一个指向指针的的指针,它指向的指针是指向一个整型数(Apointertoapointertoaninteger) d)一个有10个整型数的数组(Anarrayof10integers) e)一个有10个指针的数组,该指针是指向一个整型数的(Anarrayof10pointerstointegers) f)一个指向有10个整型数数组的指针(Apointertoanarrayof10integers) g)一个指向函数的指针,该函数有一个整型参数并返回一个整型数(Apointertoafunctionthattakesanintegerasanargumentandreturnsaninteger) h)一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数(Anarrayoftenpointerstofunctionsthattakeaninteger argumentandreturnaninteger) 答案是: a)inta;//Aninteger b)int*a;//Apointertoaninteger c)int**a;//Apointertoapointertoaninteger d)inta[10];//Anarrayof10integers e)int*a[10];//Anarrayof10pointerstointegers f)int(*a)[10];//Apointertoanarrayof10integers g)int(*a)(int);//Apointertoafunctionathattakesanintegerargumentandreturnsaninteger h)int(*a[10])(int);//Anarrayof10pointerstofunctionsthattakeanintegerargumentandreturnaninteger 21、A.c和B.c两个c文件中使用了两个相同名字的static变量,编译的时候会不会有问题这两个static变量会保存到哪里(栈还是堆或者其他的) 答:static的全局变量,表明这个变量仅在本模块中有意义,不会影响其他模块。 他们都放在数据区,但是编译器对他们的命名是不同的。 如果要使变量在其他模块也有意义的话,需要使用extern关键字。 第二部分:程序代码评价或者找错 1、下面的代码输出是什么,为什么?voidfoo(void){unsignedinta=6;intb=-20;(a+b>6)puts(">6"):puts("<=6");}这个问题测试你是否懂得C语言中的整数自动转换原则,我发现有些开发者懂得极少这些东西。不管如何,这无符号整型问题的答案是输出是">6"。原因是当表达式中存在有符号类型和无符号类型时所有的操作数都自动转换为无符号类型。因此-20变成了一个非常大的正整数,所以该表达式计算出的结果大于6。这一点对于应当频繁用到无符号数据类型的嵌入式系统来说是丰常重要的。如果你答错了这个问题,你也就到了得不到这份工作的边缘。 2、C语言同意一些令人震惊的结构,下面的结构是合法的吗,如果是它做些什么?inta=5,b=7,c;c=a+++b; 这个问题将做为这个测验的一个愉快的结尾。不管你相不相信,上面的例子是完全合乎语法的。问题是编译器如何处理它?水平不高的编译作者实际上会争论这个问题,根据最处理原则,编译器应当能处理尽可能所有合法的用法。因此,上面的代码被处理成:c=a+++b;因此,这段代码持行后a=6,b=7,c=12。如果你知道答案,或猜出正确答案,做得好。如果你不知道答案,我也不把这个当作问题。我发现这个问题的最大好处是这是一个关于代码编写风格,代码的可读性,代码的可修改性的好的话题。3、设有以下说明和定义: typedefunion{longi;intk[5];charc;}DATE; structdata{intcat;DATEcow;doubledog;}too; DATEmax; 则语句printf("%d",sizeof(structdate)+sizeof(max));的执行结果是? 答、结果是:52。DATE是一个union,变量公用空间.里面最大的变量类型是int[5],占用20个字节.所以它的大小是20 data是一个struct,每个变量分开占用空间.依次为int4+DATE20+double8=32. 所以结果是20+32=52. 当然...在某些16位编辑器下,int可能是2字节,那么结果是int2+DATE10+double8=20 4、请写出下列代码的输出内容 #include main() { inta,b,c,d; a=10; b=a++; c=++a; d=10*a++; printf("b,c,d:%d,%d,%d",b,c,d); return0; } 答:10,12,120 5、请找出下面代码中的所以错误 说明:以下代码是把一个字符串倒序,如“abcd”倒序后变为“dcba” 1、#include"string.h" 2、main() 3、{ 4、char*src="hello,world"; 5、char*dest=NULL; 6、intlen=strlen(src); 7、dest=(char*)malloc(len); 8、char*d=dest; 9、char*s=src[len]; 10、while(len--!=0) 11、d++=s--; 12、printf("%s",dest); 13、return0; 14、} 答: 方法1: intmain(){ char*src="hello,world"; intlen=strlen(src); char*dest=(char*)malloc(len+1);//要为\0分配一个空间 char*d=dest; char*s=&src[len-1];//指向最后一个字符 while(len--!=0) *d++=*s--; *d=0;//尾部要加\0 printf("%s\n",dest); free(dest);//使用完,应当释放空间,以免造成内存汇泄露 方法2: #include charstr[]="hello,world"; intlen=strlen(str); chart; for(inti=0;i t=str[i]; str[i]=str[len-i-1];str[len-i-1]=t; printf("%s",str); 6、请问下面程序有什么错误 inta[60][250][1000],i,j,k; for(k=0;k<=1000;k++) for(j=0;j<250;j++) for(i=0;i<60;i++) a[i][j][k]=0; 答案:把循环语句内外换一下 7、以下3个有什么区别char*constp;//常量指针,p的值不可以修改 charconst*p;//指向常量的指针,指向的常量值不可以改 constchar*p;//和charconst*p 8、写出下面的结果 charstr1[]="abc"; charstr2[]="abc"; constcharstr3[]="abc"; constcharstr4[]="abc"; constchar*str5="abc"; constchar*str6="abc"; char*str7="abc"; char*str8="abc"; cout<<(str1==str2)< cout<<(str3==str4)< cout<<(str5==str6)< cout<<(str7==str8)< 结果是:0011 解答:str1,str2,str3,str4是数组变量,它们有各自的内存空间; 而str5,str6,str7,str8是指针,它们指向相同的常量区域。 9、以下代码中的两个sizeof用法有问题吗? voidUpperCase(charstr[])//将str中的小写字母转换成大写字母 for(size_ti=0;i if('a'<=str[i]&&str[i]<='z') str[i]-=('a'-'A'); charstr[]="aBcDe"; cout<<"str字符长度为:"< UpperCase(str); cout< 10、写出输出结果 inta[5]={1,2,3,4,5}; int*ptr=(int*)(&a+1); printf("%d,%d",*(a+1),*(ptr-1)); 输出:2,5 *(a+1)就是a[1],*(ptr-1)就是a[4],执行结果是2,5 &a+1不是首地址+1,系统会认为加一个a数组的偏移,是偏移了一个数组的大小(本例是5个int) 则ptr实际是&(a[5]),也就是a+5 原因如下: &a是数组指针,其类型为int(*)[5]; 而指针加1要根据指针类型加上一定的值, 不同类型的指针+1之后增加的大小不同 a是长度为5的int数组指针,所以要加5*sizeof(int) 所以ptr实际是a[5] 但是prt与(&a+1)类型是不一样的(这点很重要) 所以prt-1只会减去sizeof(int*) a,&a的地址是一样的,但意思不一样,a是数组首地址,也就是a[0]的地址,&a是对象(数组)首地址,a+1是数组下一元素的地址,即a[1],&a+1是下一个对象的地址,即a[5]. 11、请问以下代码有什么问题: intmain() chara; char*str=&a; strcpy(str,"hello"); printf(str); 没有为str分配内存空间,将会发生异常 问题出在将一个字符串复制进一个字符变量指针所指地址。虽然可以正确输出结果,但因为越界进行内在读写而导致程序崩溃。 char*s="AAA"; printf("%s",s); s[0]='B'; 有什么错? cosntchar*s="AAA"; 然后又因为是常量,所以对是s[0]的赋值操作是不合法的。 12、交换两个变量的值,不使用第三个变量。 即a=3,b=5,交换之后a=5,b=3; 有两种解法,一种用算术算法,一种用^(异或) a=a+b; b=a-b; a=a-b; or a=a^b;//只能对int,char.. b=a^b; a=a^b; a^=b^=a; 17、下面的程序会出现什么结果 #include voidgetmemory(char*p) p=(char*)malloc(100); strcpy(p,"helloworld"); char*str=NULL; getmemory(str); printf("%s/n",str); free(str); 程序崩溃,getmemory中的malloc不能返回动态内存,free()对str操作很危险 13、下面的语句会出现什么结果? charszstr[10]; strcpy(szstr,"0123456789"); 答案:长度不一样,会造成非法的OS,应该改为charszstr[11]; 14、(void*)ptr和(*(void**))ptr的结果是否相同? 答:其中ptr为同一个指针 .(void*)ptr和(*(void**))ptr值是相同的 15、问函数既然不会被其它函数调用,为什么要返回1? intx=3; printf("%d",x); return1; 答:mian中,c标准认为0表示成功,非0表示错误。具体的值是某中具体出错信息 16、对绝对地址0x100000赋值且想让程序跳转到绝对地址是0x100000去执行 (unsignedint*)0x100000=1234; 首先要将0x100000强制转换成函数指针,即: (void(*)())0x100000 然后再调用它: *((void(*)())0x100000)(); 用typedef可以看得更直观些: typedefvoid(*)()voidFuncPtr; *((voidFuncPtr)0x100000)(); 17、分析下面的程序: voidGetMemory(char**p,intnum) *p=(char*)malloc(num); GetMemory(&str,100); if(str!=NULL) strcpy(str,"world"); printf("\nstris%s",str); getchar(); 输出strisworld。 free只是释放的str指向的内存空间,它本身的值还是存在的. 所以free之后,有一个好的习惯就是将str=NULL. 此时str指向空间的内存已被回收,如果输出语句之前还存在分配空间的操作的话,这段存储空间是可能被重新分配给其他变量的, 尽管这段程序确实是存在大大的问题(上面各位已经说得很清楚了),但是通常会打印出world来。 这是因为,进程中的内存管理一般不是由操作系统完成的,而是由库函数自己完成的。 当你malloc一块内存的时候,管理库向操作系统申请一块空间(可能会比你申请的大一些),然后在这块空间中记录一些管理信息(一般是在你申请的内存前面一点),并将可用内存的地址返回。但是释放内存的时候,管理库通常都不会将内存还给操作系统,因此你是可以继续访问这块地址的,只不过。。。。。。。。楼上都说过了,最好别这么干。 18、给定结构structA chart:4; chark:4; unsignedshorti:8; unsignedlongm; };问sizeof(A)= 给定结构structA chart:4;4位 chark:4;4位 unsignedshorti:8;8位 unsignedlongm;//偏移2字节保证4字节对齐 };//共8字节 19、下面的函数实现在一个数上加一个数,有什么错误?请改正。 intadd_n(intn) staticinti=100; i+=n; returni; 当你第二次调用时得不到正确的结果,难道你写个函数就是为了调用一次?问题就出在static上 20、给出下面程序的答案 #include #include #include typedefstructAA intb1:5; intb2:2; }AA; voidmain() AAaa; charcc[100]; strcpy(cc,"0123456789abcdefghijklmnopqrstuvwxyz"); memcpy(&aa,cc,sizeof(AA)); cout< cout< 答案是-16和1 首先sizeof(AA)的大小为4,b1和b2分别占5bit和2bit. 经过strcpy和memcpy后,aa的4个字节所存放的值是: 0,1,2,3的ASC码,即00110000,00110001,00110010,00110011 所以,最后一步:显示的是这4个字节的前5位,和之后的2位 分别为:10000,和01 因为int是有正负之分所以:答案是-16和1 21、写出sizeof(structname1)=,sizeof(structname2)=的结果 structname1{ charstr; shortx; intnum; structname2{ sizeof(structname1)=8,sizeof(structname2)=12 在第二个结构中,为保证num按四个字节对齐,char后必须留出3字节的空间;同时为保证整个结构的自然对齐(这里是4字节对齐),在x后还要补齐2个字节,这样就是12字节。