这个简单的问题很少有人能回答完全。在C语言中,关键字static有三个明显的作用:
答、1)引用必须被初始化,指针不必。
2)引用初始化以后不能被改变,指针可以改变所指的对象。
3)不存在指向空值的引用,但是存在指向空值的指针。
指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作。程序中使用指针,程序的可读性差;而引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作。
流操作符<<和>>、赋值操作符=的返回值、拷贝构造函数的参数、赋值操作符=的参数、其它情况都推荐使用引用
答:防止该头文件被重复引用。
答:前者是从StandardLibrary标准库的路径寻找和引用file.h,而后者是从当前工作路径搜寻并引用file.h。
答:全局变量储存在静态数据区,局部变量在堆栈中。
答:左右子树都是平衡二叉树且左右子树的深度差值的绝对值不大于1。
答:1.没有回收垃圾资源
2.层次太深的递归调用
答:O(n^2)
答:constructor构造函数
答:队列先进先出,栈后进先出
答:switch的参数不能为实型(floatdouble之类的)。
答:能,局部会屏蔽全局。要用全局变量,需要使用"::"
局部变量可以与全局变量同名,在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量。对于有些编译器而言,在同一个函数内可以定义多个同名的局部变量,比如在两个循环体内都定义一个同名的局部变量,而那个局部变量的作用域就在那个循环体内
答、和while(1)相同,无限循环。
17、do……while和while……do有什么区别?
答、前一个循环一遍再判断,后一个判断以后再循环。
static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别?
答、全局变量(外部变量)的说明之前再冠以static就构成了静态的全局变量。全局变量本身就是静态存储方式,静态全局变量当然也是静态存储方式。这两者在存储方式上并无不同。这两者的区别虽在于非静态全局变量的作用域是整个源程序,当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。而静态全局变量则限制了其作用域,即只在定义该变量的源文件内有效,在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用,因此可以避免在其它源文件中引起错误。
从以上分析可以看出,把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围。
static函数与普通函数作用域不同。仅在本文件。只在当前源文件中使用的函数应该说明为内部函数(static),内部函数应该在当前源文件中说明和定义。对于可在当前源文件以外使用的函数,应该在一个头文件中说明,要使用这些函数的源文件要包含这个头文件
static全局变量与普通的全局变量有什么区别:static全局变量只初使化一次,防止在其他文件单元中被引用;
static局部变量和普通局部变量有什么区别:static局部变量只被初始化一次,下一次依据上一次结果值;
static函数与普通函数有什么区别:static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝
19、程序的内存分配答:一个由c/C++编译的程序占用的内存分为以下几个部分1、栈区(stack)—由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。2、堆区(heap)—一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表3、全局区(静态区)(static)—全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后由系统释放。4、文字常量区—常量字符串就是放在这里的。程序结束后由系统释放。5、程序代码区—存放函数体的二进制代码
例子程序这是一个前辈写的,非常详细//main.cppinta=0;//全局初始化区char*p1;//全局未初始化区main(){intb;栈chars[]="abc";//栈char*p2;//栈char*p3="123456";//123456\0在常量区,p3在栈上。staticintc=0;//全局(静态)初始化区p1=(char*)malloc(10);p2=(char*)malloc(20);//分配得来得10和20字节的区域就在堆区。strcpy(p1,"123456");//123456\0放在常量区,编译器可能会将它与p3所向"123456"优化成一个地方。}
答:堆(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读取字符,显然慢了。
答:预编译又称为预处理,是做些代码文本的替换工作。处理#开头的指令,比如拷贝#include包含的文件代码,#define宏定义的替换,条件编译等,就是为编译做的预备工作的阶段,主要处理#开始的预编译指令,预编译指令指示了在程序正式编译前就由编译器进行的操作,可以放在程序中的任何位置。
c编译系统在对程序进行通常的编译之前,先进行预处理。c提供的预处理功能主要有以下三种:1)宏定义2)文件包含3)条件编译
1、总是使用不经常改动的大型代码体。
2、程序由多个模块组成,所有模块都使用一组标准的包含文件和相同的编译选项。在这种情况下,可以将所有包含文件预编译为一个预编译头。
constinta;
intconsta;
constint*a;
int*consta;
intconst*aconst;
前两个的作用是一样,a是一个常整型数。第三个意味着a是一个指向常整型数的指针(也就是,整型数是不可修改的,但指针可以)。第四个意思a是一个指向整型数的常指针(也就是说,指针指向的整型数是可以修改的,但指针是不可修改的)。最后一个意味着a是一个指向常整型数的常指针(也就是说,指针指向的整型数是不可修改的,同时指针也是不可修改的)。如果应试者能正确回答这些问题,那么他就给我留下了一个好印象。顺带提一句,也许你可能会问,即使不用关键字const,也还是能很容易写出功能正确的程序,那么我为什么还要如此看重关键字const呢?我也如下的几下理由:
2).通过给优化器一些附加的信息,使用关键字const也许能产生更紧凑的代码。
3).合理地使用关键字const可以使编译器很自然地保护那些不希望被改变的参数,防止其被无意的代码修改。简而言之,这样可以减少bug的出现
答:一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子:
1).并行设备的硬件寄存器(如:状态寄存器)
2).一个中断服务子程序中会访问到的非自动变量(Non-automaticvariables)
3).多线程应用中被几个任务共享的变量
回答不出这个问题的人是不会被雇佣的。我认为这是区分C程序员和嵌入式系统程序员的最基本的问题。嵌入式系统程序员经常同硬件、中断、RTOS等等打交道,所用这些都要求volatile变量。不懂得volatile内容将会带来灾难。
假设被面试者正确地回答了这是问题(嗯,怀疑这否会是这样),我将稍微深究一下,看一下这家伙是不是直正懂得volatile完全的重要性。
1).一个参数既可以是const还可以是volatile吗?解释为什么。
2).一个指针可以是volatile吗?解释为什么。
3).下面的函数有什么错误:
intsquare(volatileint*ptr)
{
return*ptr**ptr;
}
下面是答案:
1).是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。
2).是的。尽管这并不很常见。一个例子是当一个中服务子程序修该一个指向一个buffer的指针时。
3).这段代码的有个恶作剧。这段代码的目的是用来返指针*ptr指向值的平方,但是,由于*ptr指向一个volatile型参数,编译器将产生类似下面的代码:
inta,b;
a=*ptr;
b=*ptr;
returna*b;
由于*ptr的值可能被意想不到地该变,因此a和b可能是不同的。结果,这段代码可能返不是你所期望的平方值!正确的代码如下:
longsquare(volatileint*ptr)
inta;
returna*a;
答:按照数据结构类型的不同,将数据模型划分为层次模型、网状模型和关系模型。
答:(1).结构和联合都是由多个不同的数据类型成员组成,但在任何同一时刻,联合中只存放了一个被选中的成员(所有成员共用一块地址空间),而结构的所有成员都存在(不同成员的存放地址不同)。(2).对于联合的不同成员赋值,将会对其它成员重写,原来成员的值就不存在了,而对于结构的不同成员赋值是互不影响的
答:1)从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。2)在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集。3)从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由程序员决定,使用非常灵活,但问题也最多
答:Const作用:定义常量、修饰函数参数、修饰函数返回值三个作用。被Const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。
1)const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误。2)有些集成化的调试工具可以对const常量进行调试,但是不能对宏常量进行调试。
答:数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。指针可以随时指向任意类型的内存块。(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< 答:BOOL:if(!a)orif(a)int:if(a==0)float:constEXPRESSIONEXP=0.000001if(a 答:#ifdef__cpluspluscout<<"c++";#elsecout<<"c";#endif 答:带参宏函数 参数类型没有参数类型问题定义实参、形参类型 处理过程不分配内存分配内存 程序长度变长不变 答、设2个栈为A,B,一开始均为空. 入队: 将新元素push入栈A; 出队: (1)判断栈B是否为空; (2)如果不为空,则将栈A中所有元素依次pop出并push到栈B; (3)将栈B的栈顶元素pop出; 这样实现的队列入队和出队的平摊复杂度都还是O(1),比上面的几种方法要好 答:这个问题用几个解决方案。我首选的方案是: while(1) 一些程序员更喜欢如下方案: for(;;) 这个实现方式让我为难,因为这个语法没有确切表达到底怎么回事。如果一个应试者给出这个作为方案,我将用这个作为一个机会去探究他们这样做的 基本原理。如果他们的基本答案是:“我被教着这样做,但从没有想到过为什么。”这会给我留下一个坏印象。 第三个方案是用goto Loop: ... gotoLoop; 应试者如给出上面的方案,这说明或者他是一个汇编语言程序员(这也许是好事)或者他是一个想进入新领域的BASIC/FORTRAN程序员。 答:嵌入式系统总是要用户对变量或寄存器进行位操作。给定一个整型变量a,写两段代码,第一个设置a的bit3,第二个清除a的bit3。在以上两个操作中,要保持其它位不变。对这个问题有三种基本的反应1)不知道如何下手。该被面者从没做过任何嵌入式系统的工作。2)用bitfields(字段)。Bitfields是被扔到C语言死角的东西,它保证你的代码在不同编译器之间是不可移植的,同时也保证了的你的代码是不可重用的。我最近不幸看到Infineon为其较复杂的通信芯片写的驱动程序,它用到了bitfields因此完全对我无用,因为我的编译器用其它的方式来实现bitfields的。从道德讲:永远不要让一个非嵌入式的家伙粘实际硬件的边。3)用#defines和bitmasks操作。这是一个有极高可移植性的方法,是应该被用到的方法。最佳的解决方案如下:#defineBIT3(0x1<<3)staticinta;voidset_bit3(void){a|=BIT3;}voidclear_bit3(void){a&=~BIT3;}一些人喜欢为设置和清除值而定义一个掩码同时定义一些说明常数,这也是可以接受的。我希望看到几个要点:说明常数、|=和&=~操作。 答:嵌入式系统经常具有要求程序员去访问某特定的内存位置的特点。在某工程中,要求设置一绝对地址为0x67a9的整型变量的值为0xaa66。编译器是一个纯粹的ANSI编译器。写代码去完成这一任务。这一问题测试你是否知道为了访问一绝对地址把一个整型数强制转换(typecast)为一指针是合法的。这一问题的实现方式随着个人风格不同而不同。典型的类似代码如下:int*ptr;ptr=(int*)0x67a9;//先取出地址de值付给指针*ptr=0xaa66;//再把指针解引用Amoreobscureapproachis:一个较晦涩的方法是:*(int*const)(0x67a9)=0xaa55;即使你的品味更接近第二种方案,但我建议你在面试时使用第一种方案。 2)ISR不能传递参数。3)在许多的处理器/编译器中,浮点一般都是不可重入的。有些处理器/编译器需要让额处的寄存器入栈,有些处理器/编译器就是不允许在ISR中做浮点运算。此外,ISR应该是短而有效率的,在ISR中做浮点运算是不明智的。4)与第三点一脉相承,printf()经常有重入和性能上的问题。如果你丢掉了第三和第四点,我不会太为难你的。不用说,如果你能得到后两点,那么你的被雇用前景越来越光明了。 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 答:局部变量:在一个函数内部定义的变量是内部变量,它只在本函数范围内有效,也就是说只有在本函数内才能使用它们,在此函数以外时不能使用这些变量的,它们称为局部变量;说明:1.主函数main中定义的变量也只在主函数中有效,而不因为在主函数中定义而在整个文件或程序中有效2.不同函数中可以使用名字相同的变量,它们代表不同的对象,互不干扰3.形式参数也使局部变量4.在一个函数内部,可以在复合语句中定义变量,这些变量只在本符合语句中有效全局变量:在函数外定义的变量是外部变量,外部变量是全局变量,全局变量可以为本文件中其它函数所共用,它的有效范围从定义变量的位置开始到本源文件结束;说明:1.设全局变量的作用:增加了函数间数据联系的渠道2.建议不再必要的时候不要使用全局变量,因为a.全局变量在程序的全部执行过程中都占用存储单元; b.它使函数的通用性降低了c.使用全局变量过多,会降低程序的清晰性3.如果外部变量在文件开头定义,则在整个文件范围内都可以使用该外部变量,如果不再文件开头定义,按上面规定作用范围只限于定义点到文件终了。如果在定义点之前的函数想引用该外部变量,则应该在该函数中用关键字extern作外部变量说明4.如果在同一个源文件中,外部变量与局部变量同名,则在局部变量的作用范围内,外部变量不起作用;静态变量:在程序运行期间分配固定的存储空间的变量,叫做静态变量 答:交换两个参数值的宏定义为:.#defineSWAP(a,b)\ (a)=(a)+(b);\ (b)=(a)-(b);\ (a)=(a)-(b); 输入两个参数,输出较小的一个:#defineMIN(A,B)((A)<(B))(A):(B)) 表明1年中有多少秒(忽略闰年问题):#defineSECONDS_PER_YEAR(60*60*24*365)UL #defineDOUBLE(x)x+x与#defineDOUBLE(x)((x)+(x)) i=5*DOUBLE(5);i为30i=5*DOUBLE(5);i为50 已知一个数组table,用一个宏定义,求出数据的元素个数 #defineNTBL #defineNTBL(sizeof(table)/sizeof(table[0])) 42、A.c和B.c两个c文件中使用了两个相同名字的static变量,编译的时候会不会有问题这两个static变量会保存到哪里(栈还是堆或者其他的) 答:static的全局变量,表明这个变量仅在本模块中有意义,不会影响其他模块。 他们都放在数据区,但是编译器对他们的命名是不同的。 如果要使变量在其他模块也有意义的话,需要使用extern关键字。 答:将这个指针指向的next节点值copy到本节点,将next指向next->next,并随后删除原next指向的节点。 %d代表十进制 %o代表八进制 %x代表十六进制 %u无符号十进制数 %e以科学记数法表示 %#o代表带前缀o的八进制 %#x代表待前缀ox的十六进制 \0oo八进制值(o表示一个八进制数字) \xhh十六进制值(h表示一个十六进制数字) 16进制0x234这样的(如24就是0x018,凡是以0X或0x开头的数字序列)8进制01111这样的(凡是16进制0x234这样的(如24就是0x018,凡是以0X或0x开头的数字序列)8进制01111这样的(凡是以0开头的数字序列)以0开头的数字序列) 八进制数octalnumber二进制数binarynumber 十进制数DecimalNumber 十六进制数hexadecimalnumber 1、下面的代码输出是什么,为什么?voidfoo(void){unsignedinta=6;intb=-20;(a+b>6)puts(">6"):puts("<=6");}这个问题测试你是否懂得C语言中的整数自动转换原则,我发现有些开发者懂得极少这些东西。不管如何,这无符号整型问题的答案是输出是">6"。原因是当表达式中存在有符号类型和无符号类型时所有的操作数都自动转换为无符号类型。因此-20变成了一个非常大的正整数,所以该表达式计算出的结果大于6。这一点对于应当频繁用到无符号数据类型的嵌入式系统来说是丰常重要的。如果你答错了这个问题,你也就到了得不到这份工作的边缘。2、评价下面的代码片断:unsignedintzero=0;unsignedintcompzero=0xFFFF;/*1'scomplementofzero*/对于一个int型不是16位的处理器为说,上面的代码是不正确的。应编写如下:unsignedintcompzero=~0;这一问题真正能揭露出应试者是否懂得处理器字长的重要性。在我的经验里,好的嵌入式程序员非常准确地明白硬件的细节和它的局限,然而PC机程序往往把硬件作为一个无法避免的烦恼。 3、C语言同意一些令人震惊的结构,下面的结构是合法的吗,如果是它做些什么?inta=5,b=7,c;c=a+++b;因此,上面的代码被处理成:c=a+++b;因此,这段代码持行后a=6,b=7,c=12。如果你知道答案,或猜出正确答案,做得好。如果你不知道答案,我也不把这个当作问题。我发现这个问题的最大好处是这是一个关于代码编写风格,代码的可读性,代码的可修改性的好的话题。 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 #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 我总结:不管a的自加还是自减在等号的那一边,最终a自身的值也会改变 intinc(inta) return(++a); intmulti(int*a,int*b,int*c) return(*c=*a**b); typedefint(FUNC1)(intin); typedefint(FUNC2)(int*,int*,int*); voidshow(FUNC2fun,intarg1,int*arg2) INCp=&inc; inttemp=p(arg1); fun(&temp,&arg1,arg2); printf("%d\n",*arg2); show(multi,10,&a); 答:110 7、请找出下面代码中的所以错误 说明:以下代码是把一个字符串倒序,如“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); 8、请问下面程序有什么错误 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; 答案:把循环语句内外换一下 //对于多重循环一定是内循环数大于等于外循环数 .#defineMax_CB500 voidLmiQueryCSmd(StructMSgCB*pmsg) unsignedcharucCmdNum; ...... for(ucCmdNum=0;ucCmdNum ......; 答案:死循环 //字符型应该是到255,再加的话就溢出了,我觉得会出问题,可能就死循环了 10、以下3个有什么区别char*constp;//常量指针,p的值不可以修改 charconst*p;//指向常量的指针,指向的常量值不可以改 constchar*p;//和charconst*p 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是指针,它们指向相同的常量区域。 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< 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]. 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]的赋值操作是不合法的。 inta=248;b=4;intconstc=21;constint*d=&a; int*conste=&b;intconst*fconst=&a; 请问下列表达式哪些会被编译器禁止?为什么? *c=32;d=&b;*d=43;e=34;e=&a;f=0x321f; *c这是个什么东东,禁止 *d说了是const,禁止 e=&a说了是const禁止 const*fconst=&a;禁止 即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; .#include #include voidgetmemory(char*p)//修改:(char**p)把地址传过来 p=(char*)malloc(100); strcpy(p,"helloworld"); char*str=NULL; getmemory(str); printf("%s/n",str); free(str); 程序崩溃,getmemory中的malloc不能返回动态内存,free()对str操作很危险 charszstr[10]; strcpy(szstr,"0123456789"); 答案:长度不一样,会造成非法的OS,应该改为charszstr[11]; 答:其中ptr为同一个指针 .(void*)ptr和(*(void**))ptr值是相同的 intx=3; printf("%d",x); return1; 答:mian中,c标准认为0表示成功,非0表示错误。具体的值是某中具体出错信息 (unsignedint*)0x100000=1234;//经典复制 首先要将0x100000强制转换成函数指针,即: (void(*)())0x100000 然后再调用它: *((void(*)())0x100000)(); 用typedef可以看得更直观些: typedefvoid(*)()voidFuncPtr; *((voidFuncPtr)0x100000)(); unsignedshortA=10; printf("~A=%u\n",~A); charc=128; printf("c=%d\n",c); 第一题,~A=0xfffffff5,int值为-11,但输出的是uint。所以输出4294967285 第二题,c=0x10,输出的是int,最高位为1,是负数,所以它的值就是0x00的补码就是128,所以输出-128。 这两道题都是在考察二进制向int或uint转换时的最高位处理。 补码:例如12模的系统中,加8和减4效果是一样的,因此凡是减4运算,都可以用加8来代替。对“模”而言,8和4互为补数。实际上以12模的系统中,11和1,10和2,9和3,7和5,6和6都有这个特性。共同的特点是两者相加等于模。在以12模的系统中,加8和减4效果是一样的,因此凡是减4运算,都可以用加8来代替。所以对于模为100000000的8位系统来说,减去b和加上100000000-b是一个道理,而(100000000-b)是什么?恰好就是b的补码(负数的补码等于其反码+1)定理:减去一个数就是加上它的补码,结果一样,所以解决了负数的计算。有了补码的概念,所有的加减都可以用加法来计算了。对于计算机而言方便了许多 假设模为8(8位)的操作系统,即它能表示256个数,数的表示范围为-128----+127(共256,注意别忘了0),正负数各占一半-128------+127,但对于-128-----1计算机会以它的补码表示即-128对应+128,-127----+129,-126-----+130,-2----254,-1----+255,当在打印输出是如果你要在8位的操作系统中输出+128-------+255,它会以-128--------1给你输出来 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一块内存的时候,管理库向操作系统申请一块空间(可能会比你申请的大一些),然后在这块空间中记录一些管理信息(一般是在你申请的内存前面一点),并将可用内存的地址返回。但是释放内存的时候,管理库通常都不会将内存还给操作系统,因此你是可以继续访问这块地址的,只不过。。。。。。。。楼上都说过了,最好别这么干。 #include"stdio.h" #include"string.h" voidmain() charaa[10]; printf("%d",strlen(aa)); Printf(“%d”,sizeof(aa)); sizeof()和初不初始化,没有关系; strlen()和初始化有关。 char(*str)[20];/*str是一个数组指针,即指向数组的指针.*/ char*str[20];/*str是一个指针数组,其元素为指针型数据.*/ 答:0x801010用二进制表示为:“100000000001000000010000”,十进制的值为8392720,再加上5就是8392725 chart::4; chark:4; unsignedshorti:8; unsignedlongm; };问sizeof(A)= 给定结构structA chart:4;4位 chark:4;4位 unsignedshorti:8;8位 unsignedlongm;//偏移2字节保证4字节对齐 };//共8字节 intadd_n(intn) staticinti=100; i+=n; returni; 当你第二次调用时得不到正确的结果,难道你写个函数就是为了调用一次?问题就出在static上//static会把值保存下来 #include #include #include typedefstructAA intb1:5; intb2:2; }AA; 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 intfunc(x) intcountx=0; while(x) countx++; x=x&(x-1);//死记,反正数里面只要有1循环就不会停止,每次最低位一定被清零0---9最低位位是0--1---0----1---0----交叉排列的 returncountx; 结果呢? 知道了这是统计9999的二进制数值中有多少个1的函数,且有 9999=9×1024+512+256+15 9×1024中含有1的个数为2; 512中含有1的个数为1; 256中含有1的个数为1; 15中含有1的个数为4; 故共有1的个数为8,结果为8。 1000-1=0111,正好是原数取反。这就是原理。 用这种方法来求1的个数是很效率很高的。 不必去一个一个地移位。循环次数最少。 structbit {inta:3; intb:2; intc:3; }; bits; char*c=(char*)&s; cout< *c=0x99; cout< inta=-1; printf("%x",a); 输出为什么是 4 1 -1 -4 ffffffff 因为0x99在内存中表示为10011001,a=001,b=11,c=100 当c为有符合数时,c=100,最高1为表示c为负数,负数在计算机用补码表示,所以c=-4;同理 b=-1; 当c为有符合数时,c=100,即c=4,同理b=3 #defineMAX255 unsignedcharA[MAX],i;//i被定义为unsignedchar for(i=0;i<=MAX;i++) A[i]=i; 解答:死循环加数组越界访问(C/C++不进行数组越界检查) MAX=255 数组A的下标范围为:0..MAX-1,这是其一.. 其二.当i循环到255时,循环内执行: A[255]=255; 这句本身没有问题..但是返回for(i=0;i<=MAX;i++)语句时, 由于unsignedchar的取值范围在(0..255),i++以后i又为0了..无限循环下去. structname1{ charstr; shortx; intnum; structname2{ sizeof(structname1)=8,sizeof(structname2)=12 在第二个结构中,为保证num按四个字节对齐,char后必须留出3字节的空间;同时为保证整个结构的自然对齐(这里是4字节对齐),在x后还要补齐2个字节,这样就是12字节。 inti:8; intj:4; inta:3; doubleb; structs2 printf("sizeof(s1)=%d\n",sizeof(s1)); printf("sizeof(s2)=%d\n",sizeof(s2)); result:16,24 第一个structs1 理论上是这样的,首先是i在相对0的位置,占8位一个字节,然后,j就在相对一个字节的位置,由于一个位置的字节数是4位的倍数,因此不用对齐,就放在那里了,然后是a,要在3位的倍数关系的位置上,因此要移一位,在15位的位置上放下,目前总共是18位,折算过来是2字节2位的样子,由于double是8字节的,因此要在相对0要是8个字节的位置上放下,因此从18位开始到8个字节之间的位置被忽略,直接放在8字节的位置了,因此,总共是16字节。特殊注意 第二个最后会对照是不是结构体内最大数据的倍数,不是的话,会补成是最大数据的倍数 structBBB longnum; char*name; shortintdata; charha; shortba[5]; }*p; p=0x1000000; p+0x200=____; (Ulong)p+0x200=____; (char*)p+0x200=____; 希望各位达人给出答案和原因,谢谢拉 解答:假设在32位CPU上, sizeof(long)=4bytes sizeof(char*)=4bytes sizeof(shortint)=sizeof(short)=2bytes sizeof(char)=1bytes 由于是4字节对齐, sizeof(structBBB)=sizeof(*p) =4+4+2+1+1/*补齐*/+2*5+2/*补齐*/=24bytes(经Dev-C++验证) =0x1000000+0x200*24 =0x1000000+0x200 =0x1000000+0x200*4 Voidtest1() charstring[10]; char*str1="0123456789"; strcpy(string,str1);//溢出,应该包括一个存放'\0'的字符string[11] Voidtest2() charstring[10],str1[10]; for(I=0;I<10;I++) str1[i]='a'; Voidtest3(char*str1) if(strlen(str1)<=10)//改成<10,字符溢出,将strlen改为sizeof也可以 strcpy(string,str1); voidg(int**); intline[10],i; int*p=line;//p是地址的地址 for(i=0;i<10;i++) *p=i; g(&p);//数组对应的值加1 printf("%d\n",line[i]); voidg(int**p) (**p)++; (*p)++;//无效 输出: 2 3 5 6 7 8 9 10 intsum(inta) autointc=0; staticintb=3; c+=1; b+=2; return(a+b+c); intI; inta=2; for(I=0;I<5;I++) printf("%d,",sum(a)); //static会保存上次结果,记住这一点,剩下的自己写 输出:8,10,12,14,16, intfunc(inta) intb; switch(a) case1:30; case2:20; case3:16; default:0 returnb; 则func(1)= //b定义后就没有赋值 inta[3]; a[0]=0;a[1]=1;a[2]=2; int*p,*q; p=a; q=&a[2]; 则a[q-p]=a[2] 解释:指针一次移动一个int但计数为1 char*RetMenory(void) charp[]=“hellowworld”; returnp; voidTest(void) str=RetMemory(); RetMenory执行完毕,p资源被回收,指向未知地址。返回地址,str的内容应是不可预测的,打印的应该是str的地址 typedefstruct inta:2; intc:1; }test; testt; t.a=1; t.b=3; t.c=1; printf("%d",t.a); printf("%d",t.b); printf("%d",t.c); t.a为01,输出就是1 t.b为11,输出就是-1 t.c为1,输出也是-1 3个都是有符号数int嘛。 这是位扩展问题//查一下 01 11 编译器进行符号扩展 voidtest2() inti; 解答:如果面试者指出字符数组str1不能在数组内结束可以给3分;如果面试者指出strcpy(string,str1)调用使得从str1内存起复制到string内存起所复制的字节数具有不确定性可以给7分,在此基础上指出库函数strcpy工作方式的给10分; str1不能在数组内结束:因为str1的存储为:{a,a,a,a,a,a,a,a,a,a},没有'\0'(字符串结束符),所以不能结束 strcpy(char*s1,char*s2)他的工作原理是,扫描s2指向的内存,逐个字符付到s1所指向的内存,直到碰到'\0',因为str1结尾没有'\0',所以具有不确定性,不知道他后面还会付什么东东。 正确应如下 for(i=0;i<9;i++) str1[i]='a'+i;//把abcdefghi赋值给字符数组 str[i]='\0';//加上结束符 intarr[]={6,7,8,9,10}; int*ptr=arr; *(ptr++)+=123; printf(“%d%d”,*ptr,*(++ptr)); 输出:88 过程:对于*(ptr++)+=123;先做加法6+123,然后++,指针指向7;对于printf(“%d%d”,*ptr,*(++ptr));从后往前执行,指针先++,指向8,然后输出8,紧接着再输出8 char*a="hello"; char*b="hello"; if(a==b) printf("YES"); else printf("NO"); 这个简单的面试题目,我选输出no(对比的应该是指针地址吧),可在VC是YES在C是NO lz的呢,是一个常量字符串。位于静态存储区,它在程序生命期内恒定不变。如果编译器优化的话,会有可能a和b同时指向同一个hello的。则地址相同。如果编译器没有优化,那么就是两个不同的地址,则不同 voidfoo(intm,intn) printf("m=%d,n=%d\n",m,n); intb=3; foo(b+=3,++b);//遇到函数里自加减的这种题都不定别去管 printf("b=%d\n",b); 输出:m=7,n=4,b=7(VC6.0) #includestring.h main(void) {char*src="hello,world"; char*dest=NULL; dest=(char*)malloc(strlen(src)); char*s=src[len]; d++=s--; printf("%s",dest); 找出错误!!实现逆排**************** #include"malloc.h" dest=(char*)malloc(sizeof(char)*(strlen(src)+1)); char*s=src+len-1; *d='\0'; 12 34 56 输出到file2.txt: intmain(void) intMAX=10; int*a=(int*)malloc(MAX*sizeof(int)); int*b; FILE*fp1; FILE*fp2; fp1=fopen("a.txt","r"); if(fp1==NULL) {printf("error1"); exit(-1); fp2=fopen("b.txt","w"); if(fp2==NULL) {printf("error2"); inti=0; intj=0; while(fscanf(fp1,"%d",&a[i])!=EOF) i++; j++; if(i>=MAX) MAX=2*MAX; b=(int*)realloc(a,MAX*sizeof(int)); if(b==NULL) printf("error3"); a=b; for(;--j>=0;) fprintf(fp2,"%d\n",a[j]); fclose(fp1); fclose(fp2); 例如n=5 5=1+4;5=2+3(相加的数不能重复) 则输出 1,4;2,3。 unsignedlonginti,j,k; printf("pleaseinputthenumber\n"); scanf("%d",&i); if(i%2==0) j=i/2;//思想:一个被加数一定是这个数的1/2的左边,一个在右边 j=i/2+1; printf("Theresultis\n");