C软件工程师笔试题.docx
一、请填写BOOL, float,指针变量与“零值”比较的if语句。(10分)提示:这里“零值”可以是0,0.0, FALSE或者“空指针”。例如int变量n与“零值”比较的 if 语句为:if(n=0)if(n !=0)以此类推。请写出BOOL flag与“零值”比较的if语句:标准答案:if (flag)if( Iflag)如下写法均属不良风格,不得分。if (flag = TRUE) if (flag = 1) if (flag = FALSE) if (flag = 0)请写出float x与“零值”比较的if语句:标准答案示例:const float EPSINON = 0.00001;if(x>=EPSINON)&&(x<=EPSINON)不可将浮点变量用“或“ !二”与数字比较,应该 设法转化成“>="或此类形式。如下是错误的写法,不得分。if (x = 0.0) if (x != 0.0)请写出char*p与“零值”比较的if语句:标准答案:if (p = NULL)if (p !=NULL)如下写法均属不良风格,不得分。if (p=0) if (p !=0) if (p) if (!)二、以下为Windows NT下的32位C+程序,请计算sizeof的值(10分)char str = "Hello" ; char *p = str; int n = 10;sizeof (str) = 6 sizeof ( p ) = 4 sizeof ( n ) = 4void Func ( char str100)请计算 sizeof( str) = 4void *p = malloc( 100 );请计算 sizeof ( p ) = 4三、简答题(25分)1、头文件中的ifndef/define/endif干什么用?防止该头文件被重复引用2、#include <filename.h> 和 #include filename.hn 有什么区别?答:对于#include <filename.h> ,编译器从标准库路径开始搜索filename.h 对于#include ufilename.hv ,编译器从用户的工作路径开始搜索filename.h3、const有什么用途?(请至少说明两种)答:(1)可以定义const常量(2) const可以修饰函数的参数、返回值,甚至函数的定义体。被const修饰的东西都受到 强制保护,可以预防意外的变动,能提高程序的健壮性。4、在C+程序中调用被C编译器编译后的函数,为什么要加extern "C”声明?答:C+语言支持函数重载,C语言不支持函数重载。函数被C+编译后在库中的名字与C 语言的不同。假设某个函数的原型为:voidfoo(int x, int y);该函数被C编译器编译后在库中的名字为_f。,而C+编译器则会产生像_foo_int_int之类的 名字。free(arr);return j;) int main() ( int n, m; scanf(,%d%d"/ &n, &m); printf(''最后胜利的是d 号!Josephu(n, m);system("pause");return 0;)链表实现:/include <stdio.h>#include <malloc.h> typedef struct Node (int index;struct Node *next;JosephuNode;int Josephu(int n, int m) ( int i, j;JosephuNode *head, *tail;head = tail = (JosephuNode *)malloc(sizeof(JosephuNode); for (i = 1; i < n; +i) ( tail->index = i;tail->next = (JosephuNode *)malloc(sizeof(JosephuNode); tail = tail->next;)tail->index = i;tail->next = head;for (i = 1; tail != head; +i) (for (j = l;j<m;+j) (tail = head;head = head->next;)tail->next = head->next;printf("第4d 个出局的人是:%4d 号n, i, head->index); free(head);head = tail->next;)i = head->index;free(head);return i;)int main()(int n, m;scanf("%d%d", &n, &m);printf("最后月生利的是d 号! n", Josephu(n, m);system("pause");return 0;)斐波拉契数列递归实现的方法如下:int Funct( int n )(if(n=0) return 1;if(n=l) return 1;retrurn Funct(n-l) + Funct(n-2);)请问,如何不使用递归,来实现上述函数?请教各位高手!解答:intFunct(intn)n为非负整数(int a=0;int b=l;int c;if(n=0) c=l;else if(n=l) c=l;else for(int i=2;i<=n;i+) 应该 n 从 2 开始算起(c=a+b;a=b;b=c;)return c;)在对齐为4的情况下struct BBB long num; char *name; short int data; char ha;short ba5;)*P;p=0xl000000;p+0x200=;(Ulong)p+0x200=;(char*)p+0x200=;希望各位达人给出答案和原因,谢谢拉解答:假设在32位CPU上,sizeof(long) = 4 bytessizeof(char *) = 4 bytessizeof(short int) = sizeof(short) = 2 bytessizeof(char) = 1 bytes由于是4字节对齐,sizeof(struct BBB) = sizeof(*p)= 4 + 4 + 2 + l + 1/*补齐*/ + 2*5 + 2/*补齐*/ = 24 bytes (经 Dev-C+验证)p=0xl000000;p+0x200=;=0x1000000 + 0x200*24(Ulong)p+0x200=;=0x1000000 + 0x200(char*)p+0x200=;=0x1000000 + 0x200*4写一个函数,它的原形是 int continumax(char *outputstr,char *intputstr)功能:在字符串中找出连续最长的数字串,并把这个串的长度返回,并把这个最长数字串付给其中 一个函数参数outputstr所指内存。例如:"abcdl2345edl25ssi23456789"的首地址传给 intputstr后,函数将返回9, outputstr 所指的值为 123456789int continumax(char *outputstr; char *inputstr)(char *in = inputstr, *out = outputstr, Kemp, *final;int count = 0, maxlen = 0;while( *in != '0')(if( *in>47 &&*in<58) for(temp = in; *in > 47 && *in < 58 ; in+ ) count+;)elsein+;if( maxlen < count)(maxlen = count;count = 0;final = temp;)for(int i = 0; i < maxlen; i+)(*out = *final;out+;final+;)*out = *0'return maxlen;)不用库函数,用C语言实现将一整型数字转化为字符串 方法1:int getlen(char *s)int n;for(n = 0; *s != '0' s+)n+;return n;)void reverse(char s)(int c,i,j;for(i = 0,j = getlen(s) -1; i < j; i+J-)c = si;si = sj;sj = c;)void itoa(int n,char s) int i,sign;if(sign = n) < 0) n = -n;i = 0;do/*以反序生成数字*/si+ = n%10 + 'O'/*get next number*/while(n /= 10) > 0);/*delete the number*/if(sign < 0)si+=si = '0'reverse(s);)方法2:#include <iostream>using namespace std;void itochar(int num);void itochar(int num)(int i = 0;intj;char stra10;char strb10;while ( num )(strai+=num%10+48;num=num/10;)strai = '0'for( j=0; j < i; j+)(strbj = strai-j-l;)strbj = '0'cout«strb«endl;)int main()(int num;cin»num;itochar(num);return 0;)用指针的方法,将字符串“ABCD1234efgh”前后对调显示/include <stdio.h>#include <string.h>#include <dos.h> int main() (char str = "ABCD1234efghH;int length = strlen(str);char * pl = str;char * p2 = str + length -1;while(pl < p2)( char c = *pl; *pl = *p2; *p2 = c;+pl;-p2;)printf("str now is %sn",str);system("pause");return 0;)有一个数组a1000存放0-1000;要求每隔二个数删掉一个数,到末尾时循环至开头继续进行, 求最后一个被删掉的数的原始下标位置。方法2:链表#include<iostream> using namespace std;#define null 0 struct node (int data;node* next;); int main() (node* head=new node;head->data=O;head->next=null; node* p=head; for(int i=l;i<1000;i+) node* tmp=new node;tmp->data=i;tmp->next=null;head->next=tmp;head=head->next;)head->next=p;while(p!=p->next)(p->next->next=p->next->next->next;p=p->next->next;)cout«p->data;return 0;)试题:void test2()(char string10, strl10;int i;for(i=0; i<10; i+)(strli = 'a')strcpy( string, strl);解答:对试题2,如果面试者指出字符数组st门不能在数组内结束可以给3分;如果面试者 指出strcpy(string, strl)调用使得从strl内存起复制到string内存起所复制的字节数具有不确 定性可以给7分,在此基础上指出库函数strcpy工作方式的给10分;strl不能在数组内结束:因为strl的存储为:相,睨尸产闭睨后户,没有01字符串结束符),所以 不能结束strcpy( char *sl,char *s2)他的工作原理是,扫描s2指向的内存,逐个字符付到si所指向的 内存,直到碰到因为stH结尾没有、(T,所以具有不确定性,不知道他后面还会付什么东 东。正确应如下void test2()(char string10, strl10;int i;for(i=0; i<9; i+) strli=才+i; 把abcdefghi赋值给字符数组 )stri=VT; 加上结束符strcpy( string, strl);)分析:int arr = 6,7,8,9,10;int *ptr = arr;*(ptr+)+=123;printf( " %d %d n , *ptr, *(+ptr);输出:88过程:对于*(ptr+)+=123;先做加法6+123,然后+,指针指向7;对于printf(" %d %d ",*ptr,*(+ptr);从后往前执行,指针先+,指向8,然后输出8,紧接着再输出8已知一个单向链表的头,请写出删除其某一个结点的算法,要求,先找到此结点,然后删除。slnodetype *Delete(slnodetype *Head,int key)1=|=, if(Head->number=key)(Head=Pointer->next;free(Pointer);break;)Back = Pointer;Pointer=Pointer->next;if(Pointer->number=key)(Back->next=Pointer->next;free(Pointer);break;)void delete(Node* p)(if(Head = Node)while(p)1写出程序把一个链表中的接点顺序倒排typedef struct linknode(int data;struct linknode *next;node;将一个链表逆置node *reverse(node *head)(node *pz*q,*r;p=head;q=p->next; while(q!=NULL) ( r=q->next; q->next=p; p=q; q=r; )head->next=NULL; head=p;return head; )2写出程序删除链表中的所有接点 void del_all(node *head) ( node *p;while(head!=NULL) ( p=head->next; free(head); head=p; ) coutcv''释放空间成功! ”<<endl; )两个字符串,s,t;把t字符串插入到S字符串中,S字符串有足够的空间存放t字符串 void insert(char *s, char *t, int i) ( char *q = t; char *p =s;if(q = NULL)return;while(*p!=,0,) (P+; ) while(*q!=0) ( *p=*q;P+; q+; ) *P = '0,; )编写一个C函数,该函数在一个字符串中找到可能的最长的子字符串,且该字符串是由同 一字符组成的。char * search(char *cpSource, char ch) char *cpTemp=NULL, *cpDest=NULL;int iTemp, iCount=0;while(*cpSource) (if(*cpSource = ch)(iTemp = 0;cpTemp = cpSource;while(*cpSource = ch)+iTemp, +cpSource;if(iTemp > iCount)iCount = iTemp, cpDest = cpTemp;if(!*cpSource)break;)+cpSource;)return cpDest;)一个单向链表,不知道头节点,一个指针指向其中的一个节点,问如何删除这个指针指向的 节点?将这个指针指向的next节点值copy到本节点,将next指向next->next,并随后删除原next 指向的节点。编程实现:找出两个字符串中最大公共子字符串,如“abccade/dgcadde”的最大子串为“cad” int GetCommon(char *sl, char *s2, char *rl, char *r2) (int lenl = strlen(sl);int Ien2 = strlen(s2);int maxlen = 0;for(int i = 0; i < lenl; i+) (for(int j = 0; j < Ien2; j十十) (if(sli = s2j) int as = i, bs = j, count = 1;while(as + 1 < lenl && bs + 1 < Ien2 && sl+as = s2+bs)C+提供了 C连接交换指定符号extern “C”来解决名字匹配问题。5、请简述以下两个for循环的优缺点for (i=0; i<N; i+)if (condition)DoSomething();else DoOtherthing();)/第二个if (condition) for (i=0; i<N; i+)DoSomething();else for (i=0; i<N; i+)DoOtherthing。;优点:程序简洁缺点:多执行了 N.1次逻辑判断,并且打断了循环“流水线”作业,使得编译器不能对循环 进行优化处理,降低了效率。优点:循环的效率高 缺点:程序不简洁四、有关内存的思考题(20分)void GetMemory(char *p) p = (char *)malloc(100);)void Test(void) char *str = NULL;GetMemory(str);strcpy(sti; "hello world");printf(str);请问运行Test函数会有什么样的结果?答:程序崩溃,getmemory中的malloc不能返回动态内存,free ()对str操作很危险 博 主:getmemory中p是形参,是一个指针变量,getmemory(str)调用后,传入的是指针变量 保存的对象地址,p=(char *) malloc(lOO)实际上是把申请的动态内存空间的首地址付给p指 向的地址(即str指向的地址null),这个是错误的。应该修改成指向指针的指针void getmemory(char *p),这样malloc返回的地址付给*p (即str变量本身)。char *GetMemory(void) char p = "hello world"return p;void Test(void) char *str = NULL;str = GetMemory();printf(str);请问运行Test函数会有什么样的结果?答:可能是乱码。因为GetMemory返回的是指向“栈内存”的指针,该指针的地址不是NULL,但其原现的 内容已经被清除,新内容不可知。RetMenory执行完毕,p资源被回收,指向未知地址。返回地址,str的内容应是不可预测的, 打印的应该是str的地址Void GetMemory2(char *p, int num)count+;if(count > maxlen) maxlen = count;rl = si + i;r2 = s2+j;) ) ) ) p = (char *)malloc(num); void Test(void) char *str = NULL;GetMemory(&str, 100);strcpy(str, "hello");printf(str);请问运行Test函数会有什么样的结果?答:(1)能够输出hello(2)内存泄漏void Test(void) char *str = (char *) malloc(lOO);strcpy(str, hello);free(str);if(str != NULL)strcpy(str; "world");printf(str);请问运行Test函数会有什么样的结果?答:篡改动态内存区的内容,后果难以预料,非常危险。因为free(str);之后,str成为野指针,if(str != NULL)语句不起作用。五、 已知 strcpy 函数的原型是 char *strcpy(char *strDest, const char *strSrc);其中strDest是目的字符串,strSrc是源字符串。(1)不调用C+/C的字符串库函数,请编写函数strcpy 答:char* my_strcpy(char* strdest, const char* strsrc)(assert(strdest != NULL) && (strsrc != NULL) char* address = strdest;while(*strdest+ = *strsrc+) != NULL) return address;)(2) strcpy能把strSrc的内容复制到strDest,为什么还要char*类型的返回值? 答:为了实现链式表达式。2分例如 int length = strlen( strcpy( strDest, “hello world”);六、编写类String的构造函数、析构函数和赋值函数(25分)已知类String的原型为:class String public:String(const char *str = NULL); / 普通构造函数String(const String &other); / 拷贝构造函数-String(void);/ 析构函数String & operate =(const String &other); / 赋值函数private:char *m_data;/用于保存字符串);请编写String的上述4个函数。普通构造函数String:String(const char *str)(if(str=NULL)(m_data = new charl; /得分点:对空字符串自动申请存放结束标志、O1的 空加分点:对m_data加NULL判断*m_data = '0' else(int length = strlen(str);m_data = new charlength+l; / 若能加 NULL 判断则更好 strcpy(m_data, str);)/String的析构函数String:String(void)(delete m_data; / 或 delete m_data;)拷贝构造函数String:String(const String &other) / 得分点:输入参数为 const 型 (int length = strlen(other.m_data);m_data = new charlength+l;加分点:对 m_data 力口 NULL 判断strcpy(m_data, other.m_data);)赋值函数String & String:operate =(const String &other) / 得分点:输入参数为 const 型 (if(this = &other)得分点:检查自赋值return *this;delete m_data;得分点:释放原有的内存资源int length = strlen( other.m_data );m_data = new charlength+l;加分点:对 m_data 加 NULL 判断strcpy( m_data, other.m_data );return *this;得分点:返回本对象的引用)编写一个函数,要求输入年月日时分秒,输出该年月日时分秒的下一秒。如输入2004年12 月31日23时59分59秒,则输出2005年1月1日。时。分。秒。void ResetTheTime(int *year,int *month,int *date,int *hour,int *minute,int*second)intdayOfMonth12=31,28,31,30,31,30,31,31,30,31,30,31;if( *year < 0 11 *month < 1 11 *month > 12 11*date < 1 11 *date > 31 11 *hour < 0 11 *hour > 23 11*minute < 0 | | *minute > 59| | *second <0 11 *second >60 ) return;if( *year%400 = 0 11 *year%100 != 0 && *year%4 = 0 ) dayOfMonthl = 29;if(*second >= 60)(*second = 0;*minute += 1;if(*minute >= 60)(*minute = 0;*hour += 1;if(*hour >= 24)(*hour = 0;*date += 1;if(*date > dayOfMonth*month-l)(*date = 1;*month += 1;if(*month > 12)(*month=l;*year += 1;)return;)1 ,全局变量和局部变量在内存中是否有区别?如果有,是什么区别? 全局变量储存在静态数据库,局部变量在堆栈. static有什么用途?(请至少说明两种)1 .限制变量的作用域2.设置变量的存储域不能做switch。的参数类型是:switch的参数不能为实型。如何引用一个已经定义过的全局变量?答:extern可以用引用头文件的方式,也可以用extern关键字,如果用引用头文件方式来引用某个在 头文件中声明的全局变理,假定你将那个变写错了,那么在编译期间会报错,如果你用extern 方式引用时,假定你犯了同样的错误,那么在编译期间不会报错,而在连接期间报错 全局变量可不可以定义在可被多个.C文件包含的头文件中?为什么? 答:可以,在不同的C文件中以static形式来声明同名全局变量。可以在不同的C文件中声明同名的全局变量,前提是其中只能有一个C文件中对此变量赋 初值,此时连接不会出错char* ss = "0123456789"sizeof(ss)结果4 = = =ss是指向字符串常量的字符指针,sizeof获得的是一个指针的之 所占的空间,应该是长整型的,所以是4sizeof(*ss)结果1 = = =*ss是第一个字符其实就是获得了字符串的第一位O所占的内 存空间,是char类型的,占了 1位 请找出下面代码中的所以错误说明:以下代码是把一个字符串倒序,如“abed”倒序后变为“dcba”1> #include"string.h"2、main()3、(4、 char*src=,hello/world"5、char* dest=NULL;6、 int len=strlen(src);dest=(char*)malloc(len);7、 char* d=dest;char* s=srclen;10> while(len-!=0)d+= s-;12、printf("%s",dest);13> return 0;14、)答:方法1:int main()char* sre = "hello,world"int len = strlen(src);char* dest = (char*)malloc(len+l);要为0 分配一个空间char* d = dest;char* s = &srclen-l;指向最后一个字符while( len- != 0 )*d+=*s-;*d= '0 ;尾部要加0printf("%sn,/dest);free(dest);/使用完,应当释放空间,以免造成内存汇泄露 return 0;)方法2:/include <stdio.h>#include <string.h>main()(char str=,hello/world,;int len=strlen(str);chart;for(int i=0; i<len/2; i+)(t=stri;stri=strlen-i-l; strlen-i-l=t;)printf("%s",str);return 0;)用两个栈实现一个队列的功能?要求给出算法和思路!设2个栈为A,B, 一开始均为空.入队:将新元素push入栈A;出队:判断栈B是否为空;(2)如果不为空,则将栈A中所有元素依次pop出并push到栈B;将栈B的栈顶元素pop出;char * const p; 常量指针,p的值不可以修改char const *p; 指向常量的指针,指向的常量值不可以改const char *p; 和 char const *pmain()(inta5=l,2,3,4,5;int *ptr=(int *)(&a+l);printf("%d/%d"/*(a+l)/*(ptr-l);输出:2,5*(a+l)就是a,*(ptr-l)就是a4,执行结果是2, 5&a+l不是首地址+1,系统会认为加一个a数组的偏移,是偏移了一个数组的大小(本例是5 个 int)int *ptr=(int *)(&a+l);则 ptr 实际是&(a5),也就是 a+5原因如下:&a是数组指针,其类型为int(*)5;而指针加1要根据指针类型加上一定的值,不同类型的指针+1之后增加的大小不同a是长度为5的int数组指针,所以要加5*sizeof(int)所以ptr实际是a5但是prt与(&a+l)类型是不一样的(这点很重要)所以prt-1只会减去sizeof(int*)a,&a的地址是一样的,但意思不一样,a是数组首地址,也就是a的地址,&a是对象(数 组)首地址,a+1是数组下一元素的地址,即al,&a+l是下一个对象的地址,即a5.char* s="AAA"printf("%s",s);sO='B'printf("%s",s);有什么错?“AAA”是字符串常量。s是指针,指向这个字符串常量,所以声明s的时候就有问题。cosnt char* s="AAA"然后又因为是常量,所以对是s0的赋值操作是不合法的。int (*s10)(int)函数指针数组,每个指针指向一个int func(int param)的函数。.交换两个变量的值,不使用第三个变量。即a=3,b=5,交换之后a=5,b=3;有两种解法,一种用算术算法,一种用人(异或)a = a + b;b = a-b;a = a-b;or a = aAb;/ 只能对 int,char.b = aAb;a = aAb;3.c和C+中的struct有什么不同?c和C+中struct的主要区别是c中的struct不可以含有成员函数,而C+中的struct可以。 C+中struct和class的主要区别在于默认的存取权限不同,struct默认为public,而class默 认为 private 1: (void *)ptr和(*(void*)ptr的结果是否相同?其中ptr为同一个指针 .(void *)ptr 和(*(void*)ptr 值是相同的改错:int main(void) int *p;int arr100;p = &arr;return 0;解答:搞错了,是指针类型不同,int *p; 二级指针&arr; 得到的是指向第一维为100的数组的指针#include <stdio.h>int main(void) int *p, *q;int arr100;q = arr;P = &q;return 0;)下面这个程序执行后会有什么错误或者效果:#define MAX 255int main()unsigned char AMAX,i;/i 被定义为 unsigned charfor (i=0;i<=MAX;i+)Ai=i;解答:死循环加数组越界访问(C/C+不进行数组越界检查)MAX=255数组A的下标范围为O.MAX-1,这是其一.淇二当i循环到255时,循环内执行:A255=255;这句本身没有问题.但是返回for (i=0;i<=MAX;i+)语句时,由于unsigned char的取值范围在(0255)j+以后i又为0 了.无限循环下去.设编号为1, 2,n的n个人围坐一圈,约定编号为k (l<=k<=n)的人从1开始报数,数 到m的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直 到所有人出列为止,由此产生一个出队编号的序列。数组实现:#include <stdio.h>#include <malloc.h>int Josephu(int n, int m)(int flag, i, j = 0;int *arr = (int *)malloc(n * sizeof(int);for (i = 0; i < n; +i)arri = 1;for (i = 1; i < n; +i)(flag = 0;while