C/C++面试题(三)

1、设置地址为 0x67a9 的整型变量的值为 0xaa66

int *ptr;
ptr = (int *)0x67a9;
*ptr = 0xaa66;
说明:这道题就是强制类型转换的典型例子,无论在什么平台地址长度和整型数据的长度是一样的,
即一个整型数据可以强制转换成地址指针类型,只要有意义即可。

2、 面向对象的三大特征

面向对象的三大特征是封装性、继承性和多态性:

 封装性:将客观事物抽象成类,每个类对自身的数据和方法实行 protection( private, protected,public)。

 继承性:广义的继承有三种实现形式: 实现继承( 使用基类的属性和方法而无需额外编码的能力)、可视继承(子窗体使用父窗体的外观和实现代码)、接口继承(仅使用属性和方法,实现滞后到子类实现)。

多态性:是将父类对象设置成为和一个或更多它的子对象相等的技术。用子类对象给父类对象赋值之后,父类对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。

说明:面向对象的三个特征是实现面向对象技术的关键,每一个特征的相关技术都非常的复杂,程序员应该多看、多练。

 

3、 C++的空类有哪些成员函数

(1)缺省构造函数。

(2)缺省拷贝构造函数。

(3)缺省析构函数。

(4)缺省赋值运算符。

(5)缺省取址运算符。

(6)缺省取址运算符const。

注意:有些书上只是简单的介绍了前四个函数。没有提及后面这两个函数。但后面这两个函数也是空类的默认函数。另外需要注意的是,只有当实际使用这些函数的时候,编译器才会去定义它们

 

4、 谈谈你对拷贝构造函数和赋值运算符的认识

拷贝构造函数和赋值运算符重载有以下两个不同之处:

(1)拷贝构造函数生成新的类对象,而赋值运算符不能。

(2)由于拷贝构造函数是直接构造一个新的类对象,所以在初始化这个对象之前不用检验源对象是否和新建对象相同。而赋值运算符则需要这个操作,另外赋值运算中如果原来的对象中有内存分配要先把内存释放掉。

注意:当类中有指针类型的成员变量时,一定要重写拷贝构造函数和赋值运算符,不要使用默认的。

 

5、 用 C++设计一个不能被继承的类

  template <typename T> class A  
      {  
             friend T;  
      private:  
             A() {}  
             ~A() {}  
      };  
        
      class B : virtual public A<B>  
      {  
      public:  
             B() {}  
             ~B() {}  
      };  
      class C : virtual public B  
      {  
      public:  
             C() {}  
             ~C() {}  
      };  
      void main( void )  
      {  
             B b;  
             //C c;  
             return;  
      }  

注意:构造函数是继承实现的关键,每次子类对象构造时,首先调用的是父类的构造函数,然后才是自己的。

6、访问基类的私有虚函数

写出以下程序的输出结果:

 #include <iostream.h>  
 class A  

 {  
               virtual void g()  
               {  
                      cout << "A::g" << endl;  
               }  
        private:  
               virtual void f()  
               {  
                      cout << "A::f" << endl;  
               }  
       };  
       class B : public A  
       {  
               void g()  
               {  
                      cout << "B::g" << endl;  
               }  
               virtual void h()  
               {  
                      cout << "B::h" << endl;  
               }  
       };  
       typedef void( *Fun )( void );  
       void main()  
       {  
               B b;  
               Fun pFun;  
               for(int i = 0 ; i < 3; i++)  
               {  
                      pFun = ( Fun )*( ( int* ) * ( int* )( &b ) + i );  
                      pFun();  
               }        
       }
输出结果:
B::g
A::f
B::h
注意:本题主要考察了面试者对虚函数的理解程度。一个对虚函数不了解的人很难正确的做出本题。
在学习面向对象的多态性时一定要深刻理解虚函数表的工作原理。
7、简述类成员函数的重写、重载和隐藏的区别
 (1)重写和重载主要有以下几点不同。  
