首页 养生问答 疾病百科 养生资讯 女性养生 男性养生
您的当前位置:首页正文

C软件工程师笔试题范文

2020-10-08 来源:华佗健康网
一、请填写BOOL , float, 指针变量 与“零值”比较的 if 语句。(10分) 提示:这里“零值”可以是0, 0.0 , FALSE或者“空指针”。例如 int 变量 n 与“零值”比较的 if 语句为: if ( n == 0 ) if ( n != 0 )

以此类推。请写出 BOOL flag 与“零值”比较的 if 语句:

标准答案: if ( flag ) if ( !flag )

如下写法均属不良风格,不得分。

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 ) = 4 void Func ( char str[100]) {请计算sizeof( str ) = 4} void *p = malloc( 100 ); 请计算 sizeof ( p ) = 4 三、简答题(25分)

1、头文件中的 ifndef/define/endif 干什么用? 防止该头文件被重复引用

2、#include 和 #include “filename.h” 有什么区别?

答:对于#i nclude ,编译器从标准库路径开始搜索 filename.h 对于#i nclude “filename.h” ,编译器从用户的工作路径开始搜索 filename.h

3、const 有什么用途?(请至少说明两种) 答:(1)可以定义 const 常量

(2)const可以修饰函数的参数、返回值,甚至函数的定义体。被const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。

4、在C++ 程序中调用被 C编译器编译后的函数,为什么要加 extern “C”声明?

答:C++语言支持函数重载,C语言不支持函数重载。函数被C++编译后在库中的名字与C语言的不同。假设某个函数的原型为: void foo(int x, int y);

该函数被C编译器编译后在库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字。 C++提供了C连接交换指定符号extern“C”来解决名字匹配问题。

5、请简述以下两个for循环的优缺点 for (i=0; ielse DoOtherthing(); }

// 第二个 if (condition) { for (i=0; ielse { for (i=0; iDoOtherthing();}优点:程序简洁

缺点:多执行了N-1次逻辑判断,并且打断了循环“流水线”作业,使得编译器不能对循环进行优化处理,降低了效率。优点:循环的效率高 缺点:程序不简洁

四、有关内存的思考题(20分) void GetMemory(char *p) { p = (char *)malloc(100); }

void Test(void)

{ char *str = NULL; GetMemory(str);

strcpy(str, \"hello world\"); printf(str); }

请问运行Test函数会有什么样的结果?

答:程序崩溃,getmemory中的malloc 不能返回动态内存, free()对str操作很危险 博主:getmemory中p是形参,是一个指针变量,getmemory(str)调用后,传入的是指针变量保存的对象地址,p=(char *) malloc(100)实际上是把申请的动态内存空间的首地址付给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) { 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(100); 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 char[1]; // 得分点:对空字符串自动申请存放结束标志'\\0'的空 //加分点:对m_data加NULL 判断 *m_data = '\\0'; } else

{

int length = strlen(str);

m_data = new char[length+1]; // 若能加 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 char[length+1]; //加分点:对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 char[length+1]; //加分点:对m_data加NULL 判断 strcpy( m_data, other.m_data );

return *this; //得分点:返回本对象的引用 }

编写一个函数,要求输入年月日时分秒,输出该年月日时分秒的下一秒。如输入2004年12月31日23时59分59秒,则输出2005年1月1日0时0分0秒。

void ResetTheTime(int *year,int *month,int *date,int *hour,int *minute,int*second) { int dayOfMonth[12]={31,28,31,30,31,30,31,31,30,31,30,31}; if( *year < 0 || *month < 1 || *month > 12 || *date < 1 || *date > 31 || *hour < 0 || *hour > 23 || *minute < 0 ||*minute > 59|| *second <0 || *second >60 ) return; if( *year%400 == 0 || *year%100 != 0 && *year%4 == 0 ) dayOfMonth[1] = 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-1]) { *date = 1; *month += 1; if(*month > 12) { *month=1; *year += 1; } } } } } return; }

1.全局变量和局部变量在内存中是否有区别?如果有,是什么区别? 全局变量储存在静态数据库,局部变量在堆栈

2. static有什么用途?(请至少说明两种) 1.限制变量的作用域2.设置变量的存储域

不能做switch()的参数类型是: switch的参数不能为实型。

如何引用一个已经定义过的全局变量? 答:extern

可以用引用头文件的方式,也可以用extern关键字,如果用引用头文件方式来引用某个在头文件中声明的全局变理,假定你将那个变写错了,那么在编译期间会报错,如果你用extern方式引用时,假定你犯了同样的错误,那么在编译期间不会报错,而在连接期间报错

