第一部分:基本概念及其它问答题
1、 关键字static的作用是什么?
static 可以申明一个静态变量,可以申明一些静态方法和静态类,由static修饰的静态成员是保存在全局变量区域,在编译的时候为变量或者方法开辟空间,生命周期随着从空间开辟了开始一直到程序的运行结束,该段空间才会释放,如果是static修饰的方法,那么这个方法可以在内外通过类名来调用。Static修饰的方法或者变量只初始化一次,也就是在第一次才初始化,如果到了第二次执行初始化,那么系统会自动判断当前变量或者方法是否初始化过了,如果是,那么则不会在初始化,如果没有,则才会初始化。
在C语言中,关键字static有三个明显的作用:
1). 在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。
2). 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量。
3). 在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用。
大多数应试者能正确回答第一部分,一部分能正确回答第二部分,同是很少的人能懂得第三部分。这是一个应试者的严重的缺点,因为他显然不懂得本地化数
据和代码范围的好处和重要性。
2、“引用”与指针的区别是什么?
引用相当于给变量起个别名,实质是一个变量或者一个内存空间只是起了两个不同的名称而已,对其中任意一个操作都会影响到另外一个名称变量里面的值,指针变量是指指向变量或者方法的地址,通过指针变量也能够起到改变或者调用原有变量里面的值,指针有多级指针的说法,例如二级指针也就是指向指针的地址,指针的应用范围比引用更广泛一些,但引用相对而言使用起来比较方便一些,仅仅是起个别名就OK了。
1) 引用必须被初始化,指针不必。
2) 引用初始化以后不能被改变,指针可以改变所指的对象。
3) 不存在指向空值的引用,但是存在指向空值的指针。
指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作。程序中使用指针,程序的可读性差;而引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作。
流操作符<<和>>、赋值操作符=的返回值、拷贝构造函数的参数、赋值操作符=的参数、其它情况都推荐使用引用
3、.h头文件中的ifndef/define/endif 的作用?
防止该头文件重定义。
4、#include<file.h>与 #include "file.h"的区别?
前面一种是从系统文件中去找file.h文件,而后者是从当前项目文件中去找file.h文件。
5、冒泡排序算法的时间复杂度是什么?
O(n^2) [n的平方]
6、不能做switch()的参数类型
除了×××,字符型,枚举类型,其他都不能。
7、局部变量能否和全局变量重名?
能,但最好不要这让用,防止开发者混淆,局部变量的作用范围只是当前方法内,空间开辟在栈上,而全局变量作用范围在整个程序始末,开辟空间在全局变量区。
答:能,局部会屏蔽全局。要用全局变量,需要使用"::"
局部变量可以与全局变量同名,在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量。对于有些编译器而言,在同一个函数内可以定义多个同名的局部变量,比如在两个循环体内都定义一个同名的局部变量,而那个局部变量的作用域就在那个循环体内
8、如何引用一个已经定义过的全局变量?
采用extern关键字来实现。
答、可以用引用头文件的方式,也可以用extern关键字,如果用引用头文件方式来引用某个在头文件中声明的全局变量,假定你将那个变量写错了,那么在编译期间会报错,如果你用extern方式引用时,假定你犯了同样的错误,那么在编译期间不会报错,而在连接期间报错。
9、全局变量可不可以定义在可被多个.C文件包含的头文件中?为什么?
答、可以,在不同的C文件中以static形式来声明同名全局变量。
可以在不同的C文件中声明同名的全局变量,前提是其中只能有一个C文件中对此变量赋初值,此时连接不会出错。
10、语句for( ;1 ;)有什么问题?它是什么意思?
该循环将是一个无限循环,没有结束条件,或者说结束条件永远达不到。将达到让循环体一直循环执行的效果,相当于while(1)。
11、解释堆和栈的区别
堆的空间比较大,栈的空间比较小,很有限。但是栈的存取速度比较快,堆的存取速度慢。堆用malloc开辟,释放用free关键字释放,开辟了堆的内存空间需要我们手动自己释放空间,而开辟在栈上面的空间则不需要,这时编译器自己自动为我们开辟和释放的。
(1)申请方式
stack:由系统自动分配。例如,声明在函数中一个局部变量int b;系统自动在栈中为b开辟空间
heap:需要程序员自己申请,并指明大小,在c中malloc函数
如p1=(char*)malloc(10);
在C++中用new运算符
如p2=(char*)malloc(10);
但是注意p1、p2本身是在栈中的。
(2)申请后系统的响应
栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。
堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,
会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。
(3)申请大小的限制
栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。
(4)申请效率的比较:
栈:由系统自动分配,速度较快。但程序员是无法控制的。
堆:是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便.
另外,在WINDOWS下,最好的方式是用Virtual Alloc分配内存,他不是在堆,也不是在栈,而是直接在进程的地址空间中保留一块内存,虽然用起来最不方便。但是速度快,也最灵活。
(5)堆和栈中的存储内容
栈:在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。
当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。
堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容由程序员安排。
(6)存取效率的比较
char s1[]="aaaaaaaaaaaaaaa";
char *s2="bbbbbbbbbbbbbbbbb";
aaaaaaaaaaa是在运行时刻赋值的;
而bbbbbbbbbbb是在编译时就确定的;
但是,在以后的存取中,在栈上的数组比指针所指向的字符串(例如堆)快。
比如:
#include
voidmain()
{
char a=1;
char c[]="1234567890";
char *p="1234567890";
a = c[1];
a = p[1];
return;
}
对应的汇编代码
10:a=c[1];
004010678A4DF1movcl,byteptr[ebp-0Fh]
0040106A884DFCmovbyteptr[ebp-4],cl
11:a=p[1];
0040106D8B55ECmovedx,dwordptr[ebp-14h]
004010708A4201moval,byteptr[edx+1]
004010738845FCmovbyteptr[ebp-4],al
第一种在读取时直接就把字符串中的元素读到寄存器cl中,而第二种则要先把指针值读到edx中,在根据edx读取字符,显然慢了。
12、关键字const是什么含意?
const关键字是静态常量的意思,开辟在静态区域,一旦创建以后就不可以修改空间里面的值。
constchar *p,和char const *p 是一样的效果,表示指针p指向的区域里面的值不可改变,指针方向可以改变。
constchar * const p是指指针的指向和指针所指向的里面的值都不可以改变。
char* const p 是指指针的指向不可以改变,但是指针指向的那个区域里面的值是可以改变的。
答:我只要一听到被面试者说:“const意味着常数”,我就知道我正在和一个业余者打交道。去年Dan Saks已经在他的文章里完全概括了const的所有用法,因此ESP(译者:Embedded Systems Programming)的每一位读者应该非常熟悉const能做什么和不能做什么.如果你从没有读到那篇文章,只要能说出const意味着“只读”就可以了。尽管这个答案不是完全的答案,但我接受它作为一个正确的答案。(如果你想知道更详细的答案,仔细读一下Saks的文章吧。)如果应试者能正确回答这个问题,我将问他一个附加的问题:下面的声明都是什么意思?
const int a;
int const a;
const int *a;
int * const a;
int const * a const;
前两个的作用是一样,a是一个常整型数。第三个意味着a是一个指向常整型数的指针(也就是,整型数是不可修改的,但指针可以)。第四个意思a是一个指向整型数的常指针(也就是说,指针指向的整型数是可以修改的,但指针是不可修改的)。最后一个意味着a是一个指向常整型数的常指针(也就是说,指针指向的整型数是不可修改的,同时指针也是不可修改的)。如果应试者能正确回答这些问题,那么他就给我留下了一个好印象。顺带提一句,也许你可能会问,即使不用关键字 const,也还是能很容易写出功能正确的程序,那么我为什么还要如此看重关键字const呢?我也如下的几下理由:
1). 关键字const的作用是为给读你代码的人传达非常有用的信息,实际上,声明一个参数为常量是为了告诉了用户这个参数的应用目的。如果你曾花很多时间清理其它人留下的垃圾,你就会很快学会感谢这点多余的信息。(当然,懂得用const的程序员很少会留下的垃圾让别人来清理的。)
2). 通过给优化器一些附加的信息,使用关键字const也许能产生更紧凑的代码。
3). 合理地使用关键字const可以使编译器很自然地保护那些不希望被改变的参数,防止其被无意的代码修改。简而言之,这样可以减少bug的出现
13、结构与联合有和区别?
结构体和联合体他们内存开辟的方式不一样,联合体成员是共享内存,而结构体则是成员变量都有自己的一块独立的内存空间。
答:(1). 结构和联合都是由多个不同的数据类型成员组成,但在任何同一时刻,联合中只存放了一个被选中的成员(所有成员共用一块地址空间),而结构的所有成员都存在(不同成员的存放地址不同)。
(2). 对于联合的不同成员赋值,将会对其它成员重写, 原来成员的值就不存在了,而对于结构的不同成员赋值是互不影响的
14、描述内存分配方式以及它们的区别?
联合体是里面的成员共享一块内存区域,以最大的内型为基准,然后整个联合体开辟的空间就是单一的那个最大的类型变量所开辟的空间。
结构体是里面的成员变量,都以开辟空间占用的最大的那个类型为对其基准然后乘以他们成员个数,也就是结构体整体的内存空间开辟的大小。
答:1)从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。
2)在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集。
3)从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new 申请任意多少的内存,程序员自己负责在何时用free或delete 释放内存。动态内存的生存期由程序员决定,使用非常灵活,但问题也最多
15、请说出const与#define 相比,有何优点?
#define是在编译的时候就定义了,而const则是在程序执行到当前变量的定义才定义该变量的。const相比那样,定义变量的形式更多样化。
答:Const作用:定义常量、修饰函数参数、修饰函数返回值三个作用。被Const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。
1) const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误。
2)有些集成化的调试工具可以对const常量进行调试,但是不能对宏常量进行调试。
16、简述数组与指针的区别?
数组的首地址也就是数组的指针,数组的空间是开辟在栈上的,里面的内容可以改变,而指针定义的变量,所指向的内容是开辟在静态区域,它所指向的内容是不可以改变的。
答:数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。指针可以随时指向任意类型的内存块。
(1)修改内容上的差别
char a[] = “hello”;
a[0] = ‘X’;
char *p = “world”; // 注意p指向常量字符串
p[0] = ‘X’; // 编译器不能发现该错误,运行时错误
(2) 用运算符sizeof可以计算出数组的容量(字节数)。sizeof(p),p为指针得到的是一个指针变量的字节数,而不是p所指的内存容量。C++/C语言没有办法知道指针所指的内存容量,除非在申请内存时记住它。注意当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针。
char a[] = "hello world";
char *p = a;
cout<< sizeof(a) <<endl; // 12 字节
cout<< sizeof(p) <<endl; // 4 字节
计算数组和指针的内存容量
void Func(char a[100])
{
cout<< sizeof(a) <<endl; // 4 字节而不是100字节
}
17、分别写出BOOL,int,float,指针类型的变量a 与“零”的比较语句。
1.BOOLf = true;if(f);
2.intf = 0;if(f == 0);
3.floatf = 0;if((f>-0.000001)&&(f<0.000001));最好是用取绝对值函数,但是我忘了。
答:BOOL : if ( !a ) or if(a)
int : if ( a == 0)
float : const EXPRESSION EXP = 0.000001
if ( a < EXP&& a >-EXP)
pointer : if ( a != NULL) or if(a == NULL)
18、如何判断一段程序是由C 编译程序还是由C++编译程序编译的?
externc?不确定了,印象中有点记得又有点模糊
答:#ifdef __cplusplus
cout<<"c++";
#else
cout<<"c";
#endif
19、访问固定的内存位置(Accessing fixed memory locations)
const修饰 ,用char * const p,指针固定,如果有需要也可以将指向的内容也固定 const char * const p
答:嵌入式系统经常具有要求程序员去访问某特定的内存位置的特点。在某工程中,要求设置一绝对地址为0x67a9的整型变量的值为0xaa66。编译器是一个纯粹的ANSI编译器。写代码去完成这一任务。
这一问题测试你是否知道为了访问一绝对地址把一个整型数强制转换(typecast)为一指针是合法的。这一问题的实现方式随着个人风格不同而不同。典型的类似代码如下:
int *ptr;
ptr = (int *)0x67a9;
*ptr = 0xaa66;
A more obscure approach is:
一个较晦涩的方法是:
*(int * const)(0x67a9) = 0xaa55;
即使你的品味更接近第二种方案,但我建议你在面试时使用第一种方案。
20、用变量a给出下面的定义
a) 一个整型数(An integer)
int a;
b) 一个指向整型数的指针(A pointer to an integer)
int* a;
c) 一个指向指针的的指针,它指向的指针是指向一个整型数(A pointer to apointer to an integer)
int**a;
d) 一个有10个整型数的数组(An arrayof 10 integers)
inta[10];
e) 一个有10个指针的数组,该指针是指向一个整型数的(An array of 10 pointers to integers)
int a*[10] int *a[10];
f) 一个指向有10个整型数数组的指针(Apointer to an array of 10 integers)
int* a[10] int (*a)[10];
g) 一个指向函数的指针,该函数有一个整型参数并返回一个整型数(A pointer to afunction that takes an integer as an argument and returns an integer)
int* a(int) int (*a)(int);
h) 一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数( An array of ten pointers to functions that take an integer
argument and return an integer )
int (*a[10])(int);
不记得了,有点晕了!这一块知识害得加强!
21、A.c 和B.c两个c文件中使用了两个相同名字的static变量,编译的时候会不会有问题?这两个static变量会保存到哪里(栈还是堆或者其他的)?
不会有问题,虽然都是开辟在全局变量区,但是有作用是有范围的限制,要访问c变量必须要加上类名,才能访问,这样就没问题。
答:static的全局变量,表明这个变量仅在本模块中有意义,不会影响其他模块。
他们都放在数据区,但是编译器对他们的命名是不同的。
如果要使变量在其他模块也有意义的话,需要使用extern关键字。
第二部分:程序代码评价或者找错
1、下面的代码输出是什么,为什么?
voidfoo(void)
{
unsigned int a = 6;
int b = -20;
(a+b > 6) ? puts("> 6") : puts("<=6");
}
输出>6,因为这两个变量的类型不同,就存在一个隐式转化的问题,将b隐式转化成无符号×××变量,然后讲个数相加起来还是得到一个无符号×××,这样就>6,输出前一种结果。
这个问题测试你是否懂得C语言中的整数自动转换原则,我发现有些开发者懂得极少这些东西。不管如何,这无符号整型问题的答案是输出是 ">6"。原因是当表达式中存在有符号类型和无符号类型时所有的操作数都自动转换为无符号类型。因此-20变成了一个非常大的正整数,所以该表达式计算出的结果大于6。这一点对于应当频繁用到无符号数据类型的嵌入式系统来说是丰常重要的。如果你答错了这个问题,你也就到了得不到这份工作的边缘。
2、 C语言同意一些令人震惊的结构,下面的结构是合法的吗,如果是它做些什么?
inta = 5, b = 7, c;
c = a+++b;
合法的。运行的结果是:a =6,b=7,c=12;
因为a++,是先将a的值给出来然后a再自增,跟++a是反的,++a是先自增,然后在给出自增后的值。
3、设有以下说明和定义:
typedefunion {long i; int k[5]; char c;} DATE;
structdata { int cat; DATE cow; double dog;} too;
DATEmax;
则语句 printf("%d",sizeof(struct date)+sizeof(max));的执行结果是?
20*3+20=80
答、结果是:52。DATE是一个union,变量公用空间. 里面最大的变量类型是int[5],占用20个字节.所以它的大小是20
data是一个struct,每个变量分开占用空间.依次为int4 + DATE20 +double8 = 32.
所以结果是 20 + 32 = 52.
当然...在某些16位编辑器下, int可能是2字节,那么结果是 int2 + DATE10 + double8 = 20
编译器的结果:union:24 struct:40
4、请写出下列代码的输出内容
#include<stdio.h>
main()
{
inta,b,c,d;
a=10;
b=a++; b=10;a=11;
c=++a; a=12;c=12;
d=10*a++; d=120;a=13;
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、 int len=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、 return 0;
14、}
错在第11行,虽然第9行中s指向数组的末尾,但是如果s—的话会以数组整体为单位长度进行减1,也就是说执行了自减之后,s就指向数组的起始位置,而不是数组的倒数第二个位置。
答:
方法1:
int main(){
char* src ="hello,world";
int len = 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);// 使用完,应当释放空间,以免造成内存汇泄露
return 0;
}
方法2:利用数组来实现
#include <stdio.h>
#include <string.h>
main()
{
char str[]="hello,world";
int len=strlen(str);
char t;
for(int i=0; i<len/2;i++)
{
t=str[i];
str[i]=str[len-i-1];str[len-i-1]=t;
}
printf("%s",str);
return 0;
}
6、请问下面程序有什么错误?
int a[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 * const p; //常量指针,p的值不可以修改
charconst * p;//指向常量的指针,指向的常量值不可以改
constchar *p和charconst *p 指针常量,p可以变,但是指向的数不可以变
8、写出下面的结果
charstr1[] = "abc";
charstr2[] = "abc";
constchar str3[] = "abc";
constchar str4[] = "abc";
constchar *str5 = "abc";
constchar *str6 = "abc";
char*str7 = "abc";
char*str8 = "abc";
cout<< ( str1 == str2 ) << endl; 0
cout<< ( str3 == str4 ) << endl; 0
cout<< ( str5 == str6 ) << endl; 0
cout<< ( str7 == str8 ) << endl; 1
结果是:0 0 1 1
解答:str1,str2,str3,str4是数组变量,它们有各自的内存空间;
而str5,str6,str7,str8是指针,它们指向相同的常量区域。
9、以下代码中的两个sizeof用法有问题吗?
voidUpperCase( char str[] ) // 将 str 中的小写字母转换成大写字母
{
for( size_t i=0; i<sizeof(str)/sizeof(str[0]);++i )
if( 'a'<=str[i] &&str[i]<='z' )
str[i] -= ('a'-'A' );
}
charstr[] = "aBcDe";
cout<< "str字符长度为: " << sizeof(str)/sizeof(str[0]) << endl;
UpperCase(str );
cout<< str << endl;
有问题,参数数组是一个形参,实际上里面的值并没有传过去,sizeof(str)的值应该是8,也就是一个指针的字节大小
答:函数内的sizeof有问题。根据语法,sizeof如用于数组,只能测出静态数组的大小,无法检测动态分配的或外部数组大小。函数外的str是一个静态定义的数组,因此其大小为6,函数内的str实际只是一个指向字符串的指针,没有任何额外的与数组相关的信息,因此sizeof作用于上只将其当指针看,一个指针为4个字节,因此返回4。
10、写出输出结果
main()
{
int a[5]={1,2,3,4,5};
int *ptr=(int *)(&a+1);
printf("%d,%d",*(a+1),*(ptr-1));
}
5,4
输出:2,5
*(a+1)就是a[1],*(ptr-1)就是a[4],执行结果是2,5
&a+1不是首地址+1,系统会认为加一个a数组的偏移,是偏移了一个数组的大小(本例是5个int)
int *ptr=(int*)(&a+1);
则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、请问以下代码有什么问题:
int main()
{
chara;
char*str=&a;
strcpy(str,"hello");
printf(str);
return0;
}
str并没有开辟空间,只是指向一个字符的指针,如果硬要strcpy的话,要先对str指向一个malloc过的一个空间之后,才能继续这样用,调用这个strcpy。
没有为str分配内存空间,将会发生异常
问题出在将一个字符串复制进一个字符变量指针所指地址。虽然可以正确输出结果,但因为越界进行内在读写而导致程序崩溃。
char* s="AAA";
printf("%s",s);
s[0]='B';
printf("%s",s);
有什么错?
"AAA"是字符串常量。s是指针,指向这个字符串常量,所以声明s的时候就有问题。
cosnt char*s="AAA";
然后又因为是常量,所以对是s[0]的赋值操作是不合法的。
12、交换两个变量的值,不使用第三个变量。
即a=3,b=5,交换之后a=5,b=3;
只能针对int和char
a =a^b;
b =a^b;
a =a^b;
或者
b =a + b;
a =b - a;
b =b – a;
17、下面的程序会出现什么结果
#include<stdio.h>
#include <stdlib.h>
void getmemory(char *p)
{
p=(char *) malloc(100);
strcpy(p,"hello world");
}
int main( )
{
char *str=NULL;
getmemory(str);
printf("%s/n",str);
free(str);
return 0;
}
什么都不会输出,main中str并没能通过调用getmemory函数给他开辟空间,解决办法:1.将getmemory函数有一个char*的返回值,然后在main函数中str = getmemory(str)或者2.通过二级指针来解决。getmemory(&str);在函数定义中,参数为char **p;
程序崩溃,getmemory中的malloc不能返回动态内存, free()对str操作很危险
13、下面的语句会出现什么结果?
char szstr[10];
strcpy(szstr,"0123456789");
数组中存有这十个数
答案:长度不一样,会造成非法的OS,应该改为char szstr[11];
14、(void*)ptr 和 (*(void**))ptr的结果是否相同?
相同吧
答:其中ptr为同一个指针
.(void *)ptr 和 (*(void**))ptr值是相同的
15、问函数既然不会被其它函数调用,为什么要返回1?
int main()
{
int x=3;
printf("%d",x);
return 1;
}
return 0程序退出?
答:mian中,c标准认为0表示成功,非0表示错误。具体的值是某中具体出错信息
16、对绝对地址0x100000赋值且想让程序跳转到绝对地址是0x100000去执行
(unsigned int*)0x100000 =1234;
首先要将0x100000强制转换成函数指针,即:
(void (*)())0x100000
然后再调用它:
*((void (*)())0x100000)();
用typedef可以看得更直观些:
typedef void(*)() voidFuncPtr;
*((voidFuncPtr)0x100000)();
17、分析下面的程序:
voidGetMemory(char **p,int num)
{
*p=(char *)malloc(num);
}
intmain()
{
char *str=NULL;
GetMemory(&str,100);
strcpy(str,"hello");
free(str);
if(str!=NULL)
{
strcpy(str,"world");
}
printf("\n str is %s",str);
getchar();
}
程序没有输出,因为str先释放了堆中开辟的空间,他就为null了。
输出str is world。
free 只是释放的str指向的内存空间,它本身的值还是存在的.
所以free之后,有一个好的习惯就是将str=NULL.
此时str指向空间的内存已被回收,如果输出语句之前还存在分配空间的操作的话,这段存储空间是可能被重新分配给其他变量的,
尽管这段程序确实是存在大大的问题(上面各位已经说得很清楚了),但是通常会打印出world来。
这是因为,进程中的内存管理一般不是由操作系统完成的,而是由库函数自己完成的。
当你malloc一块内存的时候,管理库向操作系统申请一块空间(可能会比你申请的大一些),然后在这块空间中记录一些管理信息(一般是在你申请的内存前面一点),并将可用内存的地址返回。但是释放内存的时候,管理库通常都不会将内存还给操作系统,因此你是可以继续访问这块地址的,只不过。。。。。。。。楼上都说过了,最好别这么干。
18、给定结构struct A
{
char t:4;
char k:4;
unsigned short i:8;
unsigned long m;
};问sizeof(A) = ?
8*3= 24
给定结构struct A
{
char t:4; 4位
char k:4; 4位
unsigned short i:8; 8位
unsigned long m; // 偏移2字节保证4字节对齐
}; // 共8字节
19、下面的函数实现在一个数上加一个数,有什么错误?请改正。
intadd_n ( int n )
{
static int i = 100;
i += n;
return i;
}
i是静态变量,只会初始化一次,应去掉static
20、给出下面程序的答案
#include<iostream.h>
#include<string.h>
#include<malloc.h>
#include<stdio.h>
#include<stdlib.h>
#include<memory.h>
typedefstruct AA
{
int b1:5;
int b2:2;
}AA;
voidmain()
{
AA aa;
char cc[100];
strcpy(cc,"0123456789abcdefghijklmnopqrstuvwxyz");
memcpy(&aa,cc,sizeof(AA));
cout << aa.b1 <<endl;
cout << aa.b2 <<endl;
}
答案是 -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(struct name2)=的结果
structname1{
char str;
short x;
int num;
}
4*3=12
structname2{
char str;
int num;
short x;
}
4*3 = 12
sizeof(structname1)=8,sizeof(struct name2)=12
在第二个结构中,为保证num按四个字节对齐,char后必须留出3字节的空间;同时为保证整个结构的自然对齐(这里是4字节对齐),在x后还要补齐2个字节,这样就是12字节。
void(*func[10])(void (*A)(void *));
typedef int III;
#define IIII int;
区别:
#define就作简单替换,typedef
C++四种强制类型转换:
static_cast
const_cast
reinterpret_cast
dynamic_cast
例如:
const char *p = "sadfsad";
char *p1 = const_cast<char *>(p);
int i=0;
int j=0;
if((i++&&++i)&&(j++)){};
结果:i=1;j=0;
在if条件判断中,&&先看前面的,先看前面的,只要为否就不会再运算后面的条件,所以只运行i++,结果是0;
#include <stdio.h>
typedef union
{
long i; //内存以8对齐,但不够放int数组,所以要3份8字节的空间
int k[5];
char c;
}DATE;
struct aa {
int a[21];
};
struct date
{
int cat;
DATE cow; //按照联合体中最长的内型和当前对象最长的类型为基准对齐,如果是结构体的话还是看结构体中最长的类型,
//struct aa a; //解释:字节对齐以8字节为基础,先开辟一个8字节的,结果存了4个字节空间,然后后面还有四个字节空间存放结构体中的int a[0],然后后面在以8字节为单位空间去开辟存储
double dog;
}too;
DATE max;
date:48 union:24