范围的区别:被重写的和重写的函数在两个类中,而重载和被重载的函数在同一个类中。  
参数的区别:被重写函数和重写函数的参数列表一定相同,而被重载函数和重载函数的参数列表一 定不同。  
virtual的区别:重写的基类中被重写的函数必须要有virtual 修饰,而重载函数和被重载函数可以被 virtual 修饰,也可以没有。  
(2 )隐藏和重写、重载有以下几点不同。  
与重载的范围不同:和重写一样,隐藏函数和被隐藏函数不在同一个类中。  
参数的区别:隐藏函数和被隐藏的函数的参数列表可以相同,也可不同,但是函数名肯定要相同。 
当参数不相同时,无论基类中的参数是否被virtual 修饰,基类的函数都是被隐藏,而不是被重写。  
说明:虽然重载和覆盖都是实现多态的基础,但是两者实现的技术完全不相同,达到的目的也是完 
全不同的,覆盖是动态态绑定的多态,而重载是静态绑定的多态。  
8、简述多态实现的原理
编译器发现一个类中有虚函数, 便会立即为此类生成虚函数表 vtable。 虚函数表的各表项为指向对
应虚函数的指针。编译器还会在此类中隐含插入一个指针 vptr(对 vc 编译器来说,它插在类的第一个位
置上) 指向虚函数表。 调用此类的构造函数时,在类的构造函数中,编译器会隐含执行 vptr 与 vtable 的
关联代码,将 vptr 指向对应的 vtable, 将类与此类的 vtable 联系了起来。 另外在调用类的构造函数时,
指向基础类的指针此时已经变成指向具体的类的 this 指针,这样依靠此 this 指针即可得到正确的 vtable,。
如此才能真正与函数体进行连接,这就是动态联编,实现多态的基本原理。
注意:一定要区分虚函数,纯虚函数、虚拟继承的关系和区别。牢记虚函数实现原理,因为多态
C++面试的重要考点之一,而虚函数是实现多态的基础。

9、链表和数组有什么区别
数组和链表有以下几点不同:
( 1)存储形式: 数组是一块连续的空间,声明时就要确定长度。 链表是一块可不连续的动态空间,
长度可变,每个结点要保存相邻结点指针。
( 2)数据查找: 数组的线性查找速度快, 查找操作直接使用偏移地址。 链表需要按顺序检索结点,
效率低。
( 3)数据插入或删除: 链表可以快速插入和删除结点, 而数组则可能需要大量数据移动。
( 4)越界问题: 链表不存在越界问题,数组有越界问题。
说明:在选择数组或链表数据结构时,一定要根据实际需要进行选择。数组便于查询,链表便于插
入删除。数组节省空间但是长度固定,链表虽然变长但是占了更多的存储空间。

10、怎样把一个单链表反序
( 1) 反转一个链表。循环算法。
List reverse(List n)
{
if(!n) //判断链表是否为空,为空即退出。
{
return n;
}
list cur = n.next; //保存头结点的下个结点
list pre = n; //保存头结点
list tmp;

pre.next = null; //头结点的指针指空,转换后变尾结点
while ( NULL != cur.next ) //循环直到cur.next为空
{
tmp = cur; //实现如图 10.3—图 10.5 所示
tmp.next = pre
pre = tmp;
cur = cur.next;
}
return tmp; //f 返回头指针
}
( 2) 反转一个链表。递归算法。
List *reverse( List *oldList, List *newHead = NULL )
{
List *next = oldList-> next; //记录上次翻转后的链表
oldList-> next = newHead; //将当前结点插入到翻转后链表的开头
newHead = oldList; //递归处理剩余的链表
return ( next==NULL )? newHead: reverse( t, newHead );
}
说明: 循环算法就是图 10.2—图 10.5 的移动过程,比较好理解和想到。递归算法的设计虽有一点难
度,但是理解了循环算法,再设计递归算法就简单多了。
11、用户输入M,N值,从1至N开始顺序循环数数,每数到M输出该数值,直至全部输出。写出C程序。循环链表,用取余操作做(感觉类似下面的题目)