全局变量可不可以定义在可被多个.C文件包含的头文件中?为什么? 答:可以,在不同的C文件中以static形式来声明同名全局变量。

可以在不同的C文件中声明同名的全局变量,前提是其中只能有一个C文件中对此变量赋初值,此时连接不会出错

char* ss = \"\";

sizeof(ss) 结果 4 ===》ss是指向字符串常量的字符指针,sizeof 获得的是一个指针的之所占的空间,应该是长整型的,所以是4

sizeof(*ss) 结果 1 ===》*ss是第一个字符 其实就是获得了字符串的第一位'0' 所占的内存空间,是char类型的,占了 1 位

请找出下面代码中的所以错误

说明:以下代码是把一个字符串倒序,如“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\13、 return 0; 14、} 答: 方法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\

free(dest);// 使用完,应当释放空间,以免造成内存汇泄露 return 0; }

方法2:

#include #include main() {

char str[]=\"hello,world\"; int len=strlen(str); char t;

for(int i=0; it=str[i];

str[i]=str[len-i-1]; str[len-i-1]=t; }

printf(\"%s\return 0;

}

.用两个栈实现一个队列的功能?要求给出算法和思路! 设2个栈为A,B, 一开始均为空. 入队:

将新元素push入栈A; 出队:

(1)判断栈B是否为空;

(2)如果不为空,则将栈A中所有元素依次pop出并push到栈B; (3)将栈B的栈顶元素pop出;

char * const p; //常量指针,p的值不可以修改

char const * p;//指向常量的指针,指向的常量值不可以改 const char *p; //和char const *p

