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:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章