课程设计题三约瑟夫(Joseph)环 
设计目的:

1.掌握单向循环链表的建立。

2.掌握单向循环链表的操作。

设计内容
  编号是1,2,……,n的n个人按照顺时针方向围坐一圈,每个人只有一个密码(正整数)。一开始任选一个正整数作为报数上限值m,从第一个人开始顺时针方向自1开始顺序报数,报到m时停止报数。报m的人出列,将他的密码作为新的m值,从他在顺时针方向的下一个人开始重新从1报数,如此下去,直到所有人全部出列为止。请设计一个程序求出出列顺序。
设计要求

1.利用单向循环链表存储结构模拟此过程,按照出列的顺序输出各个人的编号。

2.测试数据:m的初值为20,n=7,7个人的密码依次为3,1,7,2,4,7,4,首先m=6,则正确的输出是什么?

3.输入数据:建立输入函数处理输入的数据,输入m的初值n,输入每个人的密码,建立单向循环链表。

4.输出形式:建立一个输出函数,将正确的出列顺序输出。

// 约瑟夫环.cpp : Defines the entry point for the console application.
#include "stdafx.h"
#include "iostream.h"
#include "stdlib.h"
//定义数据类型
typedef struct Joseph
{
int name;//链表中人员的姓名编号
int password;//手中持有的密码
int Length;//链表的长度
struct Joseph *next;//结点指针域

}Joseph,*LinkJoseph;
typedef struct 
{
LinkJoseph front;
LinkJoseph rear;
}LinkList;
//初始化单向循环链表
void InitList(LinkList &L)
{
LinkJoseph J=new Joseph;//构造头结点
L.front=L.rear=J;//都指向头结点
J->next=NULL;//指针域置空
J->name=-1;
J->password=-1;
J->Length=0;
}
//输入姓名和密码使其形成一个环
void InList(LinkList &L)
{
int n;
cout<<"请输入总人数n=";
cin>>n;             
cout<<endl;  
for(int i=1;i<=n;i++)
{
LinkJoseph p=new Joseph;//构建新结点
L.front->Length++;//表长自加
cout<<"请输入第"<<i<<"个人的姓名编号: ";
if(i<=0)
{
cout<<"请输入一个正整数i!"<<endl;
exit(0);
}
cin>>p->name;
//printf("\b");
cout<<"请输入第"<<i<<"个人的密码: ";
if(i<=0)
{
cout<<"请输入一个正整数i!"<<endl;
exit(0);
}
cin>>p->password;
if(L.front->Length<n)
{
p->next=NULL;//新结点的指针域置空
L.rear->next=p;//将新结点插入到表尾
L.rear=p;//更改尾指针
}
else//判断生成的节点是否是第n个
{
p->next=L.front->next;//若是最后一个人,则使其指向第一个人,形成单向循环链表
L.rear->next=p;//将新结点插入到表尾
L.rear=p;//尾指针指向最后一个人
}
cout<<endl;
}
cout<<"链表的长度为 "<<L.front->Length<<endl;
}