main() {

int a[5]={1,2,3,4,5}; int *ptr=(int *)(&a+1);

printf(\"%d,%d\}输出: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].

char* s=\"AAA\"; printf(\"%s\s[0]='B';

printf(\"%s\有什么错?

\"AAA\"是字符串常量。s是指针,指向这个字符串常量,所以声明s的时候就有问题。 cosnt char* s=\"AAA\";

然后又因为是常量,所以对是s[0]的赋值操作是不合法的。

int (*s[10])(int) 函数指针数组,每个指针指向一个int func(int param)的函数。

.交换两个变量的值,不使用第三个变量。即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;

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 arr[100]; p = &arr; return 0;} 解答:

搞错了,是指针类型不同, int **p; //二级指针

&arr; //得到的是指向第一维为100的数组的指针 #include int main(void) { int **p, *q; int arr[100]; q = arr; p = &q; return 0; }

下面这个程序执行后会有什么错误或者效果: #define MAX 255 int main()

{unsigned char A[MAX],i;//i被定义为unsigned char 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++)语句时,

由于unsigned char的取值范围在(0..255),i++以后i又为0了..无限循环下去.

设编号为1,2,… n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m 的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。

数组实现:

#include #include

int Josephu(int n, int m) {

int flag, i, j = 0;

int *arr = (int *)malloc(n * sizeof(int)); for (i = 0; i < n; ++i) arr[i] = 1;

for (i = 1; i < n; ++i) {

flag = 0;

while (flag < m) {

if (j == n) j = 0;

if (arr[j]) ++flag; ++j; }

arr[j - 1] = 0;

printf(\"第%4d个出局的人是:%4d号\\n\}

free(arr); return j; }

int main() {

int n, m;

scanf(\"%d%d\

printf(\"最后胜利的是%d号!\\n\system(\"pause\"); return 0; }

链表实现:

#include #include 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 = 1; j < m; ++j) {

tail = head;

head = head->next; }

tail->next = head->next;

printf(\"第%4d个出局的人是:%4d号\\n\free(head);

head = tail->next; }

i = head->index; free(head); return i; }

int main() {

int n, m;

scanf(\"%d%d\

printf(\"最后胜利的是%d号!\\n\system(\"pause\"); return 0; }

斐波拉契数列递归实现的方法如下: int Funct( int n ) {

if(n==0) return 1; if(n==1) return 1;

retrurn Funct(n-1) + Funct(n-2); }

请问,如何不使用递归,来实现上述函数? 请教各位高手!

解答:int Funct( int n ) // n 为非负整数 {

int a=0; int b=1; int c;

if(n==0) c=1;

else if(n==1) c=1;

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 ba[5]; }*p; p=0x;

p+0x200=____;

(Ulong)p+0x200=____; (char*)p+0x200=____;

希望各位达人给出答案和原因,谢谢拉 解答:假设在32位CPU上, sizeof(long) = 4 bytes sizeof(char *) = 4 bytes

sizeof(short int) = sizeof(short) = 2 bytes sizeof(char) = 1 bytes

由于是4字节对齐,

sizeof(struct BBB) = sizeof(*p)

= 4 + 4 + 2 + 1 + 1/*补齐*/ + 2*5 + 2/*补齐*/ = 24 bytes (经Dev-C++验证)

p=0x;

p+0x200=____; = 0x + 0x200*24

(Ulong)p+0x200=____; = 0x + 0x200

(char*)p+0x200=____; = 0x + 0x200*4

写一个函数,它的原形是int continumax(char *outputstr,char *intputstr) 功能:

在字符串中找出连续最长的数字串,并把这个串的长度返回,并把这个最长数字串付给其中一个函数参数outputstr所指内存。例如:\"abcd12345ed125ss\"的首地址传给intputstr后,函数将返回 9,outputstr所指的值为

int continumax(char *outputstr, char *inputstr) {

char *in = inputstr, *out = outputstr, *temp, *final; int count = 0, maxlen = 0;

while( *in != '\\0' ) {

if( *in > 47 && *in < 58 ) {

for(temp = in; *in > 47 && *in < 58 ; in++ ) count++;

} else in++;

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 = s[i]; s[i] = s[j]; s[j] = c; } }

void itoa(int n,char s[]) {

int i,sign;

if((sign = n) < 0) n = -n; i = 0;

do{/*以反序生成数字*/

s[i++] = n%10 + '0';/*get next number*/ }while((n /= 10) > 0);/*delete the number*/

if(sign < 0) s[i++] = '-';

s[i] = '\\0'; reverse(s); }

方法2:

#include using namespace std;

void itochar(int num);

void itochar(int num) {

int i = 0; int j ;

char stra[10]; char strb[10]; while ( num ) {

stra[i++]=num%10+48; num=num/10; }

stra[i] = '\\0';

for( j=0; j < i; j++) {

strb[j] = stra[i-j-1]; }

strb[j] = '\\0'; cout<int main() {

int num; cin>>num; itochar(num); return 0; }

用指针的方法,将字符串“ABCD1234efgh”前后对调显示 #include #include #include int main() {

char str[] = \"ABCD1234efgh\"; int length = strlen(str); char * p1 = str;

char * p2 = str + length - 1; while(p1 < p2)

{

char c = *p1; *p1 = *p2; *p2 = c; ++p1; --p2; }

printf(\"str now is %s\\n\system(\"pause\"); return 0; }

有一个数组a[1000]存放0--1000;要求每隔二个数删掉一个数,到末尾时循环至开头继续进行,求最后一个被删掉的数的原始下标位置。 方法2:链表

#include using namespace std; #define null 0 struct node {

int data; node* next; };

int main() {

node* head=new node; head->data=0; head->next=null; node* p=head;

for(int i=1;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<data; return 0; }

试题:

void test2() {

char string[10], str1[10]; int i;

for(i=0; i<10; i++) {

str1[i] = 'a'; }

strcpy( string, str1 ); }

解答:对试题2,如果面试者指出字符数组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',所以具有不确定性,不知道他后面还会付什么东东。 正确应如下 void test2() {

char string[10], str1[10]; int i;

for(i=0; i<9; i++) {

str1[i] = 'a'+i; //把abcdefghi赋值给字符数组 }

str[i]='\\0';//加上结束符 strcpy( string, str1 ); }

分析:

int arr[] = {6,7,8,9,10}; int *ptr = arr; *(ptr++)+=123;

printf(“ %d %d ”, *ptr, *(++ptr)); 输出:8 8 过程:对于*(ptr++)+=123;先做加法6+123,然后++,指针指向7;对于printf(“ %d %d ”, *ptr, *(++ptr));从后往前执行,指针先++,指向8,然后输出8,紧接着再输出8

已知一个单向链表的头,请写出删除其某一个结点的算法,要求,先找到此结点,然后删除。 slnodetype *Delete(slnodetype *Head,int key){}中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 *p,*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; }

cout<<\"释放空间成功!\"<两个字符串,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\的最大子串为\"cad\" int GetCommon(char *s1, char *s2, char **r1, char **r2) {

int len1 = strlen(s1); int len2 = strlen(s2); int maxlen = 0;

for(int i = 0; i < len1; i++) {

for(int j = 0; j < len2; j++) {

if(s1[i] == s2[j]) {

int as = i, bs = j, count = 1;

while(as + 1 < len1 && bs + 1 < len2 && s1[++as] == s2[++bs]) count++;

if(count > maxlen) {

maxlen = count; *r1 = s1 + i; *r2 = s2 + j; } } } }

free

因篇幅问题不能全部显示,请点此查看更多更全内容