(1)什么是预编译,何时需要预编译?
1. 总是使用而不经常改动的大型代码体。(例如#define宏定义的代码,在预处理阶段就会进行代码替换,而不是在编译阶段按照语法语义生成代码。)
2. 程序由多个模块组成,所有模块都使用一组标准的包含文件和相同的编译选项。在这种情况下,可以将所有包含文件编译为一个预编译头。(这里的理解是)
预编译指令指示了在程序正式编译前就由编译器进行的操作,可以放在程序中的任何位置。
其中Visual Studio新建的C++项目就自动为项目添加了预编译头文件,名称为“pch.h”,用户可以将一些不经常被改变的代码,还是如#define宏定义,inline内联函数等,或者将一些系统必须包含的头文件等,添加到“pch.h”文件中。
(2)char * const p; char const * p; const char *p 上述三个有什么区别?
主要是看const后面的变量,例如:
char * const p, 由于const在p前面,因此这个说明p是一个常量指针,不能修改。
char const * p,const在*p的前面,因此说明*p是一个常量,即p是一个指向常量的指针,其指向的常量不可修改。
const char *p, 与char const * p相同,const在char *p前面,但是由于char表示变量类型,对const的作用对象无影响,因此实际还是表示*p是一个const类型,即指针所指的变量是常量,不可改变。
(3)字符数组和字符串常量
char str1[] = "abc";
char str2[] = "abc";
const char str3[] = "abc";
const char str4[] = "abc";
const char *str5 = "abc";
const char *str6= "abc";
char *str7 = "abc"; //应该加上const限定符
char *str8 = "abc"; //应该加上const限定符
cout << ( str1 == str2 ) << endl;
cout << ( str3 == str4 ) << endl;
cout << ( str5 == str6 ) << endl;
cout << ( str7 == str8 ) << endl;
注意一点,“abc”是一个字符串常量,用其初始化字符数组,str1~str4都是字符数组变量,其每一个都对应不同变量在内存的存储空间,所以当然是互不相等的。而str5~str8,它们是指针,指向同一个常量区域,因此他们互相都是相等的。可以看看添加下面的代码进行验证。
printf("str1: %lu\n",str1);
printf("str2: %lu\n",str2);
printf("str3: %lu\n",str3);
printf("str4: %lu\n",str4);
printf("str5: %lu\n",str5);
printf("str6: %lu\n",str6);
printf("str7: %lu\n",str7);
printf("str8: %lu\n",str8);
得到的结果如下:
str1: 2686748
str2: 2686744
str3: 2686740
str4: 2686736
str5: 4214885
str6: 4214885
str7: 4214885
str8: 4214885
另外这道题需要注意的是,“abc”是字符串常量,其指针必须是一个const类型的char*,即表示字符串常量中的内容不允许修改。而实际str6和str7用char*类型的字符指针去指向字符串常量,会报错,应该在前面加上const限定符。
(4)以下代码中sizeof的用法有问题吗?
void UpperCase( char str[] ) // 将str中的小写字母转换成大写字母
{ for( size_t i=0; i
上面代码UpperCase函数中sizeof实际上是检测了一个char型的指针,当然是返回指针的大小(也就是4),在main函数中可以得到正确的sizeof长度,是整个数组的大小,但是要注意字符串常量在末尾隐含了一个‘\0’,因此sizeof结果是6。最后输出应该是先打印一个6,然后打印“ABCDe”,即只更新了前四个字母。
其实编译器在这里可能会给出警告:
warning: 'sizeof' on array function parameter 'str' will return size of
'char*' [-Wsizeof-array-argument]
printf("%d\n",sizeof(str));
^
(5)一个32位的机器,该机器的指针是多少位?
指针是多少位只要看地址总线的位数就行了。80386以后的机子都是32的数据总线。所以指针的位数就是4个字节了。
(6)下面程序的输出
int main(void)
{
int a[5]={1,2,3,4,5};
int *ptr=(int*)(&a+1);
printf("%d,%d",*(a+1),*(ptr-1));
return 0;
}
输出:2, 5。
*(a+1)不再赘述,(&a+1)中&a是数组指针,因为a是一个指向5个int的数组的指针,其本质为int (*)[5],然后再其基础上+1,自然是偏移一个数组大小(即偏移5个int大小)得到ptr指针。ptr指针减一之后实际就到了a[4]所在的元素,printf得到的是a[4]=5.
从下面的ptr的地址0x28ff3c和a[0]的地址0x28ff28就可以看出,二者相差了20个字节,就是5个int的大小。
(7)下面代码有什么问题?
int main() {
char a;
char *str=&a;
strcpy(str,"hello");
printf(str); return 0;
}
a定义为char类型的数据,为将“hello”拷贝到a的内存,肯定会在读写时发生内存越界问题。可以改成下面的形式:
int main() {
char a[10];
char *str=a;
strcpy(str,"hello");
printf(str);
return 0;
}
(8)char* s="AAA"; printf("%s",s); s[0]='B'; printf("%s",s);有什么错?
这个在上面讲到了,"AAA"是字符串常量,应该用const指针来指向它;同时const指针所指区域不允许更改,所以对s[0]的赋值操作也不正确。
(9)写一个标准宏,这个宏输入两个参数然后返回较小的一个
#define Min(X, Y) ((X)>(Y)?(Y):(X)) //结尾没有‘;’并且记得加括号
应当注意,这个宏在有些时候无法给出正确的答案,比如下面的代码:
int a=2,b=3;
int* p=&a;
int least=MIN((*p)++,b);//least=3,a=4,b=3
这个函数的本意应该是判断(*p)++的值与b的值的大小,将较小的那个数赋值给least,但是这里需要注意,(*p)先进行自增以后参与三目运算符的比较判断部分,然后三目运算符?:返回的也是(*p)++,这里*p又自增了一次,虽然least能够得到最初的(*p)++与b较小的那个值,但是*p在这个操作过程中自增了两次,这可能不是我们需要的。
(10)嵌入式系统中经常要用到无限循环,你怎么用C编写死循环?
while(1){}或者for(;;)
(11)关键字static的作用是什么?
定义静态变量
(12)关键字const有什么含意?
表示常量,不可被修改的变量。
(13)关键字volatile有什么含意?并举出三个不同的例子?
提示编译器对象的值可能在编译器未监测到的情况下改变。
三个例子:
(具体可以参考:C语言中volatile关键字的作用)
(14)int (*s[10])(int) 表示的是什么?
先看一个简单的:int (*p)(int)表示什么?答:一个指向函数的指针,该函数接收一个int型的参数;
那么,int (*s[10])(int)是不是就是表示一个数组,这个数组里面每个元素都是一个指向函数的指针,该函数接收一个int型的参数,并且返回值也是int。
(15)有以下表达式,请问下列表达式哪些会被编译器禁止?为什么?(原文这个地方比较乱,我按照自己的理解整理了一下)
int a=248, b=4;
int const c=21;
const int *d=&a;
int *conste=&b;
int const *f=&a;
以下是要进行的操作,该操作能否进行见注释:
c=32;//被禁止,编译器提示“表达式必须是可以被修改的左值”,其实就是说c是常量,不能修改
d=&b;//可以执行,*d是const表示d所指向的内存空间不可以被修改,但是d本身可以被修改
*d=43;//被禁止,参考上一条注释
e=34;//这里有两个问题,首先e是const,不能修改,另外e是int*类型,不能赋int类型的值
e=&a;//e是const,不能修改
*e=12;//这个是可以的,因为e是const,但是e指向的变量可以被修改
f=&b;//这个是可以的,*f是const,表示f指向的变量不能被修改,但是f本身可以被修改
(16)交换两个变量的值,不使用第三个变量。即a=3,b=5,交换之后a=5,b=3
这个由两种解法:
//需要注意两个传参不能是指向同一片内存区域的指针
//位运算
void exchange(int* a, int* b){
if(*a==*b)return;
*a^=*b;
*b^=*a;
*a^=*b;
}
//算术算法
void exchange(int* a, int* b){
if(*a==*b)return;
*a=*a+*b;
*b=*a-*b;
*a=*a-*b;
}
(17)c和c++中的struct有什么不同?
C中的结构不能含有成员函数,C++中的结构可以含有成员函数,C++中结构跟类的主要区别在于默认的存储权限不同,结构默认是public,类默认是private。
(18)下面函数
#include
#include
void getmemory(char *p)
{
p=(char *)malloc(100);//在程序中给p(副本)赋值,并不影响实际的str
strcpy(p,"helloworld");
}
int main( )
{
char*str=NULL;
getmemory(str); //传入参数之后,函数实际执行的是一个副本
printf("%s/n",str);
free(str);
return 0;
}
程序运行会崩溃,因为str并没有得到malloc出来的内存,对其调用free会出错。这里其实可以将指针换成int,如果传入一个int类型的变量,在getmemory中改变变量的值,实际并不会对函数外面的变量产生影响。对于int类型参数,应该传其指针,而对于指向int的指针,应该传其指针,也就是指针的指针,即**p。函数可以改成下面的形式:
void getmemory(char **p)
{
*p=(char *)malloc(100);
strcpy(*p,"helloworld");
}
int main( )
{
char*str=NULL;
getmemory(&str); //传入指针的指针
printf("%s\n",str);
free(str);
return 0;
}
(19)charszstr[10]; strcpy(szstr,"0123456789"); 产生什么结果?为什么?
产生错误,但是不会显式表现出来,因为“0123456789”还包含一个隐含的'\0',实际应该有11个字符。
(20)列举几种进程的同步机制,并比较其优缺点
几种进程同步机制:原子操作,互斥锁,信号量,自旋锁,管程,会合,分布式系统。
原子操作:原子对象是一个可通过原子操作被读取或修改的对象,原子操作是指不能被并行线程中断的操作。
自旋锁:自旋锁不会引起调用者睡眠(或者叫阻塞),如果自旋锁已经被别的执行单元保持,调用者就一直循环在这里看自旋锁的保持着是否已经释放了锁。其效率比互斥锁高。
互斥锁:同一时间只能有一个任务持有互斥锁,如果互斥锁已经被别的执行单元保持,调用者就会睡眠(或者叫阻塞),等到执行单元执行完成并且释放互斥锁,另一个阻塞的单元才能进入临界区,访问共享资源。效率比自旋锁低。
信号量机制:信号量可以用于进程或者线程之间,信号量可以并行,运行多个线程同时访问共享资源。除此之外,信号量可以用来实现多任务同步,是流程上的概念,互斥锁将多任务同步变成串行执行。
(21)进程之间通信的途径
以上参考:进程间的五种通信方式介绍,几种进程间的通信方式。
(22)进程死锁的原因
(23)死锁的4个必要条件
(24)死锁的处理
参考:死锁的四个必要条件和解决办法,死锁,死锁的四个必要条件以及处理策略。
(25)操作系统中进程调度策略有哪几种?
以上参考:操作系统中进程调度策略有哪几种?
(26)类的静态成员和非静态成员有何区别?
(27)纯虚函数如何定义?使用时应注意什么?
virtual void f() =0;
纯虚函数只提供接口,子类必须提供其实现。
(28)数组和链表的区别
数组:顺序存储数据,大小固定,可通过下标访问数据;
链表:数据可以随机存储,大小可以动态改变。
(29)ISO七层模型叫什么?TCP/IP属于哪一层?TCP/UDP有何缺点?
ISO七层模型:物理层,数据链路层,网络层,传输层,会话层,表示层,应用层。
TCP/IP属于传输层。
TCP提供了数据流传输、可靠性、有效流控制、全双工操作和多路复用技术等。与TCP不同,UDP不提供对IP协议的可靠机制、流控制以及错误回复功能等。由于UDP比较简单,UDP头包含很少的字节,比TCP负载消耗小。TCP提供稳定的传输服务,有流量控制,缺点是包头大,冗余性不好。UDP:不提供稳定服务,包头小,开销少。
(30)(void *)ptr 和 (*(void**))ptr的结果是否相同?其中ptr为同一个指针
(void*)ptr 和(*(void**))ptr值是相同的
(31)int main() { int x=3; printf("%d",x); return1; } 问函数既然不会被其它函数调用,为什么要返回1?
main中,C标准认为return 0表示成功,非0即表示错误,具体的值时其中具体出错信息。
(32)要对绝对地址0x100000赋值,我们可以用 (unsigned int*)0x100000 =1234; 那么要是想让程序跳转到绝对地址是0x100000去执行,应该怎么做?
*((void(*)( ))0x100000 ) ( ); 首先要将0x100000强制转换成函数指针,即: (void(*)())0x100000 然后再调用它:*((void (*)())0x100000)(); 用typedef可以看得更直观些: typedef void(*)() voidFuncPtr; *((voidFuncPtr)0x100000)();
(33)已知一个数组table,用一个宏定义,求出数据的元素个数
#define NTBL (sizeof(table)/sizeof(table[0]))
(34)线程与进程的区别和联系? 线程是否具有相同的堆栈? dll是否有独立的堆栈?
进程是死的,只是一些资源的集合,真正的程序执行都是线程来完成的,程序启动的时候操作系统就帮你创建了一个主线程。每个线程有自己的堆栈。 DLL中有没有独立的堆栈,这个问题不好回答,或者说这个问题本身是否有问题。因为DLL中的代码是被某些线程所执行,只有线程拥有堆栈,如果DLL中的代码是EXE中的线程所调用,那么这个时候是不是说这个DLL没有自己独立的堆栈?如果DLL中的代码是由DLL自己创建的线程所执行,那么是不是说DLL有独立的堆栈?以上讲的是堆栈,如果对于堆来说,每个DLL有自己的堆,所以如果是从DLL中动态分配的内存,最好是从DLL中删除,如果你从DLL中分配内存,然后在EXE中,或者另外一个DLL中删除,很有可能导致程序崩溃。
(35)下面代码输出是什么?分析过程
过程分析见代码注释。
int main(void){
unsigned short A = 10;
printf("~A = %u\n", ~A); //~A=-11,但是输出格式是unsigned,因此输出4294967285
char c=128; //c=0x80,二进制为1000 0000,输出int,为-128
printf("c=%d\n",c);
return 0;
}
(36)-1,2,7,28,,126请问28和126中间那个数是什么?为什么?
第一题的答案应该是4^3-1=63规律是n^3-1(当n为偶数0,2,4) n^3+1(当n为奇数1,3,5)。
(36)用两个栈实现一个队列的功能?要求给出算法和思路
设2个栈为A、B,一开始均为空。入队: 将新元素push入栈A;出队:(1)判断栈A是否为空;(2)如果为空,执行第三步;如果不为空,则将栈A中所有元素依次pop出并push到栈B; (3)将栈B的栈顶元素pop出。
(37)在c语言库函数中将一个字符转换成整型的函数是atol()吗,这个函数的原型是什么?
函数名:atol;
功能:将字符串转换成长整型数;
用法:long atol(const char *nptr);
示例:
#include
#include
int main(void)
{
long l;
char *str = "98765432";
l = atol(str); //l=98765432
printf("string = %s integer = %ld\n", str, l);
return(0);
}
输出:
string = 98765432 integer = 98765432
(38)对于一个频繁使用的短小函数,在C语言中应用什么实现,在C++中应用什么实现?
C用宏定义(#define),C++用内联函数(inline)。
(39)直接链接两个信令点的一组链路称作什么?
PPP点到点连接。
(40)软件测试都有哪些种类?
黑盒测试:针对系统功能的测试。把测试对象看做一个黑盒子,测试人员完全不考虑程序内部的逻辑结构和内部特性,只依据程序的需求规格说明书,检查程序的功能是否符合它的功能说明。
白盒测试:测试函数功能,各函数接口。是把测试对象看做一个打开的盒子,它允许测试人员利用程序内部的逻辑结构及有关信息,设计或选择测试用例,对程序所有逻辑路径进行测试。通过在不同点检查程序状态,确定实际状态是否与预期的状态一致。
其实软件测试按照不同的分类方式,有很多不同的方法,可以参考:软件测试分类。
(41)确定模块的功能和模块的接口是在软件设计的那个队段完成的?
概要设计阶段。
(42)enum string { x1, x2, x3=10, x4, x5, }x; 问x?
x是一个枚举变量,注意这里的string是枚举类型,枚举类型是整型,如果没有显式声明类型,默认就是int,并且第一个元素默认是0,因此x1=0,x2=1,x4=11,x5=12;x是枚举里面元素的任意一个,这里定义枚举变量,但是没有赋值,因此x值不固定。
(43)有下面代码,请问:p1+5=?;p2+20=?
unsigned char *p1;
unsigned long*p2;
p1=(unsigned char *)0x801000;
p2=(unsigned long *)0x810000;
答案:
//p1+5=0x801005;
//p2+20=0x810014;注意将十进制的20转为16进制,就是0x14
(44)TCP/IP通信建立的过程怎么样,端口有什么用?
TCP/IP通信建立:三次握手,可以参考:TCP/IP--理解TCP三次握手和四次挥手。
端口的作用:确定是哪个应用程序使用该协议。
(45)局部变量能否和全局变量重名?
可以。但是局部变量会屏蔽全局变量。C++中可以使用“::”域解析符来访问全局变量。
(46)如何引用一个已经定义过的全局变量?
可以用引用头文件的方式,也可以用extern关键字,如果用引用头文件方式来引用某个在头文件中声明的全局变量,假定你将那个变量写错了,那么在编译期间会报错,如果你用extern方式引用时,假定你犯了同样的错误,那么在编译期间不会报错,而在连接期间报错。
(47)全局变量可不可以定义在可被多个.C文件包含的头文件中?为什么?
这道题网上答案版本很多。我的理解是,要先搞清楚变量的定义和声明,变量定义只能出现一次,如果是将定义包含在一个被多个.C文件包含的头文件中,会导致重复定义;如果是将声明包含在一个被多个.C文件包含的头文件中,那是可以的,在其他C文件中可以定义,但同时注意,只能在一个特定的c文件中定义。
可以参考:全局变量可不可以定义在可被多个.c文件包含的头文件中,以及这个讨论。
(48)语句for( ;1 ;)有什么问题?它是什么意思?
和while(1)相同,死循环。
(49)do……while和while……do有什么区别?
前一个循环一遍再判断,后一个判断以后再循环。
(50)请写出下列代码的输出内容
输出内容见注释。
#include
#include
int main(void){
int a,b,c,d; a=10;
b=a++; //b=10,a=11
c=++a;//c=12,a=12
d=10*a++; //d=120,a=13
printf("b,c,d:%d,%d,%d",b,c,d);//b=10,c=12,d=120
return 0;
}
(51)static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别?
参考《C Primer Plus 第六版》中的概念:作用域,链接,以及存储期。其中“链接”的概念可能比较陌生,可以参考书上的解释。
全局变量的说明之前加上static就构成了静态的全局变量,全局变量和静态全局变量的作用域相同,都是文件作用域,但是静态全局变量是内部链接(只能在一个翻译单元中使用),全局变量是外部链接(可以在多文件程序中使用)。静态局部变量是改变了局部变量的存储期,将原本局部变量的自动存储器变成了静态局部变量的静态存储器,相较于局部变量,静态局部变量的作用域和链接都没有改变,只是改变了存储期。
(52)程序的局部变量存在于()中,全局变量存在于()中,动态申请数据存在于()中。
局部变量:存储在栈中,由编译器自动分配和释放。
全局变量:存储在静态区,程序结束后由系统释放。
动态申请数据:存储在堆中,如malloc分配的内存空间,需要由程序要自己释放,或者程序结束时释放。如果程序员没有在程序运行期间释放,可能造成内存泄漏。
(53)设有以下说明和定义,则语句printf("%d",sizeof(too)+sizeof(max));的执行结果是?
typedef union {//大小:20字节
long i;
int k[5]; //20字节
char c;
} DATE;
struct data { //大小32字节
int cat; //4字节
DATE cow; //20字节
double dog;//8字节
}too;
DATE max;
结果是52(32+20),详见上面代码中注释。
(54)队列和栈有什么区别?
队列先进先出,栈后进先出。
(55)已知一个单向链表的头,请写出删除其某一个结点的算法,要求,先找到此结点,然后删除。
如下:
typedef struct node{
int number;
struct node* next;
}Node;
Node*Delete(Node *Head,int key){
Node* newHead=(Node*)malloc(sizeof(Node*));
Node* Pointer;
newHead->next=Head;
while(newHead->next){
if(newHead->next->number==key){
Pointer=newHead->next;
newHead->next=newHead->next->next;
free(Pointer);
break;
}else{
newHead=newHead->next;
}
}
return newHead->next;
}
(1)有数组定义int a[2][2]={{1},{2,3}};则a[0][1]的值为0。
正确。数组部分初始化之后,没有初始化的元素默认赋值为0;但是如果数组只是定义了,没有部分初始化,则所有元素都是垃圾数据。
(2)int (*ptr) (),则ptr是一维数组的名字。
错误。前面已经介绍过,int (*ptr) ();定义了一个指向函数的指针变量,其指向的函数的返回值为int。
(3)指针在任何情况下都可进行>, <,>=, <=,==运算。
这个题其实吧,如果只是将指针作为整型进行比较,是可以的(不同类型的指针之间需要强制类型转换,统一指针类型),但是没有任何意义。
(4)switch(c) 语句中c可以是int,long,char ,float ,unsigned int 类型。
错,switch只能是整型,float不行。
(1)在OSI 7 层模型中,网络层的功能有( )
答案:确定数据包从源到目的如何选择路由。
物理层:在信道上传输原始的比特流;
数据链路层:加强物理层数据传输原始比特流的功能并进行流量控制;
网络层:确定数据包从源到目的如何选择路由;
传输层:确保到达对方的各段信息正确无误。
(2)FDDI 使用的是___局域网技术。
答案:令牌环。
(3)下面那种LAN 是应用CSMA/CD协议的()
答案:ETHERNET。
(4)TCP 和UDP 协议的相似之处是
答案:传输层协议。
(5)应用程序PING 发出的是___报文.( )
答案:ICMP 请求报文。
....未完待续....