//打印链表中的人员信息
void Print(LinkList &L)
{
cout<<endl;
int m=L.front->Length;//保存链表的长度
L.front=L.front->next;//使头指针指向第一个结点
for(int i=1;i<=m;i++)
{
cout<<"第"<<i<<"个人员的姓名编号为:"<<L.front->name<<"    "<<"密码为:"
<<L.front->password<<"    "<<"地址为: "<<L.front<<endl;
L.front=L.front->next;//循环结束,头指针指向第一个结点
}
L.front->Length=m;
//cout<<L.front<<endl;
//cout<<L.rear->next<<endl;
}
//实现出列规则
int DeList(LinkList &L)
{
int b=L.front->Length;//保存链表的长度
int m;//定义作为密码的正整数
int n=0;//保存待删除的人员顺序
cout<<endl<<"请输入初始作为密码的正整数: m=";
cin>>m;
if(m<=0)
{
cout<<"请输入一个正整数m!"<<endl;
exit(0);
}
cout<<endl;
LinkJoseph d=new Joseph;//再构建一个结点保存待删除的人员
while(b>0)
{
int s=1;//计数器
if(m==1)
{
d=L.front;//保存待删除的人员
m=d->password;
cout<<"第"<<++n<<"个出链表的人员的编号为: "<<d->name<<"   "
<<"密码为: "<<d->password<<"   "<<"地址为: "<<d<<endl;
L.rear->next=d->next;//修改结点指针
L.front=d->next;
b--;//表长自减
delete d;//释放地址空间
}
else
{
while(s<m-1)
{
L.front=L.front->next;
s++;
}
d=L.front->next;//保存待删除的人员
m=d->password;
cout<<"第"<<++n<<"个出链表的人员的编号为: "<<d->name<<"   "
<<"密码为: "<<d->password<<"   "<<"地址为: "<<d<<endl;
L.front->next=d->next;//修改结点指针
L.front=d->next;
b--;//表长自减
delete d;//释放地址空间
}
}
return 0;
}
int main(int argc, char* argv[])
{
LinkList L;//定义结点指针函数
InitList(L);//初始化头结点函数
InList(L);//生成单向循环链表
Print(L);//打印链表中的人员信息
DeList(L);//依规则删除人员
return 0;
}
12、int A[nSize],其中隐藏着若干0,其余非0整数,写一个函数int Func(int* A, int nSize),使A把0移至后面,非0整数移至数组前面并保持有序,返回值为原数据中第一个元素为0的下标。(尽可能不使用辅助空间且考虑效率及异常问题,注释规范且给出设计思路)

13、 

写一个程序, 要求功能:求出用1,2,5这三个数不同个数组合的和为100的组合个数。

 

如:100个1是一个组合,5个1加19个5是一个组合。。。。 请用C++语言写。

答案:最容易想到的算法是:

设x是1的个数,y是2的个数,z是5的个数,number是组合数

注意到0<=x<=100,0<=y<=50,0<=z=20,所以可以编程为:

number=0;

for (x=0;x<=100; x++)

for (y=0; y<=50;y++)

for (z=0; z<=20;z++)

if((x+2*y+5*z)==100)

number++;

cout<<number<<endl;

上面这个程序一共要循环100*50*20次,效率实在是太低了

事实上,这个题目是一道明显的数学问题,而不是单纯的编程问题。我的解法如下:

因为x+2y+5z=100

所以x+2y=100-5z,且z<=20 x<=100 y<=50

所以(x+2y)<=100,且(x+5z)是偶数

对z作循环,求x的可能值如下:

 

z=0, x=100, 98, 96,... 0

z=1, x=95, 93, ...,1

z=2, x=90, 88, ...,0

z=3, x=85, 83, ...,1

z=4, x=80, 78, ...,0

......

z=19, x=5, 3, 1

z=20, x=0

 

因此,组合总数为100以内的偶数+95以内的奇数+90以内的偶数+...+5以内的奇数+1,

即为:(51+48)+(46+43)+(41+38)+(36+33)+(31+28)+(26+23)+(21+18)+(16+13)+(11+8)+(6+3)+1

某个偶数m以内的偶数个数(包括0)可以表示为m/2+1=(m+2)/2

某个奇数m以内的奇数个数也可以表示为(m+2)/2

所以,求总的组合次数可以编程为:

number=0;

for (intm=0;m<=100;m+=5)

{

number+=(m+2)/2;

}

cout<<number<<endl;

这个程序,只需要循环21次, 两个变量,就可以得到答案,比上面的那个程序高效了许多

倍----只是因为作了一些简单的数学分析

 

这再一次证明了:计算机程序=数据结构+算法,而且算法是程序的灵魂,对任何工程问

题,当用软件来实现时,必须选取满足当前的资源限制,用户需求限制,开发时间限制等种

种限制条件下的最优算法。而绝不能一拿到手,就立刻用最容易想到的算法编出一个程序了

事——这不是一个专业的研发人员的行为。

那么,那种最容易想到的算法就完全没有用吗?不,这种算法正好可以用来验证新算法

的正确性,在调试阶段,这非常有用。在很多大公司,例如微软,都采用了这种方法:在调

试阶段,对一些重要的需要好的算法来实现的程序,而这种好的算法又比较复杂时,同时用

容易想到的算法来验证这段程序,如果两种算法得出的结果不一致(而最容易想到的算法保

证是正确的),那么说明优化的算法出了问题,需要修改。

可以举例表示为:

#ifdef DEBUG

int simple();

#end if

int optimize();

......

in a function:

{

result=optimize();

ASSERT(result==simple());

}

这样,在调试阶段,如果简单算法和优化算法的结果不一致,就会打出断言。同时,在程

序的发布版本,却不会包含笨重的simple()函数。——任何大型工程软件都需要预先设计良

好的调试手段,而这里提到的就是一种有用的方法。

一个学生的信息是:姓名,学号,性别,年龄等信息,用一个链表,把这些学生信息连在一起,给出一个age, 在些链表中删除学生年龄等于age的学生信息。

#include"stdio.h"

#include"conio.h"

 

struct stu{

char name[20];

char sex;

int no;

int age;

struct stu * next;

}*linklist;

struct stu*creatlist(int n)

{

int i;

//h为头结点,p为前一结点,s为当前结点

struct stu*h,*p,*s;

h = (struct stu*)malloc(sizeof(struct stu));

h->next = NULL;

p=h;

for(i=0;i<n;i++)

{

s = (struct stu*)malloc(sizeof(struct stu));

p->next = s;

printf("Pleaseinput the information of the student: name sex no age \n");

scanf("%s %c%d %d",s->name,&s->sex,&s->no,&s->age);

s->next = NULL;

p = s;

}

printf("Createsuccessful!");

return(h);

}

voiddeletelist(struct stu *s,int a)

{

struct stu *p;

while(s->age!=a)

{

p = s;

s = s->next;

}

if(s==NULL)

printf("Therecord is not exist.");

else

{

p->next =s->next;

printf("Deletesuccessful!");

}

}

void display(structstu *s)

{

s = s->next;

while(s!=NULL)

{

printf("%s %c%d %d\n",s->name,s->sex,s->no,s->age);

s = s->next;

}

}

int main()

{

struct stu *s;

int n,age;

printf("Pleaseinput the length of seqlist:\n");

scanf("%d",&n);

s = creatlist(n);

display(s);

printf("Pleaseinput the age:\n");

scanf("%d",&age);

deletelist(s,age);

display(s);

return 0;

}

14、实现一个函数,把一个字符串中的字符从小写转为大写。

#include"stdio.h"

#include"conio.h"

void uppers(char *s,char*us)

{

for(;*s!='\0';s++,us++)

{

if(*s>='a'&&*s<='z')

*us = *s-32;

else

*us = *s;

}

*us = '\0';

}

int main()

{

char *s,*us;

char ss[20];

printf("Pleaseinput a string:\n");

scanf("%s",ss);

s = ss;

uppers(s,us);

printf("Theresult is:\n%s\n",us);

getch();

}

15、随机输入一个数,判断它是不是对称数(回文数)(如3,121,12321,45254)。不能用字符串库函数 

1.

函数名称:Symmetry

功能: 判断一个数时候为回文数(121,35653)

输入: 长整型的数

输出: 若为回文数返回值为1esle 0

******************************************************************/

unsigned charSymmetry (long n)

{

long i,temp;

i=n; temp=0;

while(i) //不用出现长度问题,将数按高低位掉换

{

temp=temp*10+i%10;

i/=10;

}

return(temp==n);

}

方法一

/*---------------------------------------------------------------------------

功能:

判断字符串是否为回文数字

实现:

先将字符串转换为正整数,再将正整数逆序组合为新的正整数,两数相同则为回文数字

输入:

char *s:待判断的字符串

输出:

返回:

0:正确;1:待判断的字符串为空;2:待判断的字符串不为数字;

3:字符串不为回文数字;4:待判断的字符串溢出

----------------------------------------------------------------------------*/

unsignedIsSymmetry(char *s)

{

char *p = s;

long nNumber = 0;

long n = 0;

long nTemp = 0;

/*判断输入是否为空*/

if (*s == \'\\0\')

return 1;

/*将字符串转换为正整数*/

while (*p !=\'\\0\')

{

/*判断字符是否为数字*/

if (*p<\'0\' ||*p>\'9\')

return 2;

/*判断正整数是否溢出*/

if ((*p-\'0\') >(4294967295-(nNumber*10)))

return 4;

nNumber =(*p-\'0\') + (nNumber * 10);

p++;

}

/*将数字逆序组合,直接抄楼上高手的代码,莫怪,呵呵*/

n = nNumber;

while(n)

{

/*判断正整数是否溢出*/

if ((n%10) >(4294967295-(nTemp*10)))

return 3;

nTemp = nTemp*10 +n%10;

n /= 10;

}

/*比较逆序数和原序数是否相等*/

if (nNumber !=nTemp)

return 3;

return 0;

}

方法二

/*---------------------------------------------------------------------------

功能:

判断字符串是否为回文数字

实现:

先得到字符串的长度,再依次比较字符串的对应位字符是否相同

输入:

char *s:待判断的字符串

输出:

返回:

0:正确;1:待判断的字符串为空;2:待判断的字符串不为数字;

3:字符串不为回文数字

----------------------------------------------------------------------------*/

unsignedIsSymmetry_2(char *s)

{

char *p = s;

int nLen = 0;

int i = 0;

/*判断输入是否为空*/

if (*s == \'\\0\')

return 1;

/*得到字符串长度*/

while (*p !=\'\\0\')

{

/*判断字符是否为数字*/

if (*p<\'0\' ||*p>\'9\')

return 2;

nLen++;

p++;

}

/*长度不为奇数,不为回文数字*/

if (nLen%2 == 0)

return 4;

/*长度为1,即为回文数字*/

if (nLen == 1)

return 0;

/*依次比较对应字符是否相同*/

p = s;

i = nLen/2 - 1;

while (i)

{

if (*(p+i) !=*(p+nLen-i-1))

return 3;


i--;

}

return 0;

16、求2~2000的所有素数.有足够的内存,要求尽量快

答案:

intfindvalue[2000]={2};

static int find=1;

bool adjust(intvalue)

{

assert(value>=2);

if(value==2) returntrue;

for(inti=0;i<=find;i++)

{

if(value%findvalue[i]==0)

return false;

}

findvalue[find++];

return true;

}

 17、A,B,C,D四个进程,A向buf里面写数据,B,C,D向buf里面读数据,当A写完,且B,C,D都读一次后,A才能再写。用P,V操作实现。


18、将单向链表reverse,如ABCD变成DCBA,只能搜索链表一次。


19、将二叉树的两个孩子换位置,即左变右,右变左。不能用递规(变态!)


20、

1。大意如下:38头牛中选出3头跑得最快的,使用一个每次只能供6头比赛的场地,要求用最快的方法。(我给一个最傻瓜的答案,因为我发现一起笔试的有且恰好有38个人,不知道**什么意思?)

2。大意如下:公司职员知道老板的年龄,不知道他女儿的年龄,老板3个女儿的年龄相加为13,相乘为老板年龄,且只有一个女儿的年龄大于5岁,求这4个的年龄?(网上有一大堆答案!)

3。原题是2002年以前的一道大学生数学建模竞赛的题,是说一个学生冒雨从宿舍去食堂吃饭,200米的距离内,问是走着少淋雨还是跑着少?(该题简化了大部分的假设,只剩下一点点问题要你解决,做着没劲!)


21、网球中心共有100个网球场,每个单位可以来申请1到100的场地,申请的场地编号必须是连续的,如果场地已经被其他单位占用,就不能再次使用,而且单位在使用完场地后必须归还。请设计一个完整的系统(c语言)。(限时5分钟)

Tennis.h

struct TennisGround

{

int num;

char *agentName;

};

typedef structTennisGround TG;

void mallocTG(TG*total);

void freeTG(TG*total);

 

Tennis.c

#include<stdio.h>

#include<stdlib.h>

#include<malloc.h>

#include<string.h> 

#include"Tennis.h"

void mallocTG(TG*total)

{

int size,start,count = 0;

char *agentName =(char*)malloc(sizeof(char)*10);

printf("Pleaseinput your agentName:");

scanf("%s",agentName);

printf("Pleaseinput the size of the TennisGround:");

scanf("%d",&size);

printf("Pleaseinput the TennisGround number you want to start:");

scanf("%d",&start);

if((total+start)->agentName!= " ")

{

printf("mallocfailed!\n");

exit(-1);

}

else

{

while(count <size)

{

(total+start+count)->agentName= agentName;

count++;

}

}

}

void freeTG(TG*total)

{

char *an =(char*)malloc(sizeof(char)*10);

printf("pleaseinput agentName you want to free:");

scanf("%s",an);

int count = 0;

while(count <100)

{

if(strcmp((total+count)->agentName,an) == 0)

(total+count)->agentName= " ";

count++;

}

}

int main()

{

int i;

int sw;

TG *total =(TG*)malloc(sizeof(TG)*100);

for(i=0; i<100;i++)

{

(total+i)->num =i;

(total+i)->agentName= " ";

}

while(1)

{

printf("*******TennisGround Mallocation******************\n");

for(i=0; i<100;i++)

{

printf("%d(%s)", (total+i)->num, (total+i)->agentName);

if(i%5 == 0)

printf("\n");

}

printf("\n");

printf("**************************************************\n");

printf("Pleaseinput your choosen:(1-malloc,2-free):");

scanf("%d",&sw);

if(sw == 1)

mallocTG(total);

else

freeTG(total);

}

return 0;

}

22、

1、A1,A2....An和B交换资源,求写出PV操作的序列

2、非递归实现斐波那契数列

3、折半查找干啥用的?实现之.

4、实现有序链表上的插入


23、

1.printf的输出问题

printf("%d",total);//thisis right
printf(total);//this is wrong
printf("hello");//but this is right

2.整数类型的长度
char 1个子节,8位

unsigned short[int]
[signed] short int 
short 2个字节,16位

[signed] int 
unsigned int 
int 型在vc里是4个子节,32位,也可能是16位,2个字节

long [int]
unsigned long [int]

long型都是32位,4个字节

float 32 ,4

double 64,8

long double 128,16

char 8,一个字节,存放的实际上是字符的ascii码

3、找出错误并改正

char *my_cpy(char*src, int len){
char dest[1024];
memcpy(dest, src, len);
return dest;
}
上面的函数是否有问题,如果有指出其所在,如果没有,给出函数功能描述。

答案:
1。数组应该初始化
2。memcpy不判断是否越界,所以调用前应该判断是否越界
3。不应该返回rest,因为这个数组是在函数内部申请的,所以函数结束之后就会消失,指针也会变成“野指针”,所以指向非法地址
最后一个比较隐蔽

char *memcpy( char*dest, const char *src,int len )
{
char* pDest = (char*)dest;
char* pSrc = (char*)src;
int pos;
for(pos=0;pos<len;pos++)
{
pDest[pos] = pSrc[pos];
}
return (char*)pDest;
}

存在地问题就是没有判断指针是否非法assert(dest !=NULL || src != NULL); 条件为FLASE 显示

不调用其他函数,写一个memcpy的函数,函数原型为
void *memcpy(void *dest, void *src, size_t length);

-----------利用好断言---------

/* memcpy ─── 拷贝不重叠的内存块 */
void memcpy(void* pvTo, void* pvFrom, size_t size)
{
void* pbTo = (byte*)pvTo;
void* pbFrom = (byte*)pvFrom;
ASSERT(pvTo != NULL && pvFrom != NULL);
/* 内存块重叠吗?如果重叠,就使用memmove */
ASSERT(pbTo>=pbFrom+size || pbFrom>=pbTo+size);
while(size-->0)
*pbTo++ == *pbFrom++;
return(pvTo);
}

-----------------------

常见函数编程: 
char *strcpy(char *strDest, const char *strSrc) 

ASSERT(strDest != NULL && strSrc != NULL); 
char *addr = strDest; 
while(*strDest++=*strSrc++)
NULL; //NULL可以省略,但更有利于编译器发现错误

return addr; 


void *memcpy(void *dest, const void *src, int count) 

ASSERT(dest!= NULL && src!= NULL); 
for(int i=0; i< cout; i++) 

dest = src; 


int strcmp(const char*str1, const char *str2) 

while (str1 != NULL && str2 != NULL) 

if(*str1 < *str2) return -1; 
else if(*str1 > *str2) return 1; 
else { str1++; str2++;} 

if(str1 == NULL && str2 != NULL) 
return -1; 
else if(str1 != NULL && str2 == NULL) 
return 1; 
else return 0; 


//way2: more compact 
int strcmp(const char*str1, const char *str2) 

int i = strlen( str1 ); 
int j; 
for(j=0; j<=i; j++) 

if(str1[j] > str2[j]) return 1; //if str2 terminates, then str2[j]=0,str1[j]>str2[j], return 1;
else if(str1[j] < str2[j]) return -1; 
else if(str1[j] == '') return 0; 


//way3: optimize again. 
int strcmp(const char * str1, const char * str2 ) 

while(1) 

if(*str1 > *str2) return 1; 
else if(*str1 < *str2) return -1; 
else if(*str1 == '') return 0; 
str1++;str2++; 

}

 

 

 

 

 

 

 

一道华为笔试题

题目:请在小于99999的正整数中找符合下列条件的数,它既是完全平方数,又有两位数字相同,如:144,676。用c语言编写(不能用数字转换成字符串)。

#include<stdio.h>
#include<math.h>
//函数havesamenum确认num是否满足条件
int havesamenum(int num)
{
 int i=0,j;
 char a[10] = {0};
 
 while(num>0)
 {
  j=num%10;
  a[j]+=1;
  num=num/10;
 }
 while(a[i]<=1&&i<10)
  i++;
 if (i<10) 
  return 1;
 else 
  return 0;
}
void main(void)
{
   int i,j,m;
 
 m=(int)sqrt(99999);
 for(i=1;i<m;i++)
 {
     j=i*i;
     if (1==havesamenum(j))

    printf("%6d\t",j);
 }
}

       下图为运行结果:

 

慧通试题

1 写出程序把一个链表中的接点顺序倒排

typedef structlinknode

{

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<<"释放空间成功!"<<endl;

}

3两个字符串,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';

}

 

 

分析下面的代码:

char *a ="hello";

char *b ="hello";

if(a= =b)

printf("YES");

else

printf("NO");

这个简单的面试题目,我选输出 no(对比的应该是指针地址吧),可在VC是YES 在C是NO

lz的呢,是一个常量字符串。位于静态存储区,它在程序生命期内恒定不变。如果编译器优化的话,会有可能a和b同时指向同一个hello的。则地址相同。如果编译器没有优化,那么就是两个不同的地址,则不同


1在字符串上找出第一个只出现一次的字符,字符不只是256个(不是单纯的char ),还包括汉字。。。。。
不知道对于存在汉字的这种应该怎么处理?如果只是256个字符的话,可以想到用哈希表,出现汉字,就晕了,希望懂的大神可以帮忙指点一下。。。。。。:hand:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值