c++面試題300

1.    指出以下變量數據存儲位置
 
全局變量int(*g_pFun)(int);g_pFun=myFunction;g_pFun存儲的位置(A ) 爲全局的函數指針
 
指向空間的位置( B) 所有函數代碼位於TEXT段
 
函數內部變量 static int nCount;       ( A) 靜態變量總是在DATA段或BSS段中
 
函數內部變量 char p[]=”AAA”;  p 指向空間的位置( C) 局域變量的靜態數組,空間在Stack中
 
函數內部變量 char *p=”AAA”;  p 指向空間的位置( E) ,”AAA”爲一字符常量空間,不同編譯器有不同處理方法,大部分保存在TEXT(代碼段中),也有編譯的rodata段中
 
函數內部變量 char *p=new char; p的位置(C ) 指向空間的位置(D ) 所有malloc空間來自於heap(堆)
 
A.    數據段
 
B.    代碼段
 
C.    堆棧
 
D.    堆
 
E.    不一定, 視情況而定
 
以上知識參見C語言變量的作用域相關課件
 
2.    以下程序的輸出結果爲 ( )
 
#include <iostream>
 
main( )
 
{
 
using namespace std;
 
int num[5]={1,2,3,4,5};
 
cout <<*((int *)(&num+1)-1) <<endl;
 
}
 
A. 1        B.2        C. 3        D. 4        E. 5       F. 0        G. 未初始化內存,無法確定
 
在C語言中,一維數組名錶示數組的首地址,而且是一個指針.如上例num,
 
對&num,表示指針的指針.意味着這裏強制轉換爲二維數組指針.
 
這樣 &num+1 等同於 num[5][1],爲代碼空間. (&num+1)-1表示 num[4][0].即num[4].所以這裏答案是E.
 
 
 
擴展題目:
 
*((int *)(num+1)-1)   的值是多少?
 
Num是首指針,num+1是第二個元素指針,-1後又變成首指針.所以這裏是答案是num[0]即,A.1
 
3.    以下哪些是程序間可靠的通訊方式( C ),哪些可以用於跨主機通訊( C,D ,F).Windows命名管道跨機器也可跨機器.
 
A. 信號         B. 管道               C. TCP          D. UDP         E. PIPE         F,.串口I/O
 
4. class a
 
{
 
public:
 
virtual  void  funa( );
 
virtual  void  funb( );
 
void  fun( );
 
static  void  fund( );
 
static  int  si;
 
private:
 
int  i;
 
char  c;
 
};
 
問: 在32位編譯器默認情況下,sizeof(a)等於( )字節?
 
A. 28             B. 25      C.24          D. 20           E. 16        F.12             G. 8
 
答案在VC++下是 12. 這裏需要考慮三個問題,一是虛函數表vtable的入口表地址,二是字節對齊.三 ,靜態成員是所有對象共享,不計入sizeof空間.
 
在大部分C++的實現中,帶有虛函數的類的前4個BYTE是虛函數vtable表的這個類入口地址.所以sizeof必須要加入這個4個byte的長度,除此外,類的sizoef()爲所有數據成員總的sizeof之和,這裏是int i,和char c.其中char c被字節對齊爲4.這樣總長度爲
 
 
 
Sizeof(a) = sizeof(vtable)+size(int)+sizeof(char + pad) = 12;
 
 
 
5. 32位Windows 系統或Linux系統下
 
struct
 
{
 
char  a;
 
char  b;
 
char  c;
 
}A;
 
struct
 
{
 
short  a;
 
short  b;
 
short  c;
 
}B;
 
struct
 
{
 
short  a;
 
long  b;
 
char  c;
 
}C;
 
printf(“%d,%d,%d\n”,sizeof(A),sizeof(B),sizeof(C)); 的執行結果爲: ( )
 
A. 3,6,7         B. 3,6,8         C. 4,8,12              D. 3,6,12      E. 4,6,7         F. 4,8,9
 
 
 
C語法的字節對齊規則有兩種情況要字節對齊, 在VC++,gcc測試都是如此
 
1)    對同一個數據類型(short,int,long)發生了跨段分佈,(在32CPU裏,即一個數據類型分佈在兩個段中)纔會發生字節對齊.
 
2)    數據類型的首部和尾部必須有其一是與4對齊.而且違反上一規則.
 
l  Sizeof(A),sizeof(B)雖然總字節數不能被4整除.但剛好所有數據平均分佈在以4爲單位的各個段中.所以無需字節對齊,所以結果是 3和6
 
l  struct {char a;char b;char c;char d;char e;}F; 的sizoef(F)是等於5.
 
l  用以下實例更加清楚
 
struct {
 
char a[20];
 
short b;
 
}A;
 
struct {
 
char a[21];
 
short b;
 
}B;
 
Sizeof(A)=22,sizoef(B)=24.因爲前者沒有發生跨段分佈.後者,如果不字節對齊.a[21]佔用最後一個段的首地址,b無法作到與首部與尾部與4對齊,只能在a[21]與b之間加入一個byte,使用b的尾部與4對齊.
 
l  C就是比較好理解.要補多個成12
 
 
 
6.    依據程序,以下選擇中那個是對的? (  )
 
class A
 
{
 
int  m_nA;
 
};
 
class B
 
{
 
int   m_nB;
 
};
 
class C:public A,public B
 
{
 
int  m_nC;
 
};
 
void f (void)
 
{
 
C* pC=new C;
 
B* pB=dynamic_cast<B*>(pC);
 
A* pA=dynamic_cast<A*>(pC);
 
}
 
A. pC= =pB,(int)pC= =(int)B                                  B. pC= =pB,(int)pC!=(int)pB
 
C. pC!=pB,(int)pC= =(int)pB                                  D. pC!=pB,(int)pC!=(int)pB
 
 
 
這裏主要考多態..將程序變爲如下比較易懂
 
 
 
#include <stdio.h>
 
 
 
class A
 
{
 
public:
 
int  m_nA;
 
};
 
class B
 
{
 
public:
 
int   m_nB;
 
};
 
class C:public A,public B
 
{
 
public:
 
int  m_nC;
 
};
 
 
 
void f (void)
 
{
 
C* pC=new C;
 
B* pB=dynamic_cast<B*>(pC);
 
A* pA=dynamic_cast<A*>(pC);
 
}
 
 
 
void f1 (void)
 
{
 
C* pC=new C;
 
pC->m_nA = 1;
 
pC->m_nB = 2;
 
pC->m_nC = 3;
 
B* pB=dynamic_cast<B*>(pC);
 
A* pA=dynamic_cast<A*>(pC);
 
 
 
printf(“A=%x,B=%x,C=%x,iA=%d,iB=%d,iC=%d\n”,pA,pB,pC,(int)pA,(int)pB,(int)pC);
 
}
 
 
 
 
 
void test1();
 
 
 
int main()
 
{
 
// test1();
 
f1();
 
getchar();
 
return 0;
 
}
 
以上程序輸出:
 
A=4318d0,B=4318d4,C=4318d0,iA=4397264,iB=4397268,iC=4397264
 
即C從,A,B繼承下來,由下圖可以知道 pA=pC.而pB強制轉換後,只能取到C中B的部分.所以pB在pC向後偏移4個BYTE,(即m_nA)的空間
 
 
 
7,請寫出能匹配”[10]:dddddd ”和”[9]:abcdegf ”,不匹配”[a]:xfdf ”的正則表達式________,linux下支持正則的命令有:___find,grep_________
 
8.如下程序:
 
int i=1,k=0;
 
long *pl=NULL;
 
char *pc=NULL;
 
if(k++&&i++)
 
k++, pl++, pc++;
 
if(i++||k++)
 
i++, pl++, pc++;
 
printf(“i=%d,k=%d,pl=%ld,pc=%ld\n”,i,k,(long)pl,(long)pc);
 
 
 
打印結果爲__i=3,k=1,pl=4,pc=1________
 
主要測試邏輯表達式的短路操作.
 
&&操作中,前一個表達式爲0,後一表達式不執行
 
||操作中, 前一個表達式爲1,後一表達式不執行
 
 
 
9. 以下程序的輸出爲______________
 
#include<iostream>
 
using std::cout;
 
class A
 
{
 
public:
 
void f(void){
 
cout<< ”A::f” <<’ ‘;
 
}
 
virtual void g(void)
 
{
 
cout <<”A::g” << ‘ ‘;
 
}
 
};
 
 
 
class B : public A
 
{
 
public:
 
void f(void)
 
{
 
cout << “B :: f “ << ‘ ‘;
 
}
 
void g(void)
 
{
 
cout << “B:: g “ << ‘ ‘;
 
}
 
 
 
};
 
 
 
int main()
 
{
 
A*  pA =new B;
 
pA->f();
 
pA->g();
 
B* pB = (B*)pA;
 
pB->f();
 
pB->g();
 
}
 
A::f B:: g  B :: f  B:: g  

多態中虛函數調用.
 
f()爲非虛函數,這樣強制轉換後,執行本類的同名函數.
 
G()爲虛函數,指針總是執行虛函數,這就是多態..
 
10.下列代碼的作用是刪除list lTest 中值爲6的元素:
 
list<int> :: iterator Index = ITest .begin();
 
for( ;  Index != ITest .end();  ++ Index)
 
{
 
if((*Index) = = 6)
 
{
 
ITest .erase(Index);
 
}
 
}
 
請問有什麼錯誤____ Index = ITest .erase(Index);____________________,
 
STL的遊標處理,erase已經將Index破壞掉,需要用新的Index,否則下一循環的++Index被破壞掉
 
請寫出正確的代碼,或者在原代碼上修正.
 
 
 
11.找錯誤_以下程序:
 
char* ptr = malloc(100);
 
if(!ptr)
 
{
 
…
 
}
 
…
 
//ptr 指向的空間不夠需要重新分配
 
ptr = realloc(ptr,200);
 
if(!ptr)
 
{
 
…
 
}
 
…
 
請問有什麼錯誤___if(ptr ==NULL)____________________,請寫出正確的代碼,或者在原代碼上修正.
 
 
 
12.以下爲window NT 下32 位C++程序,請填寫如下值
 
class myclass
 
{
 
int a ;
 
int b;
 
};
 
char *p = “hello”;
 
char str[] = “world”;
 
myclass classes[2];
 
void *p2= malloc(100);
 
 
 
sizeof(p)=_4__
 
sizeof(str)=_6_
 
sizeof(classes)=_16__
 
sizeof(p2)=_4___
 
 
 
13.直接在以下程序中的錯誤的行數後的填空欄中打叉
 
程序1:
 
int main(void)
 
{
 
int i=10;_____
 
int *const j=&i;_______
 
(*j)++;____
 
j++;___*_____
 
}
 
程序2:
 
int main(void)
 
{
 
int i=20;_____
 
const int *j=&i;_________
 
*j++;______
 
(*j)++;____*____
 
}
 
 
 
主要考const 出現在*前後不同含意,const 在*後表示指針本身不能改,const 在*前面指針內容不能改,程序1中j不能修改指針,所以j++是錯,程序2,j不能改改內容,所以
 
 
 
14.用C/C++代碼實現以下要求:從1-100中挑選出10個不同的數字,請把可能的所有組合打印出來.
 
 
 
15.有一個非常大的全局數組int a[],長度n超過2的24次方,寫一個針對該數組的查找算法unsigned search(int value)(返回值下標),插入算法insert(int value,unsigned index).再次注意該數組的長度很長.
 
題目不太清,可能可以把數值本身作下標.並且按順序排序.
 
16.有兩個單向鏈表,表頭pHeader1,pHeader2,請寫一個函數判斷這兩個鏈表是否有交叉.如果有交叉,給出交叉點.程序不能改變鏈表的內容,可以使用額外的空間,時間複雜度儘量小,最好給出兩種解.(雙重循環的解由於時間複雜度高,不算正解).
 
1.移動鏈表指針,如果最終
 
17.編寫程序,將一棵樹從根節點到葉子的所有最長路徑都打印出來.比如一棵樹從跟到最末端的葉子最遠要經
 
過4個節點,那麼就把到所有要經過4個節點才能到達的葉子的搜索路徑(所有途徑節點)都分別打印出來.
 
 
 
18.請分別對一個鏈表和一個數組進行排序,並指出你排序的算法名稱以及爲何選擇該算法
 
數組可用交換法排序
 
 
 
 
 
19.有單向鏈表,其中節點結構爲Node{int value;Node *pNext};只知道指向某個節點的指針pCurrent;並且知道該節點不是尾節點,有什麼辦法把他刪除嗎?要求不斷鏈.
 
從鏈表頭開始,找到pCurrent上一個結點pPrev,然後 pPrev->pNext = pCurrent->pNext;
 
 
 
20.問題A:用什麼方法避免c/c++編程中的頭文件重複包含?問題B:假設解決了重複包含問題,但是又需要在兩個不同的頭文件中引用各申明的類,應該如何處理?具體代碼如下:
 
在頭文件Man.h中
 
….
 
Class Cman
 
{
 
….
 
CFace m_face;
 
};
 
….
 
在頭文件Face.h中
 
…
 
Class CFace
 
{
 
…
 
Cman *m_owner;
 
};
 
….
 
這樣類CMan.CFace就相互引用了,該如何處理呢?
 
 
 
1.#ifndef ….
 
#define …..
 
2.類的前向聲明
 
 
 
21.多線程和單線程各自分別在什麼時候效率更高?
 
多線程在併發,並且各線程無需訪問共享數據情況詳細最高
 
如果多線程過於頻繁切換,或共享數據很多情況下,使用單線程較好
 
 
 
22.在程序設計中,對公共資源(比如緩衝區等)的操作和訪問經常需要使用鎖來進行保護,但在大併發系統中過多的鎖會導致效率很低,通常有那些方法可以儘量避免或減少鎖的使用?
 
減少鎖的粒度,每次儘可能減少鎖範圍
 
採用隊列處理,這樣無需使用鎖.
 
23.請詳細闡述如何在release版本(windows程序或linux程序都可以)中,查找段錯誤問題.
 
可以用編譯器生成map文件來定位源碼.通過地址反查源碼
 
 
 
24.假設你編譯鏈接release版本後得到一個可執行程序(由多個cpp文件和H文件編譯),結果可執行程序文件非常大,你如何找到造成文件太大的可能原因,可能的原因是什麼?
 
使用一個已經初始化的巨大的全局數組
 
25.在編寫C++賦值運算符時有哪些要注意的地方?
 
返回值,參數最好用引用
 
減少友元函數使用,移植有問題.
 
26.假設你是參與設計嫦娥衛星的嵌入式單板軟件工程師,其中有一個快速搜索可能要用到哈希變或者平衡二叉樹,要求不管什麼條件下,單板必須在指定的短時間內有輸出,你會採取那種算法?爲什麼用這種算法,爲什麼不用另一種算法?
 
HASH.HASH訪問速度較快.
 
27.strcpy()容易引起緩衝區溢出問題,請問有什麼函數可以替代以減少風險,爲什麼?
 
strncpy
 
28.請指出spinlock,mutex,semaphore,critical section的作用與區別,都在哪些場合使用.
 
spin_lock Linux 內核自旋鎖. Mutex Windows 互質量, semaphore  POSIX ,critical section Windows
 
29.在哪些方法使阻塞模式的recv函數在沒有收到數據的情況下返回(不能將socket修改爲非阻塞模式)請描述得詳細點.
 
使用select
 
 
 
30.有3個紅色球,2個白色球,1個綠色球.取出兩個不同顏色的球就能變成兩個第三種顏色的球(比如:取出1紅球,1白球,就能變成2個綠球).問,最少幾次變化能將所有球都變成同一顏色,說明步驟和原因?
 
 
 
31.單向鏈表的反轉是一個經常被問到的一個面試題,也是一個非常基礎的問題。比如一個鏈表是這樣的: 1->2->3->4->5 通過反轉後成爲5->4->3->2->1。
 
最容易想到的方法遍歷一遍鏈表,利用一個輔助指針,存儲遍歷過程中當前指針指向的下一個元素,然後將當前節點元素的指針反轉後,利用已經存儲的指針往後面繼續遍歷。源代碼如下:
 1.struct linka {
 2.int data;
 3.linka* next;
 4.};
 5.void reverse(linka*& head) {
 6.if(head ==NULL)
 7.                  return;
 8.linka *pre, *cur, *ne;
 9.pre=head;
 10.cur=head->next;
 11.while(cur)
 12.{
 13.   ne = cur->next;
 14.   cur->next = pre;
 15.   pre = cur;
 16.   cur = ne;
 17.}
 18.head->next = NULL;
 19.head = pre;
 20.}
 
還有一種利用遞歸的方法。這種方法的基本思想是在反轉當前節點之前先調用遞歸函數反轉後續節點。源代碼如下。不過這個方法有一個缺點,就是在反轉後的最後一個結點會形成一個環,所以必須將函數的返回的節點的next域置爲NULL。因爲要改變head指針,所以我用了引用。算法的源代碼如下:
 1.linka* reverse(linka* p,linka*& head)
 2.{
 3.if(p == NULL || p->next == NULL)
 4.{
 5.   head=p;
 6.   return p;
 7.}
 8.else
 9.{
 10.   linka* tmp = reverse(p->next,head);
 11.   tmp->next = p;
 12.   return p;
 13.}
 14.}
 
32.已知String類定義如下:
 
class String
 {
 public:
 String(const char *str = NULL); // 通用構造函數
 String(const String &another); // 拷貝構造函數
 ~ String(); // 析構函數
 String & operater =(const String &rhs); // 賦值函數
 private:
 char *m_data; // 用於保存字符串
 };
 
嘗試寫出類的成員函數實現。
 
答案:
 
String::String(const char *str)
 {
 if ( str == NULL ) //strlen在參數爲NULL時會拋異常纔會有這步判斷
 {
 m_data = new char[1] ;
 m_data[0] = ‘\0′ ;
 }
 else
 {
 m_data = new char[strlen(str) + 1];
 strcpy(m_data,str);
 }
 
}
 
String::String(const String &another)
 {
 m_data = new char[strlen(another.m_data) + 1];
 strcpy(m_data,other.m_data);
 }
 
String& String::operator =(const String &rhs)
 {
 if ( this == &rhs)
 return *this ;
 delete []m_data; //刪除原來的數據,新開一塊內存
 m_data = new char[strlen(rhs.m_data) + 1];
 strcpy(m_data,rhs.m_data);
 return *this ;
 }
 
String::~String()
 {
 delete []m_data ;
 }
 


33.求下面函數的返回值(微軟)
 
int func(x)
 {
 int countx = 0;
 while(x)
 {
 countx ++;
 x = x&(x-1);
 }
 return countx;
 }
 
假定x = 9999。 答案:8
 
思路:將x轉化爲2進制,看含有的1的個數。
 
34. 什麼是“引用”?申明和使用“引用”要注意哪些問題?
 
答:引用就是某個目標變量的“別名”(alias),對應用的操作與對變量直接操作效果完全相同。申明一個引用的時候,切記要對其進行初始化。引用聲明完畢後,相當於目標變量名有兩個名稱,即該目標原名稱和引用名,不能再把該引用名作爲其他變量名的別名。聲明一個引用,不是新定義了一個變量,它只表示該引用名是目標變量名的一個別名,它本身不是一種數據類型,因此引用本身不佔存儲單元,系統也不給引用分配存儲單元。不能建立數組的引用。
 
45. 將“引用”作爲函數參數有哪些特點?
 
(1)傳遞引用給函數與傳遞指針的效果是一樣的。這時,被調函數的形參就成爲原來主調函數中的實參變量或對象的一個別名來使用,所以在被調函數中對形參變量的操作就是對其相應的目標對象(在主調函數中)的操作。
 
(2)使用引用傳遞函數的參數,在內存中並沒有產生實參的副本,它是直接對實參操作;而使用一般變量傳遞函數的參數,當發生函數調用時,需要給形參分配存儲單元,形參變量是實參變量的副本;如果傳遞的是對象,還將調用拷貝構造函數。因此,當參數傳遞的數據較大時,用引用比用一般變量傳遞參數的效率和所佔空間都好。
 
(3)使用指針作爲函數的參數雖然也能達到與使用引用的效果,但是,在被調函數中同樣要給形參分配存儲單元,且需要重複使用”*指針變量名”的形式進行運算,這很容易產生錯誤且程序的閱讀性較差;另一方面,在主調函數的調用點處,必須用變量的地址作爲實參。而引用更容易使用,更清晰。
 
36. 在什麼時候需要使用“常引用”?
 
如果既要利用引用提高程序的效率,又要保護傳遞給函數的數據不在函數中被改變,就應使用常引用。常引用聲明方式:const 類型標識符 &引用名=目標變量名;
 
例1
 
int a ;
 const int &ra=a;
 ra=1; //錯誤
 a=1; //正確
 
例2
 
string foo( );
 void bar(string & s);
 
那麼下面的表達式將是非法的:
 
bar(foo( ));
 bar(“hello world”);
 
原因在於foo( )和”hello world”串都會產生一個臨時對象,而在C++中,這些臨時對象都是const類型的。因此上面的表達式就是試圖將一個const類型的對象轉換爲非const類型,這是非法的。
 
引用型參數應該在能被定義爲const的情況下,儘量定義爲const 。
 
37. 將“引用”作爲函數返回值類型的格式、好處和需要遵守的規則?
 
格式:類型標識符 &函數名(形參列表及類型說明){ //函數體 }
 
好處:在內存中不產生被返回值的副本;(注意:正是因爲這點原因,所以返回一個局部變量的引用是不可取的。因爲隨着該局部變量生存期的結束,相應的引用也會失效,產生runtime error!
 
注意事項:
 
(1)不能返回局部變量的引用。這條可以參照Effective C++[1]的Item 31。主要原因是局部變量會在函數返回後被銷燬,因此被返回的引用就成爲了”無所指”的引用,程序會進入未知狀態。
 
(2)不能返回函數內部new分配的內存的引用。這條可以參照Effective C++[1]的Item 31。雖然不存在局部變量的被動銷燬問題,可對於這種情況(返回函數內部new分配內存的引用),又面臨其它尷尬局面。例如,被函數返回的引用只是作爲一個臨時變量出現,而沒有被賦予一個實際的變量,那麼這個引用所指向的空間(由new分配)就無法釋放,造成memory leak。
 
(3)可以返回類成員的引用,但最好是const。這條原則可以參照Effective C++[1]的Item 30。主要原因是當對象的屬性是與某種業務規則(business rule)相關聯的時候,其賦值常常與某些其它屬性或者對象的狀態有關,因此有必要將賦值操作封裝在一個業務規則當中。如果其它對象可以獲得該屬性的非常量引用(或指針),那麼對該屬性的單純賦值就會破壞業務規則的完整性。
 
(4)流操作符重載返回值申明爲“引用”的作用:
 
流操作符<<和>>,這兩個操作符常常希望被連續使用,例如:cout << “hello” << endl; 因此這兩個操作符的返回值應該是一個仍然支持這兩個操作符的流引用。可選的其它方案包括:返回一個流對象和返回一個流對象指針。但是對於返回一個流對象,程序必須重新(拷貝)構造一個新的流對象,也就是說,連續的兩個<<操作符實際上是針對不同對象的!這無法讓人接受。對於返回一個流指針則不能連續使用<<操作符。因此,返回一個流對象引用是惟一選擇。這個唯一選擇很關鍵,它說明了引用的重要性以及無可替代性,也許這就是C++語言中引入引用這個概念的原因吧。賦值操作符=。這個操作符象流操作符一樣,是可以連續使用的,例如:x = j = 10;或者(x=10)=100;賦值操作符的返回值必須是一個左值,以便可以被繼續賦值。因此引用成了這個操作符的惟一返回值選擇。
 
例3
 
#i nclude <iostream.h>
 int &put(int n);
 int vals[10];
 int error=-1;
 void main()
 {
 put(0)=10; //以put(0)函數值作爲左值,等價於vals[0]=10;
 put(9)=20; //以put(9)函數值作爲左值,等價於vals[9]=20;
 cout<<vals[0];
 cout<<vals[9];
 }
 int &put(int n)
 {
 if (n>=0 && n<=9 ) return vals[n];
 else { cout<<”subscript error”; return error; }
 }
 
(5)在另外的一些操作符中,卻千萬不能返回引用:+-*/ 四則運算符。它們不能返回引用,Effective C++[1]的Item23詳細的討論了這個問題。主要原因是這四個操作符沒有side effect,因此,它們必須構造一個對象作爲返回值,可選的方案包括:返回一個對象、返回一個局部變量的引用,返回一個new分配的對象的引用、返回一個靜態對象引用。根據前面提到的引用作爲返回值的三個規則,第2、3兩個方案都被否決了。靜態對象的引用又因爲((a+b) == (c+d))會永遠爲true而導致錯誤。所以可選的只剩下返回一個對象了。
 
38. “引用”與多態的關係?
 
引用是除指針外另一個可以產生多態效果的手段。這意味着,一個基類的引用可以指向它的派生類實例。
 
例4
 
Class A; Class B : Class A{…}; B b; A& ref = b;
 
39. “引用”與指針的區別是什麼?
 
指針通過某個指針變量指向一個對象後,對它所指向的變量間接操作。程序中使用指針,程序的可讀性差;而引用本身就是目標變量的別名,對引用的操作就是對目標變量的操作。此外,就是上面提到的對函數傳ref和pointer的區別。
 
40. 什麼時候需要“引用”?
 
流操作符<<和>>、賦值操作符=的返回值、拷貝構造函數的參數、賦值操作符=的參數、其它情況都推薦使用引用。
 
以上 2-8 參考:http://blog.csdn.net/wfwd/archive/2006/05/30/763551.aspx
 
41. 結構與聯合有和區別?
 1. 結構和聯合都是由多個不同的數據類型成員組成, 但在任何同一時刻, 聯合中只存放了一個被選中的成員(所有成員共用一塊地址空間), 而結構的所有成員都存在(不同成員的存放地址不同)。
 2. 對於聯合的不同成員賦值, 將會對其它成員重寫, 原來成員的值就不存在了, 而對於結構的不同成員賦值是互不影響的。
 
42. 下面關於“聯合”的題目的輸出?
 
a)
 
#i nclude <stdio.h>
 union
 {
 int i;
 char x[2];
 }a;
 
void main()
 {
 a.x[0] = 10;
 a.x[1] = 1;
 printf(“%d”,a.i);
 }
 答案:266 (低位低地址,高位高地址,內存佔用情況是Ox010A)
 
b)
 
main()
 {
 union{ /*定義一個聯合*/
 int i;
 struct{ /*在聯合中定義一個結構*/
 char first;
 char second;
 }half;
 }number;
 number.i=0×4241; /*聯合成員賦值*/
 printf(“%c%c\n”, number.half.first, mumber.half.second);
 number.half.first=’a'; /*聯合中結構成員賦值*/
 number.half.second=’b';
 printf(“%x\n”, number.i);
 getch();
 }
 答案: AB (0×41對應’A',是低位;Ox42對應’B',是高位)
 
6261 (number.i和number.half共用一塊地址空間)
 
43. 已知strcpy的函數原型:char *strcpy(char *strDest, const char *strSrc)其中strDest 是目的字符串,strSrc 是源字符串。不調用C++/C 的字符串庫函數,請編寫函數 strcpy。
 

答案:
 char *strcpy(char *strDest, const char *strSrc)
 {
 if ( strDest == NULL || strSrc == NULL)
 return NULL ;
 if ( strDest == strSrc)
 return strDest ;
 char *tempptr = strDest ;
 while( (*strDest++ = *strSrc++) != ‘\0’)
 return tempptr ;
 }
 
44. .h頭文件中的ifndef/define/endif 的作用?
 
答:防止該頭文件被重複引用。
 
45. #i nclude<file.h> 與 #i nclude “file.h”的區別?
 
答:前者是從Standard Library的路徑尋找和引用file.h,而後者是從當前工作路徑搜尋並引用file.h。
 
46.在C++ 程序中調用被C 編譯器編譯後的函數,爲什麼要加extern “C”?
 
首先,作爲extern是C/C++語言中表明函數和全局變量作用範圍(可見性)的關鍵字,該關鍵字告訴編譯器,其聲明的函數和變量可以在本模塊或其它模塊中使用。
 
通常,在模塊的頭文件中對本模塊提供給其它模塊引用的函數和全局變量以關鍵字extern聲明。例如,如果模塊B欲引用該模塊A中定義的全局變量和函數時只需包含模塊A的頭文件即可。這樣,模塊B中調用模塊A中的函數時,在編譯階段,模塊B雖然找不到該函數,但是並不會報錯;它會在連接階段中從模塊A編譯生成的目標代碼中找到此函數
 
extern “C”是連接申明(linkage declaration),被extern “C”修飾的變量和函數是按照C語言方式編譯和連接的,來看看C++中對類似C的函數是怎樣編譯的:
 
作爲一種面向對象的語言,C++支持函數重載,而過程式語言C則不支持。函數被C++編譯後在符號庫中的名字與C語言的不同。例如,假設某個函數的原型爲:
 
void foo( int x, int y );
 
該函數被C編譯器編譯後在符號庫中的名字爲_foo,而C++編譯器則會產生像_foo_int_int之類的名字(不同的編譯器可能生成的名字不同,但是都採用了相同的機制,生成的新名字稱爲“mangled name”)。
 
_foo_int_int 這樣的名字包含了函數名、函數參數數量及類型信息,C++就是靠這種機制來實現函數重載的。例如,在C++中,函數void foo( int x, int y )與void foo( int x, float y )編譯生成的符號是不相同的,後者爲_foo_int_float。
 
同樣地,C++中的變量除支持局部變量外,還支持類成員變量和全局變量。用戶所編寫程序的類成員變量可能與全局變量同名,我們以”.”來區分。而本質上,編譯器在進行編譯時,與函數的處理相似,也爲類中的變量取了一個獨一無二的名字,這個名字與用戶程序中同名的全局變量名字不同。
 
未加extern “C”聲明時的連接方式
 
假設在C++中,模塊A的頭文件如下:
 
// 模塊A頭文件 moduleA.h
 #ifndef MODULE_A_H
 #define MODULE_A_H
 int foo( int x, int y );
 #endif
 
在模塊B中引用該函數:
 
// 模塊B實現文件 moduleB.cpp
 #i nclude “moduleA.h”
 foo(2,3);
 
實際上,在連接階段,連接器會從模塊A生成的目標文件moduleA.obj中尋找_foo_int_int這樣的符號!
 
加extern “C”聲明後的編譯和連接方式
 
加extern “C”聲明後,模塊A的頭文件變爲:
 
// 模塊A頭文件 moduleA.h
 #ifndef MODULE_A_H
 #define MODULE_A_H
 extern “C” int foo( int x, int y );
 #endif
 
在模塊B的實現文件中仍然調用foo( 2,3 ),其結果是:
 (1)模塊A編譯生成foo的目標代碼時,沒有對其名字進行特殊處理,採用了C語言的方式;
 
(2)連接器在爲模塊B的目標代碼尋找foo(2,3)調用時,尋找的是未經修改的符號名_foo。
 
如果在模塊A中函數聲明瞭foo爲extern “C”類型,而模塊B中包含的是extern int foo( int x, int y ) ,則模塊B找不到模塊A中的函數;反之亦然。
 
所以,可以用一句話概括extern “C”這個聲明的真實目的(任何語言中的任何語法特性的誕生都不是隨意而爲的,來源於真實世界的需求驅動。我們在思考問題時,不能只停留在這個語言是怎麼做的,還要問一問它爲什麼要這麼做,動機是什麼,這樣我們可以更深入地理解許多問題):實現C++與C及其它語言的混合編程。
 
明白了C++中extern “C”的設立動機,我們下面來具體分析extern “C”通常的使用技巧:
 
extern “C”的慣用法
 
(1)在C++中引用C語言中的函數和變量,在包含C語言頭文件(假設爲cExample.h)時,需進行下列處理:
 
extern “C”
 {
 #i nclude “cExample.h”
 }
 
而在C語言的頭文件中,對其外部函數只能指定爲extern類型,C語言中不支持extern “C”聲明,在.c文件中包含了extern “C”時會出現編譯語法錯誤。
 
C++引用C函數例子工程中包含的三個文件的源代碼如下:
 
/* c語言頭文件:cExample.h */
 #ifndef C_EXAMPLE_H
 #define C_EXAMPLE_H
 extern int add(int x,int y);
 #endif
 
/* c語言實現文件:cExample.c */
 #i nclude “cExample.h”
 int add( int x, int y )
 {
 return x + y;
 }
 
// c++實現文件,調用add:cppFile.cpp
 extern “C”
 {
 #i nclude “cExample.h”
 }
 int main(int argc, char* argv[])
 {
 add(2,3);
 return 0;
 }
 
如果C++調用一個C語言編寫的.DLL時,當包括.DLL的頭文件或聲明接口函數時,應加extern “C” { }。
 
(2)在C中引用C++語言中的函數和變量時,C++的頭文件需添加extern “C”,但是在C語言中不能直接引用聲明瞭extern “C”的該頭文件,應該僅將C文件中將C++中定義的extern “C”函數聲明爲extern類型。
 
C引用C++函數例子工程中包含的三個文件的源代碼如下:
 
//C++頭文件 cppExample.h
 #ifndef CPP_EXAMPLE_H
 #define CPP_EXAMPLE_H
 extern “C” int add( int x, int y );
 #endif
 
//C++實現文件 cppExample.cpp
 #i nclude “cppExample.h”
 int add( int x, int y )
 {
 return x + y;
 }
 
/* C實現文件 cFile.c
 /* 這樣會編譯出錯:#i nclude “cExample.h” */
 extern int add( int x, int y );
 int main( int argc, char* argv[] )
 {
 add( 2, 3 );
 return 0;
 }
 
15題目的解答請參考《C++中extern “C”含義深層探索》註解:
 
47. 關聯、聚合(Aggregation)以及組合(Composition)的區別?
 
涉及到UML中的一些概念:關聯是表示兩個類的一般性聯繫,比如“學生”和“老師”就是一種關聯關係;聚合表示has-a的關係,是一種相對鬆散的關係,聚合類不需要對被聚合類負責,如下圖所示,用空的菱形表示聚合關係:
 
從實現的角度講,聚合可以表示爲:
 
class A {…} class B { A* a; …..}
 
而組合表示contains-a的關係,關聯性強於聚合:組合類與被組合類有相同的生命週期,組合類要對被組合類負責,採用實心的菱形表示組合關係:
 
實現的形式是:
 
class A{…} class B{ A a; …}
 
參考文章:http://blog.csdn.net/wfwd/archive/2006/05/30/763753.aspx
 
http://blog.csdn.net/wfwd/archive/2006/05/30/763760.aspx
 
48.面向對象的三個基本特徵,並簡單敘述之?
 
1. 封裝:將客觀事物抽象成類,每個類對自身的數據和方法實行protection(private, protected,public)
 
2. 繼承:廣義的繼承有三種實現形式:實現繼承(指使用基類的屬性和方法而無需額外編碼的能力)、可視繼承(子窗體使用父窗體的外觀和實現代碼)、接口繼承(僅使用屬性和方法,實現滯後到子類實現)。前兩種(類繼承)和後一種(對象組合=>接口繼承以及純虛函數)構成了功能複用的兩種方式。
 
3. 多態:是將父對象設置成爲和一個或更多的他的子對象相等的技術,賦值之後,父對象就可以根據當前賦值給它的子對象的特性以不同的方式運作。簡單的說,就是一句話:允許將子類類型的指針賦值給父類類型的指針。
 
49. 重載(overload)和重寫(overried,有的書也叫做“覆蓋”)的區別?
 
常考的題目。從定義上來說:
 
重載:是指允許存在多個同名函數,而這些函數的參數表不同(或許參數個數不同,或許參數類型不同,或許兩者都不同)。
 
重寫:是指子類重新定義復類虛函數的方法。
 
從實現原理上來說:
 
重載:編譯器根據函數不同的參數表,對同名函數的名稱做修飾,然後這些同名函數就成了不同的函數(至少對於編譯器來說是這樣的)。如,有兩個同名函數:function func(p:integer):integer;和function func(p:string):integer;。那麼編譯器做過修飾後的函數名稱可能是這樣的:int_func、str_func。對於這兩個函數的調用,在編譯器間就已經確定了,是靜態的。也就是說,它們的地址在編譯期就綁定了(早綁定),因此,重載和多態無關!
 
重寫:和多態真正相關。當子類重新定義了父類的虛函數後,父類指針根據賦給它的不同的子類指針,動態的調用屬於子類的該函數,這樣的函數調用在編譯期間是無法確定的(調用的子類的虛函數的地址無法給出)。因此,這樣的函數地址是在運行期綁定的(晚綁定)。
 
50. 多態的作用?
 
主要是兩個:1. 隱藏實現細節,使得代碼能夠模塊化;擴展代碼模塊,實現代碼重用;2. 接口重用:爲了類在繼承和派生的時候,保證使用家族中任一類的實例的某一屬性時的正確調用。

51. New delete 與malloc free 的聯繫與區別?
 答案:都是在堆(heap)上進行動態的內存操作。用malloc函數需要指定內存分配的字節數並且不能初始化對象,new 會自動調用對象的構造函數。delete 會調用對象的destructor,而free 不會調用對象的destructor.
 
52. 有哪幾種情況只能用intialization list 而不能用assignment?
 
答案:當類中含有const、reference 成員變量;基類的構造函數都需要初始化表。
 
53. C++是不是類型安全的?
 答案:不是。兩個不同類型的指針之間可以強制轉換(用reinterpret cast)。C#是類型安全的。
 
54. main 函數執行以前,還會執行什麼代碼?
 答案:全局對象的構造函數會在main 函數之前執行。
 
55. 描述內存分配方式以及它們的區別?
 1) 從靜態存儲區域分配。內存在程序編譯的時候就已經分配好,這塊內存在程序的整個運行期間都存在。例如全局變量,static 變量。
 2) 在棧上創建。在執行函數時,函數內局部變量的存儲單元都可以在棧上創建,函數執行結束時這些存儲單元自動被釋放。棧內存分配運算內置於處理器的指令集。
 3) 從堆上分配,亦稱動態內存分配。程序在運行的時候用malloc 或new 申請任意多少的內存,程序員自己負責在何時用free 或delete 釋放內存。動態內存的生存期由程序員決定,使用非常靈活,但問題也最多。
 
56.struct 和 class 的區別
 
答案:struct 的成員默認是公有的,而類的成員默認是私有的。struct 和 class 在其他方面是功能相當的。
 
從感情上講,大多數的開發者感到類和結構有很大的差別。感覺上結構僅僅象一堆缺乏封裝和功能的開放的內存位,而類就象活的並且可靠的社會成員,它有智能服務,有牢固的封裝屏障和一個良好定義的接口。既然大多數人都這麼認爲,那麼只有在你的類有很少的方法並且有公有數據(這種事情在良好設計的系統中是存在的!)時,你也許應該使用 struct 關鍵字,否則,你應該使用 class 關鍵字。
 
57.當一個類A 中沒有生命任何成員變量與成員函數,這時sizeof(A)的值是多少,如果不是零,請解釋一下編譯器爲什麼沒有讓它爲零。(Autodesk)
 答案:肯定不是零。舉個反例,如果是零的話,聲明一個class A[10]對象數組,而每一個對象佔用的空間是零,這時就沒辦法區分A[0],A[1]…了。
 
58. 在8086 彙編下,邏輯地址和物理地址是怎樣轉換的?(Intel)
 答案:通用寄存器給出的地址,是段內偏移地址,相應段寄存器地址*10H+通用寄存器內地址,就得到了真正要訪問的地址。
 
59. 比較C++中的4種類型轉換方式?
 
請參考:http://blog.csdn.net/wfwd/archive/2006/05/30/763785.aspx,重點是static_cast, dynamic_cast和reinterpret_cast的區別和應用。
 
60.分別寫出BOOL,int,float,指針類型的變量a 與“零”的比較語句。
 答案:
 BOOL : if ( !a ) or if(a)
 int : if ( a == 0)
 float : const EXPRESSION EXP = 0.000001
 if ( a < EXP && a >-EXP)
 pointer : if ( a != NULL) or if(a == NULL)
 
61.請說出const與#define 相比,有何優點?
 答案:1) const 常量有數據類型,而宏常量沒有數據類型。編譯器可以對前者進行類型安全檢查。而對後者只進行字符替換,沒有類型安全檢查,並且在字符替換可能會產生意料不到的錯誤。
 2) 有些集成化的調試工具可以對const 常量進行調試,但是不能對宏常量進行調試。
 
62.簡述數組與指針的區別?
 數組要麼在靜態存儲區被創建(如全局數組),要麼在棧上被創建。指針可以隨時指向任意類型的內存塊。
 (1)修改內容上的差別
 char a[] = “hello”;
 a[0] = ‘X’;
 char *p = “world”; // 注意p 指向常量字符串
 p[0] = ‘X’; // 編譯器不能發現該錯誤,運行時錯誤
 (2) 用運算符sizeof 可以計算出數組的容量(字節數)。sizeof(p),p 爲指針得到的是一個指針變量的字節數,而不是p 所指的內存容量。C++/C 語言沒有辦法知道指針所指的內存容量,除非在申請內存時記住它。注意當數組作爲函數的參數進行傳遞時,該數組自動退化爲同類型的指針。
 char a[] = “hello world”;
 char *p = a;
 cout<< sizeof(a) << endl; // 12 字節
 cout<< sizeof(p) << endl; // 4 字節
 計算數組和指針的內存容量
 void Func(char a[100])
 {
 cout<< sizeof(a) << endl; // 4 字節而不是100 字節
 }
 
63.類成員函數的重載、覆蓋和隱藏區別?
 答案:
 a.成員函數被重載的特徵:
 (1)相同的範圍(在同一個類中);
 (2)函數名字相同;
 (3)參數不同;
 (4)virtual 關鍵字可有可無。
 b.覆蓋是指派生類函數覆蓋基類函數,特徵是:
 (1)不同的範圍(分別位於派生類與基類);
 (2)函數名字相同;
 (3)參數相同;
 (4)基類函數必須有virtual 關鍵字。
 c.“隱藏”是指派生類的函數屏蔽了與其同名的基類函數,規則如下:
 (1)如果派生類的函數與基類的函數同名,但是參數不同。此時,不論有無virtual關鍵字,基類的函數將被隱藏(注意別與重載混淆)。
 (2)如果派生類的函數與基類的函數同名,並且參數也相同,但是基類函數沒有virtual 關鍵字。此時,基類的函數被隱藏(注意別與覆蓋混淆)
 
64. 如何打印出當前源文件的文件名以及源文件的當前行號?
 答案:
 cout << __FILE__ ;
 cout<<__LINE__ ;
 __FILE__和__LINE__是系統預定義宏,這種宏並不是在某個文件中定義的,而是由編譯器定義的。
 
65. main 主函數執行完畢後,是否可能會再執行一段代碼,給出說明?
 答案:可以,可以用_onexit 註冊一個函數,它會在main 之後執行int fn1(void), fn2(void), fn3(void), fn4 (void);
 void main( void )
 {
 String str(“zhanglin”);
 _onexit( fn1 );
 _onexit( fn2 );
 _onexit( fn3 );
 _onexit( fn4 );
 printf( “This is executed first.\n” );
 }
 int fn1()
 {
 printf( “next.\n” );
 return 0;
 }
 int fn2()
 {
 printf( “executed ” );
 return 0;
 }
 int fn3()
 {
 printf( “is ” );
 return 0;
 }
 int fn4()
 {
 printf( “This ” );
 return 0;
 }
 The _onexit function is passed the address of a function (func) to be called when the program terminates normally. Successive calls to _onexit create a register of functions that are executed in LIFO (last-in-first-out) order. The functions passed to _onexit cannot take parameters.
 
66. 如何判斷一段程序是由C 編譯程序還是由C++編譯程序編譯的?
 答案:
 #ifdef __cplusplus
 cout<<”c++”;
 #else
 cout<<”c”;
 #endif
 
67.文件中有一組整數,要求排序後輸出到另一個文件中
 答案:
 
#i nclude<iostream>
 
#i nclude<fstream>
 
using namespace std;
 
void Order(vector<int>& data) //bubble sort
 {
 int count = data.size() ;
 int tag = false ; // 設置是否需要繼續冒泡的標誌位
 for ( int i = 0 ; i < count ; i++)
 {
 for ( int j = 0 ; j < count – i – 1 ; j++)
 {
 if ( data[j] > data[j+1])
 {
 tag = true ;
 int temp = data[j] ;
 data[j] = data[j+1] ;
 data[j+1] = temp ;
 }
 }
 if ( !tag )
 break ;
 }
 }
 
void main( void )
 {
 vector<int>data;
 ifstream in(“c:\\data.txt”);
 if ( !in)
 {
 cout<<”file error!”;
 exit(1);
 }
 int temp;
 while (!in.eof())
 {
 in>>temp;
 data.push_back(temp);
 }
 in.close(); //關閉輸入文件流
 Order(data);
 ofstream out(“c:\\result.txt”);
 if ( !out)
 {
 cout<<”file error!”;
 exit(1);
 }
 for ( i = 0 ; i < data.size() ; i++)
 out<<data[i]<<” “;
 out.close(); //關閉輸出文件流
 }
 
68. 鏈表題:一個鏈表的結點結構
 struct Node
 {
 int data ;
 Node *next ;
 };
 typedef struct Node Node ;
 
(1)已知鏈表的頭結點head,寫一個函數把這個鏈表逆序 ( Intel)
 
Node * ReverseList(Node *head) //鏈表逆序
 {
 if ( head == NULL || head->next == NULL )
 return head;
 Node *p1 = head ;
 Node *p2 = p1->next ;
 Node *p3 = p2->next ;
 p1->next = NULL ;
 while ( p3 != NULL )
 {
 p2->next = p1 ;
 p1 = p2 ;
 p2 = p3 ;
 p3 = p3->next ;
 }
 p2->next = p1 ;
 head = p2 ;
 return head ;
 }
 (2)已知兩個鏈表head1 和head2 各自有序,請把它們合併成一個鏈表依然有序。(保留所有結點,即便大小相同)
 Node * Merge(Node *head1 , Node *head2)
 {
 if ( head1 == NULL)
 return head2 ;
 if ( head2 == NULL)
 return head1 ;
 Node *head = NULL ;
 Node *p1 = NULL;
 Node *p2 = NULL;
 if ( head1->data < head2->data )
 {
 head = head1 ;
 p1 = head1->next;
 p2 = head2 ;
 }
 else
 {
 head = head2 ;
 p2 = head2->next ;
 p1 = head1 ;
 }
 Node *pcurrent = head ;
 while ( p1 != NULL && p2 != NULL)
 {
 if ( p1->data <= p2->data )
 {
 pcurrent->next = p1 ;
 pcurrent = p1 ;
 p1 = p1->next ;
 }
 else
 {
 pcurrent->next = p2 ;
 pcurrent = p2 ;
 p2 = p2->next ;
 }
 }
 if ( p1 != NULL )
 pcurrent->next = p1 ;
 if ( p2 != NULL )
 pcurrent->next = p2 ;
 return head ;
 }
 (3)已知兩個鏈表head1 和head2 各自有序,請把它們合併成一個鏈表依然有序,這次要求用遞歸方法進行。 (Autodesk)
 答案:
 Node * MergeRecursive(Node *head1 , Node *head2)
 {
 if ( head1 == NULL )
 return head2 ;
 if ( head2 == NULL)
 return head1 ;
 Node *head = NULL ;
 if ( head1->data < head2->data )
 {
 head = head1 ;
 head->next = MergeRecursive(head1->next,head2);
 }
 else
 {
 head = head2 ;
 head->next = MergeRecursive(head1,head2->next);
 }
 return head ;
 }
 
69. 分析一下這段程序的輸出 (Autodesk)
 class B
 {
 public:
 B()
 {
 cout<<”default constructor”<<endl;
 }
 ~B()
 {
 cout<<”destructed”<<endl;
 }
 B(int i):data(i) //B(int) works as a converter ( int -> instance of B)
 {
 cout<<”constructed by parameter ” << data <<endl;
 }
 private:
 int data;
 };
 
B Play( B b)
 {
 return b ;
 }
 
(1) results:
 int main(int argc, char* argv[]) constructed by parameter 5
 { destructed B(5)形參析構
 B t1 = Play(5); B t2 = Play(t1);   destructed t1形參析構
 return 0;               destructed t2 注意順序!
 } destructed t1
 
(2) results:
 int main(int argc, char* argv[]) constructed by parameter 5
 { destructed B(5)形參析構
 B t1 = Play(5); B t2 = Play(10);   constructed by parameter 10
 return 0;               destructed B(10)形參析構
 } destructed t2 注意順序!
 
destructed t1
 
70. 寫一個函數找出一個整數數組中,第二大的數 (microsoft)
 答案:
 const int MINNUMBER = -32767 ;
 int find_sec_max( int data[] , int count)
 {
 int maxnumber = data[0] ;
 int sec_max = MINNUMBER ;
 for ( int i = 1 ; i < count ; i++)
 {
 if ( data[i] > maxnumber )
 {
 sec_max = maxnumber ;
 maxnumber = data[i] ;
 }
 else
 {
 if ( data[i] > sec_max )
 sec_max = data[i] ;
 }
 }
 return sec_max ;
 }
 
71. 寫一個在一個字符串(n)中尋找一個子串(m)第一個位置的函數。
 
KMP算法效率最好,時間複雜度是O(n+m)。
 
72. 多重繼承的內存分配問題:
 比如有class A : public class B, public class C {}
 那麼A的內存結構大致是怎麼樣的?
 
這個是compiler-dependent的, 不同的實現其細節可能不同。
 如果不考慮有虛函數、虛繼承的話就相當簡單;否則的話,相當複雜。
 可以參考《深入探索C++對象模型》,或者:
 
http://blog.csdn.net/wfwd/archive/2006/05/30/763797.aspx
 
73. 如何判斷一個單鏈表是有環的?(注意不能用標誌位,最多隻能用兩個額外指針)
 
struct node { char val; node* next;}
 
bool check(const node* head) {} //return false : 無環;true: 有環
 
一種O(n)的辦法就是(搞兩個指針,一個每次遞增一步,一個每次遞增兩步,如果有環的話兩者必然重合,反之亦然):
 bool check(const node* head)
 {
 if(head==NULL) return false;
 node *low=head, *fast=head->next;
 while(fast!=NULL && fast->next!=NULL)
 {
 low=low->next;
 fast=fast->next->next;
 if(low==fast) return true;
 }
 return false;
 }
 


74.不使用庫函數,編寫函數int strcmp(char  *source, char *dest)相等返回0,不等返回-1
 
 
 
int StrCmp(char  *source, char *dest)
 
{
 
assert(source !=NULL) ;
 
assert(dest!=NULL) ;
 
while(*source= =*dest&&*source&&*dest)
 
{
 
source++;
 
dest++;
 
}
 
return (*source!=*dest)?-1:0;
 
}
 
 
 
 
 
 
 
 
 
75.寫一個函數,實現將一個字符串中的’\t’替換成四個’*’, ’\t’個數不定。如char *p=”ht\thdsf\t\ttt\tfds dfsw\t ew\t”,替換後p=”ht****hdsf********tt****fds dfsw**** ew****”。
 
char *Replace(char *Sorce)
 
{
 
char *pTemp=Sorce;
 
int iCount=0;
 
int iSizeOfSorce=0;
 
 
 
while(*pTemp!=’\0′)
 
{
 
if(‘\t’==*pTemp)
 
iCount++;
 
pTemp++;
 
}
 
iSizeOfSorce=pTemp-Sorce;
 
 
 
char *pNewStr=new char[iSizeOfSorce+3*iCount*sizeof(char)+1];
 
char *pTempNewStr=pNewStr;
 
 
 
pTemp=Sorce;
 
while(*pTemp!=’\0′)
 
{
 
if(‘\t’==*pTemp)
 
{
 
for(int iLoop=0; iLoop<4; iLoop++)
 
{
 
*pTempNewStr=’*';
 
pTempNewStr++;
 
}
 
pTemp++;
 
}
 
else
 
{
 
*pTempNewStr=*pTemp;
 
pTemp++;
 
pTempNewStr++;
 
}
 
}
 
*pTempNewStr=’\0′;
 
 
 
return pNewStr;
 
}
 
 
 
 
 
 
 
 
 
 
 
76.寫一函數實現將一個字符串中的數字字符全部去掉。
 
void RemoveNum(char strSrc[])
 
{
 
       char *p=strSrc;
 
       char *q;
 
       while(*p!=’\0′)
 
       {
 
              if(*p>=’0′&&*p<=’9′)
 
              {
 
                     q=p;
 
                     while(*q!=’\0′)
 
                     {
 
                            *q=*(q+1);
 
                            q++;
 
                     }
 
              }
 
              else
 
              {
 
                     p++;
 
              }      

       }
 
}
 
 
 
 
 
 
 
 
 
 
 
 
 
77、鏈表節點結構如下:
 
struct STUDENT
 
{
 
long num;
 
float score;
 
STUDENT *pNext;
 
};
 
編寫實現將兩棵有序(按學號從小到大)的鏈表合併的函數,要求合併後的鏈表有序(按學號從小到大)
 
STUDENT *EmergeList(STUDENT *pHead1,STUDENT *pHead2)
 
{
 
//取小者爲表頭
 
STUDENT * pHead;
 
STUDENT *p1;
 
STUDENT *p2;
 
STUDENT *pCur;
 
STUDENT *pTemp;
 
 
 
if (pHead1->num<= pHead2->num)
 
{
 
pHead = pHead1;
 
p2 = pHead2;
 
p1=pHead1->pNext;
 
}
 
else
 
{
 
pHead = pHead2;
 
p1 = pHead1;
 
p2=pHead2->pNext;
 
}
 
pCur=pHead;
 
while(p1!=NULL&&p2!=NULL)
 
{
 
if(p2->num<p1->num)
 
{
 
pCur->pNext=p2;
 
p2=p2->pNext;
 
pCur=pCur->pNext;
 
}
 
else if(p2->num>p1->num)
 
{
 
pCur->pNext=p1;
 
p1=p1->pNext;
 
pCur=pCur->pNext;
 
}
 
else if(p2->num==p1->num)
 
{
 
pCur->pNext=p1;
 
p1=p1->pNext;
 
pCur=pCur->pNext;
 
pTemp= p2;
 
p2=p2->pNext;
 
delete pTemp;
 
pTemp = NULL;
 
}
 
}
 
if(NULL==p1)
 
{
 
pCur->pNext=p2;
 
}
 
else if(NULL==p2)
 
{
 
pCur->pNext=p1;
 
}
 
return pHead;
 
}
 
 
 
78、封裝CMyString類,要求聲明和實現分開,聲明見MyString.h,該類的聲明可以添加內容,完成STLTest文件夾下main文件的要求。
 
 
 
參見STLTest Answer文件夾
 
 
 
79.請你分別畫出OSI的七層網絡結構圖和TCP/IP的五層結構圖。
 
80.請你詳細地解釋一下IP協議的定義,在哪個層上面?主要有什麼作用?TCP與UDP呢?
 
81.請問交換機和路由器各自的實現原理是什麼?分別在哪個層次上面實現的?
 
82.請問C++的類和C裏面的struct有什麼區別?
 
83.全局變量和局部變量有什麼區別?是怎麼實現的?操作系統和編譯器是怎麼知道的?
 
 
 
84. 非C++內建型別 A 和 B,在哪幾種情況下B能隱式轉化爲A?[C++中等
 
a. class B : public A { ……} // B公有繼承自A,可以是間接繼承的
 
b. class B { operator A( ); } // B實現了隱式轉化爲A的轉化
 
c. class A { A( const B& ); } // A實現了non-explicit的參數爲B(可以有其他帶默認值的參數)構造函數
 
d. A& operator= ( const A& ); // 賦值操作,雖不是正宗的隱式類型轉換,但也可以勉強算一個
 
 
 
85. 以下代碼中的兩個sizeof用法有問題嗎?[C易]
 
void UpperCase( char str[] ) // 將 str 中的小寫字母轉換成大寫字母
 
{
 
for( size_t i=0; i<sizeof(str)/sizeof(str[0]); ++i )
 
if( ‘a’<=str[i] && str[i]<=’z’ )
 
str[i] -= (‘a’-'A’ );
 
}
 
char str[] = “aBcDe”;
 
cout << “str字符長度爲: ” << sizeof(str)/sizeof(str[0]) << endl;
 
UpperCase( str );
 
cout << str << endl;
 
86. 以下代碼有什麼問題?[C難]
 
 
 
void char2Hex( char c ) // 將字符以16進製表示
 
{
 
char ch = c/0×10 + ’0′; if( ch > ’9′ ) ch += (‘A’-’9′-1);
 
char cl = c%0×10 + ’0′; if( cl > ’9′ ) cl += (‘A’-’9′-1);
 
cout << ch << cl << ‘ ‘;
 
}
 
char str[] = “I love 中國”;
 
for( size_t i=0; i<strlen(str); ++i )
 
char2Hex( str[i] );
 
cout << endl;
 
 
 
87. 以下代碼有什麼問題?[C++易]
 
struct Test
 
{
 
Test( int ) {}
 
Test() {}
 
void fun() {}
 
};
 
void main( void )
 
{
 
Test a(1);
 
a.fun();
 
Test b();
 
b.fun();
 
}
 
 
 
 
 
88. 以下代碼有什麼問題?[C++易]
 
cout << (true?1:”1″) << endl;
 
 
 
 
 
89. 以下代碼能夠編譯通過嗎,爲什麼?[C++易]
 
 
 
unsigned int const size1 = 2;
 
char str1[ size1 ];
 
unsigned int temp = 0;
 
cin >> temp;
 
unsigned int const size2 = temp;
 
char str2[ size2 ];
 
 
 
90. 以下代碼中的輸出語句輸出0嗎,爲什麼?[C++易]
 
 
 
struct CLS
 
{
 
int m_i;
 
CLS( int i ) : m_i(i) {}
 
CLS()
 
{
 
CLS(0);
 
}
 
};
 
CLS obj;
 
cout << obj.m_i << endl;
 
 
 
 
 
91. C++中的空類,默認產生哪些類成員函數?[C++易]
 
 
 
答:
 
class Empty
 
{
 
public:
 
Empty();                             // 缺省構造函數
 
Empty( const Empty& );               // 拷貝構造函數
 
~Empty();                            // 析構函數
 
Empty& operator=( const Empty& ); // 賦值運算符
 
Empty* operator&();                  // 取址運算符
 
const Empty* operator&() const;      // 取址運算符 const
 
};
 
 
 
 
 
92. 以下兩條輸出語句分別輸出什麼?[C++難]
 
 
 
float a =1.0f;
 
cout << (int)a << endl;
 
cout << (int&)a << endl;
 
cout << boolalpha << ( (int)a == (int&)a ) << endl; // 輸出什麼?
 
float b =0.0f;
 
cout << (int)b << endl;
 
cout << (int&)b << endl;
 
cout << boolalpha << ( (int)b == (int&)b ) << endl; // 輸出什麼?
 
 
 
93. 以下反向遍歷array數組的方法有什麼錯誤?[STL易]
 
vector array;
 
array.push_back( 1 );
 
array.push_back( 2 );
 
array.push_back( 3 );
 
for( vector::size_type i=array.size()-1; i>=0; –i ) // 反向遍歷array數組
 
{
 
cout << array[i] << endl;
 
}
 
 
 
 
 
94. 以下代碼有什麼問題?[STL易]
 
typedef vector IntArray;
 
IntArray array;
 
array.push_back( 1 );
 
array.push_back( 2 );
 
array.push_back( 2 );
 
array.push_back( 3 );
 
// 刪除array數組中所有的2
 
for( IntArray::iterator itor=array.begin(); itor!=array.end(); ++itor )
 
{
 
if( 2 == *itor ) array.erase( itor );
 
}
 
 
 
95. 寫一個函數,完成內存之間的拷貝。[考慮問題是否全面]
 
 
 
答:
 
 
 
void* mymemcpy( void *dest, const void *src, size_t count )
 
{
 
char* pdest = static_cast<char*>( dest );
 
const char* psrc = static_cast<const char*>( src );
 
if( pdest>psrc && pdest<psrc+cout ) 能考慮到這種情況就行了
 
{
 
for( size_t i=count-1; i!=-1; –i )
 
pdest[i] = psrc[i];
 
}
 
else
 
{
 
for( size_t i=0; i<count; ++i )
 
pdest[i] = psrc[i];
 
}
 
return dest;
 
}
 
 
 
int main( void )
 
{
 
char str[] = “0123456789″;
 
mymemcpy( str+1, str+0, 9 );
 
cout << str << endl;
 
system( “Pause” );
 
return 0;
 
}
 
 
 
華爲C/C++筆試題(附答案)2008年02月15日星期五 18:001.寫出判斷ABCD四個表達式的是否正確, 若正確, 寫出經過表達式中 a的值(3分)
 
96.int a = 4;
 
(A)a += (a++); (B) a += (++a) ;(C) (a++) += a;(D) (++a) += (a++);
 
a = ?
 
答:C錯誤,左側不是一個有效變量,不能賦值,可改爲(++a) += a;
 
改後答案依次爲9,10,10,11
 
 
 
97.某32位系統下, C++程序,請計算sizeof 的值(5分).
 
char str[] = “http://www.ibegroup.com/”
 
char *p = str ;
 
int n = 10;
 
請計算
 
sizeof (str ) = ?(1)
 
sizeof ( p ) = ?(2)
 
sizeof ( n ) = ?(3)
 
void Foo ( char str[100]){
 
請計算
 
sizeof( str ) = ?(4)
 
}
 
void *p = malloc( 100 );
 
請計算
 
sizeof ( p ) = ?(5)
 
答:(1)17 (2)4 (3) 4 (4)4 (5)4
 
 
 
98. 回答下面的問題. (4分)
 
(1).頭文件中的 ifndef/define/endif 幹什麼用?預處理
 
答:防止頭文件被重複引用
 
(2). #i nclude 和 #i nclude “filename.h” 有什麼區別?
 
答:前者用來包含開發環境提供的庫頭文件,後者用來包含自己編寫的頭文件。
 
(3).在C++ 程序中調用被 C 編譯器編譯後的函數,爲什麼要加 extern “C”聲明?
 
答:函數和變量被C++編譯後在符號庫中的名字與C語言的不同,被extern “C”修飾的變
 
量和函數是按照C語言方式編譯和連接的。由於編譯後的名字不同,C++程序不能直接調
 
用C 函數。C++提供了一個C 連接交換指定符號extern“C”來解決這個問題。
 
(4). switch()中不允許的數據類型是?
 
答:實型
 
 
 
99. 回答下面的問題(6分)
 
(1).Void GetMemory(char **p, int num){
 
*p = (char *)malloc(num);
 
}
 
void Test(void){
 
char *str = NULL;
 
GetMemory(&str, 100);
 
strcpy(str, “hello”);
 
printf(str);
 
}
 
請問運行Test 函數會有什麼樣的結果?
 
答:輸出“hello”
 
(2). void Test(void){
 
char *str = (char *) malloc(100);
 
strcpy(str, “hello”);
 
free(str);
 
if(str != NULL){
 
strcpy(str, “world”);
 
printf(str);
 
}
 
}
 
請問運行Test 函數會有什麼樣的結果?
 
答:輸出“world”
 
 
 
100. char *GetMemory(void){
 
char p[] = “hello world”;
 
return p;
 
}
 
void Test(void){
 
char *str = NULL;
 
str = GetMemory();
 
printf(str);
 
}
 
請問運行Test 函數會有什麼樣的結果?
 
答:無效的指針,輸出不確定

101. 編寫strcat函數(6分)
 
已知strcat函數的原型是char *strcat (char *strDest, const char *strSrc);
 
其中strDest 是目的字符串,strSrc 是源字符串。
 
(1)不調用C++/C 的字符串庫函數,請編寫函數 strcat
 
答:
 
VC源碼:
 
char * __cdecl strcat (char * dst, const char * src)
 
{
 
char * cp = dst;
 
while( *cp )
 
cp++; /* find end of dst */
 
while( *cp++ = *src++ ) ; /* Copy src to end of dst */
 
return( dst ); /* return dst */
 
}
 
(2)strcat能把strSrc 的內容連接到strDest,爲什麼還要char * 類型的返回值?
 
答:方便賦值給其他變量
 
 
 
102.MFC中CString是類型安全類麼?
 
答:不是,其它數據類型轉換到CString可以使用CString的成員函數Format來轉換
 
 
 
103.C++中爲什麼用模板類。
 
答:(1)可用來創建動態增長和減小的數據結構
 
(2)它是類型無關的,因此具有很高的可複用性。
 
(3)它在編譯時而不是運行時檢查數據類型,保證了類型安全
 
(4)它是平臺無關的,可移植性
 
(5)可用於基本數據類型
 
 
 
104.CSingleLock是幹什麼的。
 
答:同步多個線程對一個數據類的同時訪問
 
 
 
105.NEWTEXTMETRIC 是什麼。
 
答:物理字體結構,用來設置字體的高寬大小
 
 
 
106.程序什麼時候應該使用線程,什麼時候單線程效率高。
 
答:1.耗時的操作使用線程,提高應用程序響應
 
2.並行操作時使用線程,如C/S架構的服務器端併發線程響應用戶的請求。
 
3.多CPU系統中,使用線程提高CPU利用率
 
4.改善程序結構。一個既長又複雜的進程可以考慮分爲多個線程,成爲幾個獨立或半獨
 
立的運行部分,這樣的程序會利於理解和修改。
 
其他情況都使用單線程。
 
 
 
107.Windows是內核級線程麼。
 
答:見下一題
 
 
 
108.Linux有內核級線程麼。
 
答:線程通常被定義爲一個進程中代碼的不同執行路線。從實現方式上劃分,線程有兩
 
種類型:“用戶級線程”和“內核級線程”。 用戶線程指不需要內核支持而在用戶程序
 
中實現的線程,其不依賴於操作系統核心,應用進程利用線程庫提供創建、同步、調度
 
和管理線程的函數來控制用戶線程。這種線程甚至在象 DOS 這樣的操作系統中也可實現
 
,但線程的調度需要用戶程序完成,這有些類似 Windows 3.x 的協作式多任務。另外一
 
種則需要內核的參與,由內核完成線程的調度。其依賴於操作系統核心,由內核的內部
 
需求進行創建和撤銷,這兩種模型各有其好處和缺點。用戶線程不需要額外的內核開支
 
,並且用戶態線程的實現方式可以被定製或修改以適應特殊應用的要求,但是當一個線
 
程因 I/O 而處於等待狀態時,整個進程就會被調度程序切換爲等待狀態,其他線程得不
 
到運行的機會;而內核線程則沒有各個限制,有利於發揮多處理器的併發優勢,但卻佔
 
用了更多的系統開支。
 
Windows NT和OS/2支持內核線程。Linux 支持內核級的多線程
 
 
 
109.C++中什麼數據分配在棧或堆中,New分配數據是在近堆還是遠堆中?
 
答:棧: 存放局部變量,函數調用參數,函數返回值,函數返回地址。由系統管理
 
堆: 程序運行時動態申請,new 和 malloc申請的內存就在堆上
 
 
 
110.使用線程是如何防止出現大的波峯。
 
答:意思是如何防止同時產生大量的線程,方法是使用線程池,線程池具有可以同時提
 
高調度效率和限制資源使用的好處,線程池中的線程達到最大數時,其他線程就會排隊
 
等候。
 
 
 
111.一般數據庫若出現日誌滿了,會出現什麼情況,是否還能使用?
 
答:只能執行查詢等讀操作,不能執行更改,備份等寫操作,原因是任何寫操作都要記
 
錄日誌。也就是說基本上處於不能使用的狀態。
 
 
 
112 SQL Server是否支持行級鎖,有什麼好處?
 
答:支持,設立封鎖機制主要是爲了對併發操作進行控制,對干擾進行封鎖,保證數據
 
的一致性和準確性,行級封鎖確保在用戶取得被更新的行到該行進行更新這段時間內不
 
被其它用戶所修改。因而行級鎖即可保證數據的一致性又能提高數據操作的迸發性。
 
113 關於內存對齊的問題以及sizof()的輸出
 
答:編譯器自動對齊的原因:爲了提高程序的性能,數據結構(尤其是棧)應該儘可能
 
地在自然邊界上對齊。原因在於,爲了訪問未對齊的內存,處理器需要作兩次內存訪問
 
;然而,對齊的內存訪問僅需要一次訪問。
 
 
 
114. int i=10, j=10, k=3; k*=i+j; k最後的值是?
 
答:60,此題考察優先級,實際寫成: k*=(i+j);,賦值運算符優先級最低
 
 
 
115.對數據庫的一張表進行操作,同時要對另一張表進行操作,如何實現?
 
答:將操作多個表的操作放入到事務中進行處理
 
 
 
116.TCP/IP 建立連接的過程?(3-way shake)
 
答:在TCP/IP協議中,TCP協議提供可靠的連接服務,採用三次握手建立一個連接。
 
第一次握手:建立連接時,客戶端發送syn包(syn=j)到服務器,並進入SYN_SEND狀
 
態,等待服務器確認;
 
第二次握手:服務器收到syn包,必須確認客戶的SYN(ack=j+1),同時自己也發送一個
 
SYN包(syn=k),即SYN+ACK包,此時服務器進入SYN_RECV狀態;
 
第三次握手:客戶端收到服務器的SYN+ACK包,向服務器發送確認包ACK(ack=k+1)
 
,此包發送完畢,客戶端和服務器進入ESTABLISHED狀態,完成三次握手。
 
 
 
117.ICMP是什麼協議,處於哪一層?
 
答:Internet控制報文協議,處於網絡層(IP層)
 
 
 
118.觸發器怎麼工作的?
 
答:觸發器主要是通過事件進行觸發而被執行的,當對某一表進行諸如UPDATE、 INSERT
 
、 DELETE 這些操作時,數據庫就會自動執行觸發器所定義的SQL 語句,從而確保對數
 
據的處理必須符合由這些SQL 語句所定義的規則。
 
 
 
119.winsock建立連接的主要實現步驟?
 
答:服務器端:socker()建立套接字,綁定(bind)並監聽(listen),用accept()
 
等待客戶端連接。
 
客戶端:socker()建立套接字,連接(connect)服務器,連接上後使用send()和recv(
 
),在套接字上寫讀數據,直至數據交換完畢,closesocket()關閉套接字。
 
服務器端:accept()發現有客戶端連接,建立一個新的套接字,自身重新開始等待連
 
接。該新產生的套接字使用send()和recv()寫讀數據,直至數據交換完畢,closesock
 
et()關閉套接字。
 
 
 
120.動態連接庫的兩種方式?
 
答:調用一個DLL中的函數有兩種方法:
 
1.載入時動態鏈接(load-time dynamic linking),模塊非常明確調用某個導出函數
 
,使得他們就像本地函數一樣。這需要鏈接時鏈接那些函數所在DLL的導入庫,導入庫向
 
系統提供了載入DLL時所需的信息及DLL函數定位。
 
2.運行時動態鏈接(run-time dynamic linking),運行時可以通過LoadLibrary或Loa
 
dLibraryEx函數載入DLL。DLL載入後,模塊可以通過調用GetProcAddress獲取DLL函數的
 
出口地址,然後就可以通過返回的函數指針調用DLL函數了。如此即可避免導入庫文件了
 
。
 
 
 
121.IP組播有那些好處?
 
答:Internet上產生的許多新的應用,特別是高帶寬的多媒體應用,帶來了帶寬的急劇
 
消耗和網絡擁擠問題。組播是一種允許一個或多個發送者(組播源)發送單一的數據包
 
到多個接收者(一次的,同時的)的網絡技術。組播可以大大的節省網絡帶寬,因爲無
 
論有多少個目標地址,在整個網絡的任何一條鏈路上只傳送單一的數據包。所以說組播
 
技術的核心就是針對如何節約網絡資源的前提下保證服務質量。
 
 
 
122. 以下代碼中的兩個sizeof用法有問題嗎?[C易]
 
void UpperCase( char str[] ) // 將 str 中的小寫字母轉換成大寫字母
 
{
 
for( size_t i=0; i<sizeof(str)/sizeof(str[0]); ++i )
 
if( ‘a’<=str[i] && str[i]<=’z’ )
 
str[i] -= (‘a’-'A’ );
 
}
 
char str[] = “aBcDe”;
 
cout << “str字符長度爲: ” << sizeof(str)/sizeof(str[0]) << endl;
 
UpperCase( str );
 
cout << str << endl;
 
 
 
答:函數內的sizeof有問題。根據語法,sizeof如用於數組,只能測出靜態數組的大小,無法檢測動態分配的或外部數組大小。函數外的str是一個靜態定義的數組,因此其大小爲
 
 
 
123,函數內的str實際只是一個指向字符串的指針,沒有任何額外的與數組相關的信息,因此sizeof作用於上只將其當指針看,一個指針爲4個字節,因此返回4。
 
 
 
一個32位的機器,該機器的指針是多少位
 
指針是多少位只要看地址總線的位數就行了。80386以後的機子都是32的數據總線。所以指針的位數就是4個字節了。
 
 
 
124.
 
main()
 
{
 
int a[5]={1,2,3,4,5};
 
int *ptr=(int *)(&a+1);
 
 
 
printf(“%d,%d”,*(a+1),*(ptr-1));
 
}
 
輸出: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].
 
 
 
 
 
125.請問以下代碼有什麼問題:
 
int  main()
 
{
 
char a;
 
char *str=&a;
 
strcpy(str,”hello”);
 
printf(str);
 
return 0;
 
}
 
沒有爲str分配內存空間,將會發生異常
 
問題出在將一個字符串複製進一個字符變量指針所指地址。雖然可以正確輸出結果,但因爲越界進行內在讀寫而導致程序崩潰。
 
 
 
char* s=”AAA”;
 
printf(“%s”,s);
 
s[0]=’B';
 
printf(“%s”,s);
 
有什麼錯?
 
“AAA”是字符串常量。s是指針,指向這個字符串常量,所以聲明s的時候就有問題。
 
cosnt char* s=”AAA”;
 
然後又因爲是常量,所以對是s[0]的賦值操作是不合法的。
 
 
 
126、關鍵字volatile有什麼含意?並舉出三個不同的例子?
 
提示編譯器對象的值可能在編譯器未監測到的情況下改變。
 
 
 
127、將樹序列化 轉存在數組或 鏈表中
 
 
 
128.下面哪個實體不是SIP協議定義的(A)。
 
A )MGC    B)UA     C)proxy     D)Redirector
 
UA = User Agent 用戶代理,指客戶端的協議棧
 
PROXY = SIP Proxy ,指SIP服務器
 
Redirector = 重定向模塊。一般用於跨服務器通訊
 
129.VOIP中本端與對端呼叫接通後,將通話轉接到第三方稱之爲(C)。
 
A)呼叫轉接   B)呼叫前轉   C)呼叫轉移   D)三方通話
 
跟普通電話相同,A,B都是沒有接通前就把呼叫轉接。D是指三方同時在通話。
 
130.VOIP的主要優點是(D)
 
A)價格便宜並且能爲客戶提供更好的增值服務。
 
B)語音質量比傳統的PSTN電話好。
 
C)通話的安全性和可靠性有更高的保障。
 
D)不需要服務提供商就可以使用。
 
音質,可靠性是傳統電話好。這題的問題在於,增值服務是指什麼?如是SP則VOIP不支持。還是服務器提供商是指什麼?VOIP需要服務器。
 
131.下面哪個技術不屬於語音處理技術(D)
 
A)靜音檢測
 
B)分組丟失補償
 
C)同聲消除
 
D)網路穿越
 
D是網絡傳輸的問題,主要是穿透NAT網關。特別是比較複雜的網絡。
 
132.SIP協議是使用下面哪種方式編解碼的()
 
A)ASN.1     B)BER      C)ABNF    D)PER
 
 
 
網絡應用
 
133.在不同網絡中MTU會發生變化,由於MTU的變化,會導致那些值也相應發生變化(A)
 
A)IP總長度字段
 
B)TCP MSS字段
 
C)UDP長度字段
 
D)TCP長度字段
 
待查,MTU變化會讓IP分片或重組。因此變化就是IP
 
134.下列關於TCP和UDP的正確的說法是(C)
 
A)TCP實時性比UDP好
 
B)TCP比UDP效率高
 
C)TCP首部比UDP的首部長
 
D)TCP安全性比UDP高
 
實時性,效率。安全性,TCP不見得比UDP高
 
135.一個套接口應該匹配(D)
 
A)源目標IP
 
B)源目標IP端口
 
C)目標IP和目標端口
 
D)本地IP和本地端口
 
SOCKET相當一IP連接上用端口標識隊列
 
136.TCP服務器出現異常並馬上重啓,通常會出現那些情況()
 
A)socket調用失敗
 
B)bind調用失敗
 
C)listen調用失敗
 
D)select調用失敗
 
此題有問題,一般軟件很難自動重啓。而TCP服務器可以在任何一個階段出問題,上述哪一個都能出現,這個本意應該是指Select.
 
底層開發
 
137.在一臺以字節爲最小存儲單位的機器上,如果把0×12345678寫到從0×0000開始的地址上,下列關於big—endian和little—enddian說法正確的是(B)
 
A)在big—endian模式下,地址0×0000到0×0003存儲的數據依次爲:0×56,0×78,0×12,0×34
 
B)在big—endian模式下,地址0×0000到0×0003存儲的數據依次爲:0×12,0×34,0×56,0×78
 
C)在little—endian模式下,地址0×0000到0×0003存儲的數據依次爲:0×34,0×12,0×78,0×56
 
D)在little—endian模式下,地址0×0000到0×0003存儲的數據依次爲:0×56,0×78,0×12,0×34
 
 
 
 
 
138.以下關於交叉編譯器概述正確的是(A)
 
A)交叉編譯器一般按照CPU類型分類,不同的CPU就有不同的交叉編譯器
 
B)交叉編譯器的速度比其他編譯器的速度要快
 
C)linux開發環境中的交叉編譯器不是gcc編譯器
 
D)交叉編譯器編譯出來的目標文件一般也能在開發機(普通PC)上運行
 
139.以下關於linux下中斷的說法正確的是()
 
A)中斷只能由硬件產生
 
B)中斷服務例程不能運行參數傳遞
 
C)中斷服務例程可以在函數結束的時候返回一個值
 
D)中斷服務例程是不可中斷的
 
D,B?
 
140.以下關於linux下系統調用的說法錯誤的是()
 
A)應用程序通過系統調用訪問內核
 
B)每個系統調用都有一個唯一的系統調用號
 
C)用戶可以定製自己的系統調用
 
D)
 
可能是A,系統調用在內核執行。但這裏訪問比較模糊。
 
141.關於SPI說法正確的是()
 
A)SPI工作在全雙工模式下
 
B)
 
C)
 
D)SPI接口一般工作在主從模式下
 
 
 
C語言
 
142.Char Test[10];char *pTest=test;問:&Test在數值上等於(A)
 
A)Test    B) Test[0]    C)&pTest     D)符號表某個符號的地址
 
&Test相當於二維指針首指針,TEST是一維的首指針
 
143.在順序表{3,6,8,10,12,15,16,18,21,25,30}中,用二分法查找關鍵碼值11,所雪的關鍵碼比較次數爲()B?
 
A)2   B)3   C)4     D)5
 
144.單鏈表中每個結點中包括一個指針link,它向該結點,現要將指針q指向的新結點放到指針p指向的單鏈表接點之後,下面的操作序列中哪一個是正確的(C)
 
A)q:=p^.link;p^.link:=q^:link
 
B)p^.link:=q^.link;q:=p^.link
 
C)q^.link:=p^.link;p^.link:=q
 
D)p^.link:=q;q^.link:=p^.link
 
145.以下敘述正確的是(C)
 
A)在C程序中,main函數必須位於程序的最前面
 
B)C程序的每行中只能寫一條語句
 
C)C語言本身沒有輸入輸出語句
 
D)在對一個C程序進行編譯的過程中,可發現註釋中的拼寫錯誤
 
146.有以下程序
 
Main()
 
{
 
Char a[]=”programming”,b[]=”language”;
 
Char *p1,*p2;
 
Int i;
 
P1=a;p2=b;
 
For(i=0;i<7;i++)
 
If(*(p1+i)==*(p2+i))
 
Printf(“%c”,*(p1+i));
 
)
 
打印出什麼()
 
 
 
147.請簡述以下兩個for循環的優缺點(6分)
 
 
 


// 第一個
 
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較大時,效率較高
 
缺點:
 
每一個循環都要做一次if判斷
 
 
 
 
 
優點:
 
當N較小時,效率較高
 
缺點:
 
循環次數較多
 
 
 

 
 
 
 
 
 
148.位運算:給定一個整型變量a,(1)給bit3置數(2)清除bit3(6分)
 
a|=(0×1<<3);
 
a&=~(0×1<<3);
 
149.評述下面的代碼(6分)
 
Main()
 
{
 
Int a[100];
 
Int *p;
 
P=((unsigned int *)a+1);
 
Printf(“0x%x”,*p);
 
}
 
1.數組沒有賦初值,
 
2.指針類型轉換不一致
 
3..打印一個未賦值的整數值,p=a[1]
 
 
 
#include <stdio.h>
 
main()
 
{
 
int a[100]={1,2,3};
 
unsigned int *p;
 
p=((unsigned int *)a+1);
 
printf(“%x,%x\n”,a,p);
 
printf(“0x%x”,*p);
 
getchar();
 
}
 
 
 
 
 
150.編程題;(10分)
 
從鍵盤輸入一組字符;
 
字母按升序排列;其餘的字符按升序排列
 
字母放前,其餘的放後
 
 
 
例如:輸入:_@AB-@ab  結果:ABab-@@_

.簡述需求分析的過程和意義
 
 
 
152.網狀、層次數據模型與關係數據模型的最大的區別是什末
 
 
 
153.軟件質量保證體系是什末 國家標準中與質量保證管理相關的幾個標準是什末 編號和全稱是什末號和全稱是什末
 
 
 
153文件格式系統有哪幾種類型?分別說說win95、win98、winMe、w2k、winNT、winXP分別支持那些文件系統
 
 
 
154.我現在有個程序,發現在WIN98上運行得很慢,怎麼判別是程序存在問題還是軟硬件系統存在問題?
 155.有關P2P點對點文件傳輸的原理
 
 
 
156.一臺計算機的IP是192.168.10.71子網掩碼255.255.255.64與192.168.10.201是同一局域網嗎?
 157.internet中e-mail協儀,IE的協儀,NAT是什麼,有什麼好處,能帶來什麼問題?DNS是什麼,它是如何工作的?
 158.PROXY是如何工作的?
 169.win2k系統內AT命令完成什麼功能,Messenger服務是做什麼,怎麼使用?
 170進程,線程的定義及區別
 171,32位操作系統內,1進程地址空間多大,進程空間與物理內存有什麼關係?
 172.網絡攻擊常用的手段,防火牆如何保證安全.
 173.如何配靜態IP,如何測網絡內2臺計算機通不通,PING一次返幾個數據包?
 174.WIN9X與WINNT以上操作系統有”服務”嗎,服務是什麼,如何停止服務?
 175.AD在WIN2KSERVER上建需什麼文件格式,AD是什麼?XP多用戶下”註銷”與”切換”的區別.
 
176.UDP可以跨網段發送嗎?
 
177.最簡單的確認遠程計算機(win2K以上)某個監聽端口是正常建立的?
 
178. 找錯
 
 
 
void test1()
 
{
 
char string[10];
 
char* str1=”0123456789″;
 
strcpy(string, str1);
 
}
 
 
 
答:表面上並且編譯都不會錯誤。但如果string數組原意表示的是字符串的話,那這個賦值就沒有達到意圖。最好定義爲char string[11],這樣最後一個元素可以存儲字符串結尾符’\0′;
 
 
 
 
 
void test2()
 
{
 
char string[10], str1[10];
 
for(int I=0; I<10;I++)
 
{
 
str1[I] =’a';
 
}
 
strcpy(string, str1);
 
}
 
 
 
答:strcpy使用錯誤,strcpy只有遇到字符串末尾的’\0′纔會結束,而str1並沒有結尾標誌,導致strcpy函數越界訪問,不妨讓str1[9]=’\0′,這樣就正常了。
 
 
 
 
 
void test3(char* str1)
 
{
 
char string[10];
 
if(strlen(str1)<=10)
 
{
 
strcpy(string, str1);
 
}
 
}
 
 
 
答:這又會出現第一道改錯題的錯誤了。strlen(str1)算出來的值是不包含結尾符’\0′的,如果str1剛好爲10個字符+1結尾符,string就得不到結尾符了。可將strlen(str1)<=10改爲strlen(str1)<10。
 
 
 
179. 找錯
 
 
 
#define MAX_SRM 256
 
 
 
DSN get_SRM_no()
 
{
 
static int SRM_no;
 
int I;
 
for(I=0;I<MAX_SRM;I++,SRM_no++)
 
{
 
SRM_no %= MAX_SRM;
 
if(MY_SRM.state==IDLE)
 
{
 
break;
 
}
 
}
 
if(I>=MAX_SRM)
 
return (NULL_SRM);
 
else
 
return SRM_no;
 
}
 
 
 
答:我不知道這段代碼的具體功能,但明顯有兩個錯誤
 
1,SRM_no沒有賦初值
 
2,由於static的聲明,使該函數成爲不可重入(即不可預測結果)函數,因爲SRM_no變量放在程序的全局存儲區中,每次調用的時候還可以保持原來的賦值。這裏應該去掉static聲明。
 
 
 
180. 寫出程序運行結果
 
 
 
int sum(int a)
 
{
 
auto int c=0;
 
static int b=3;
 
c+=1;
 
b+=2;
 
return(a+b+c);
 
}
 
void main()
 
{
 
int I;
 
int a=2;
 
for(I=0;I<5;I++)
 
{
 
printf(“%d,”, sum(a));
 
}
 
}
 
 
 
答:8,10,12,14,16
 
該題比較簡單。只要注意b聲明爲static靜態全局變量,其值在下次調用時是可以保持住原來的賦值的就可以。
 
 
 
 
 
 
 
181.
 
 
 
int func(int a)
 
{
 
int b;
 
switch(a)
 
{
 
case 1: b=30;
 
case 2: b=20;
 
case 3: b=16;
 
default: b=0;
 
}
 
return b;
 
}
 
 
 
則func(1)=?
 
答:func(1)=0,因爲沒有break語句,switch中會一直計算到b=0。這是提醒我們不要忘了break。呵呵。
 
 
 
182:
 
 
 
int a[3];
 
a[0]=0; a[1]=1; a[2]=2;
 
int *p, *q;
 
p=a;
 
q=&a[2];
 
 
 
則a[q-p]=?
 
答:a[q-p]=a[2]=2;這題是要告訴我們指針的運算特點
 
 
 
183.
 
定義 int **a[3][4], 則變量佔有的內存空間爲:_____
 
答:此處定義的是指向指針的指針數組,對於32位系統,指針佔內存空間4字節,因此總空間爲3×4×4=48。
 
 
 
184.
 
編寫一個函數,要求輸入年月日時分秒,輸出該年月日時分秒的下一秒。如輸入2004年12月31日23時59分59秒,則輸出2005年1月1日0時0分0秒。
 
答:
 
 
 
/*輸入年月日時分秒,輸出年月日時分秒的下一秒,輸出仍然在原內存空間*/
 
bool NextMinute(int *nYear,int *nMonth,int *nDate,int *nHour,int *nMinute,int *nSecond)
 
{
 
if(*nYear<0 || *nMonth>12 || *nMonth<0 || *nHour>23 || *nHour<0 || *nMinute<0 || *nMinute>59 || *nSecond<0 || *nSecond>59) return false;
 
int nDays;
 
switch(*nMonth)
 
{
 
case 1:
 
case 3:
 
case 5:
 
case 7:
 
case 8:
 
case 10:
 
case 12:
 
nDays=31;
 
break;
 
case 2:// 判斷閏年
 
if(*nYear%400==0||*nYear%100!=0&&*nYear%4==0)
 
{
 
nDays=29;
 
}
 
else
 
{
 
nDays=28;
 
}
 
break;
 
default:
 
nDays=30;
 
break;
 
}
 
if(*nDate<0 || *nDate>nDays) return false;
 
 
 
(*nSecond)++;  // 秒加1
 
if(*nSecond>=60)  // 秒滿60,做出特殊處理,下面時,日,月等類同
 
{
 
*nSecond=0;
 
(*nMinute)++;
 
if(*nMinute>=60)
 
{
 
*nMinute=0;
 
(*nHour)++;
 
if(*nHour>=24)
 
{
 
*nHour=0;
 
(*nDate)++;
 
if(*nDate>nDays)
 
{
 
*nDate=1;
 
(*nMonth)++;
 
if(*nMonth>12)
 
{
 
*nMonth=1;
 
(*nYear)++;
 
}
 
}
 
}
 
}
 
}
 
return true;
 
}
 
/*示例可運行代碼*/
 
void main()
 
{
 
int nYear=2004,nMonth=12,nDate=31,nHour=23,nMinute=59,nSecond=59;
 
bool res = NextMinute(&nYear,&nMonth,&nDate,&nHour,&nMinute,&nSecond);
 
if(res)
 
printf(“The result:%d-%d-%d %d:%d:%d”,nYear,nMonth,nDate,nHour,nMinute,nSecond);
 
else
 
printf(“Input error!\n”);
 
}
 
 
 
185. 寫一個函數,判定運算環境(16位以上字長)是little-endian還是big-endian
 
 
 
186. 操作系統的主要組成部分?
 
 
 
187.操作系統中進程調度策略有哪幾種?
 
 
 
188.進程間主要的通訊方式?
 
 
 
189.寫出進程的主要狀態?
 
 
 
190.以太網物理地址和IP地址轉換採用什麼協議?
 
 
 
191.IP地址的編碼分爲哪兩部分?
 
 
 
192.寫出以太網數據幀格式
 
 
 
/193.8031和8051的主要區別?
 
 
 
 
 
194.C++中的空類,默認產生哪些類成員函數?
 
 
 
 
 
分析以下程序的執行結果
 
#include<iostream.h>
 
class base
 
{
 
public:
 
base(){cout<< “constructing base class”<<endl;}
 
~base(){cout<<”destructing base class”<<endl;}
 
};
 
class subs:public base
 
{
 
public:
 
subs(){cout<<”constructing sub class”<<endl;}
 
~subs(){cout<<”destructing sub class”<<endl;}
 
};
 
void main()
 
{
 
subs s;
 
}
 
 
 
195.指出下面程序的錯誤
 
#define SIZE 5
 
struct String
 
{
 
char *pData;
 
};
 
void  main()
 
{
 
char *pData;
 
};
 
void  main()
 
{
 
char acValue1[SIZE]={‘H’,’E’,’L’,’L’,’O’};
 
char acValue2[SIZE]={‘W’,’O’,’L’,’D’};
 
struct String a,b,c;
 
a.pData=malloc(SIZE*sizeof(char));
 
memcpy(a.pData,acValuel,SIZE);
 
b.pData=malloc(SIZE*sizeof(char));
 
mempcpy(b.pData,acValue2,SIZE);
 
b=a;
 
free(a.pData);
 
c=b;
 
}
 
 
 
 
 
196.指出下面兩段程序的區別
 
【1】
 
main()
 
{
 
int loop=1;
 
int arr[10];
 
int i=0;
 
while(loop<5)
 
{
 
for(;i<=10;i++)
 
{
 
arr[i]=1;
 
}
 
loop++;
 
}
 
}
 
【2】
 
main()
 
{
 
int arr[10];
 
int loop=1;
 
int i=0;
 
while(loop<5)
 
{
 
for(i=0;i<=10;i++)
 
{
 
arr[i]=1;
 
}
 
loop++;
 
}
 
}
 
 
 
197.指出下面程序的錯誤(函數GetValue返回 unsigned char類型的值)
 
#define  MAXNUM  400;
 
unsigned char uclndex,uclnputVar,aucArray[MAXNUM];
 
for(ucIndx =0;ucIndex<=MAXNUM;ucIndex++)
 
{
 
aucArray[ucIndex]=aucArray[ucIndex]+1;
 
}
 
ucInputVar=GetValue();
 
for(ucIndex=0;ucIndex>(ucInputVar-1);ucIndex++)
 
{
 
aucArray[ucIndex]=aucArray[ucIndex]*2+1;
 
}
 
 
 
198.什麼是com和ActiveX,簡述DCOM。
 答:COM(Component Object Mode)即組件對象模型,是組件之間相互接口的規範。其作用是使各種軟件構件和應用軟件能夠用一種統一的標準方式進行交互。COM不是一種面向對象的語言,而是一種與源代碼無關的二進制標準。
 ActiveX是Microsoft提出的一套基於COM的構件技術標準,實際上是對象嵌入與煉接(OLE)的新版本。基於分佈式環境下的COM被稱作DCOM(Distribute COM,分佈式組件對象模型),它實現了COM對象與遠程計算機上的另一個對象之間直接進行交互。DCOM規範定義了分散對象創建和對象間通信的機制,DCOM是ActiveX的基礎,因爲ActiveX主要是針對Internet應用開發(相比OLE)的技術,當然也可以用於普通的桌面應用程序。
 
199.列出3個常用網絡協議使用的端口。
 答:HTTP協議用80端口,FTP協議用21端口,POP3協議用110端口
 
 
 
199  什麼是ODBC?
 答:ODBC(Open Database Connectivity,開放數據庫互連)是微軟公司開放服務結構(WOSA,Windows Open Services Architecture)中有關數據庫的一個組成部分,它建立了一組規範,並提供了一組對數據庫訪問的標準API(應用程序編程接口)。ODBC的最大優點是能以統一的方式(用它提供的API訪問數據庫)處理所有的數據庫。
 
200  結構化編程和goto語句的區別和關係?
 答:結構化編程設計思想採用了模塊分解與功能抽象和自頂向下、分而治之的方法,從而有效地將一個較複雜的程序系統設計任務分解成許多易於控制和處理的子程序,便於開發和維護。goto語句可以實現無條件跳轉,改變程序流向,破壞結構化編程設計風格。但goto語句在結構化編程中並非不可使用,只是要受到限制的使用

199  MFC中SendMessage和PostMessage的區別?
 答:PostMessage 和SendMessage的區別主要在於是否等待應用程序做出消息處理。PostMessage只是把消息放入隊列,然後繼續執行;而SendMessage必須等待應用程序處理消息後才返回繼續執行。這兩個函數的返回值也不同,PostMessage的返回值表示PostMessage函數執行是否正確,而SendMessage的返回值表示其他程序處理消息後的返回值。
 202.改錯
 #include
 #include
 class CBuffer
 {
 char * m_pBuffer;
 int m_size;
 public:
 CBuffer()
 {
 m_pBuffer=NULL;
 }
 ~CBuffer()
 {
 Free();
 }
 void Allocte(int size) (3) {
 m_size=size;
 m_pBuffer= new char[size];
 }
 private:
 void Free()
 {
 if(m_pBuffer!=NULL)
 {
 delete m_pBuffer;
 m_pBuffer=NULL;
 }
 }
 public:
 void SaveString(const char* pText) const
 {
 strcpy(m_pBuffer, pText);
 }
 char* GetBuffer() const
 {
 return m_pBuffer;
 }
 };
 
void main (int argc, char* argv[])
 {
 CBuffer buffer1;
 buffer1.SaveString(“Microsoft”);
 printf(buffer1.GetBuffer());
 }
 
答:改正後
 主要改正SaveString函數
 將
 void SaveString(const char* pText) const
 {
 strcpy(m_pBuffer, pText);
 }
 改爲
 void SaveString(const char* pText) (1)
 {
 Allocte(strlen(pText)+1); (2)
 strcpy(m_pBuffer, pText);
 }
 原因:
 (1) const成員函數表示不會修改數據成員,而SaveString做不到,去掉const聲明
 (2) m_pBuffer指向NULL,必須用Allocte分配空間才能賦值。
 (3) 另外需要將Allocte成員函數聲明爲私有成員函數更符合實際
 
203.下來程序想打印“Welcome MSR Asia”,改正錯誤
 #include
 #include
 char * GetName (void)
 {
 //To return “MSR Asia” String
 char name[]=”MSR Asia”;
 return name;
 }
 void main(int argc, char* argv[])
 {
 char name[32];
 //Fill in zeros into name
 for(int i=0;i<=32;i++)
 {
 name[i]=’\0′;
 }
 //copy “Welcome” to name
 name=”Welcome”;
 //Append a blank char
 name[8]=” “;
 //Append string to name
 strcat(name,GetName());
 //print out
 printf(name);
 }
 
答:改正後爲
 #include
 #include
 char * GetName (void)
 {
 //To return “MSR Asia” String
 //char name[]=”MSR Asia”; (1)
 char *name=(char *)malloc(strlen(“MSR Asia”)+1);
 strcpy(name,”MSR Asia”);
 return name;
 }
 void main(int argc, char* argv[])
 {
 char name[32];
 //Fill in zeros into name
 for(int i=0;i<=32;i++)
 {
 name[i]=’\0′;
 }
 //copy “Welcome” to name
 //name=”Welcome”; (2)
 strcat(name,”Welcome “);
 //Append a blank char
 // name[8]=’ ‘; (3)
 //Append string to name
 char *p=GetName(); (4)
 strcat(name,p);
 free (p);
 //print out
 printf(name);
 }
 原因:(1)在函數內部定義的變量在函數結束時就清空了,必須動態分配內存
 (2)字符串賦值語句錯誤,應該用strcat
 (3)該語句無效,可去掉
 (4)定義一個指針指向動態分配的內存,用完後需用free語句釋放
 
 
 
 
 
204.寫出下面程序的輸出結果
 #include
 class A
 {
 public:
 void FuncA()
 {
 printf(“FuncA called\n”);
 }
 virtual void FuncB()
 {
 printf(“FuncB called\n”);
 }
 };
 
class B: public A
 {
 public:
 void FuncA()
 {
 A::FuncA();
 printf(“FuncAB called\n”);
 }
 virtual void FuncB()
 {
 printf(“FuncBB called\n”);
 }
 };
 
void main(void)
 {
 B b;
 A *pa;
 pa=&b;
 A *pa2=new A;
 b.FuncA(); (1)
 b.FuncB(); (2)
 pa->FuncA(); (3)
 pa->FuncB(); (4)
 pa2->FuncA(); (5)
 pa2->FuncB();
 delete pa2;
 }
 答:
 1.b.FuncA(); 輸出
 FuncA called
 FuncAB called
 2.b.FuncB();輸出
 FuncBB called
 上兩者好理解,直接調用類B的相應成員函數
 3.pa->FuncA();輸出
 FuncA called 調用類A的FuncA()
 4.pa->FuncB();輸出
 FuncBB called調用類B的FuncB(),原因是C++的動態決議機制,當基類函數聲明爲virtual時,指向派生類對象的基類指針來調用該函數會選擇派生類的實現,除非派生類沒有才調用基類的虛函數。還有一點注意的是:指向基類類型的指針可以指向基類對象也可以指向派生類對象,如pa=&b;
 5. pa2->FuncA();
 pa2->FuncB();輸出
 FuncA called
 FuncB called
 這也好理解,直接調用類A的相應成員函數
 
206.In the main() function, after ModifyString(text) is called, what’s the value of ‘text’?
 #include
 #include
 int FindSubString(char* pch)
 {
 int count=0;
 char* p1=pch;
 while(*p1!=’\0′)
 {
 if(*p1==p1[1]-1)
 {
 p1++;
 count++;
 }
 else
 {
 break;
 }
 }
 int count2=count;
 while(*p1!=’\0′)
 {
 if(*p1==p1[1]+1)
 {
 p1++;
 count2–;
 }
 else
 {
 break;
 }
 }
 if(count2==0)
 return count;
 return 0;
 }
 
void ModifyString(char* pText)
 {
 char* p1=pText;
 char* p2=p1;
 while(*p1!=’\0′)
 {
 int count=FindSubString(p1);
 if(count>0)
 {
 *p2++=*p1;
 sprintf(p2, “%I”, count);
 while(*p2!= ‘\0′)
 {
 p2++;
 }
 p1+=count+count+1;
 }
 else
 {
 *p2++=*p1++;
 }
 }
 }
 void main(void)
 {
 char text[32]=”XYBCDCBABABA”;
 ModifyString(text);
 printf(text);
 }
 答:我不知道這個結構混亂的程序到底想考察什麼,只能將最後運行結果寫出來是XYBCDCBAIBAAP
 
 
 
207. Programming (Mandatory)
 Linked list
 a. Implement a linked list for integers,which supports the insertafter (insert a node after a specified node) and removeafter (remove the node after a specified node) methods;
 b. Implement a method to sort the linked list to descending order.
 答:題目的意思是實現一個整型鏈表,支持插入,刪除操作(有特殊要求,都是在指定節點後進行操作),並寫一個對鏈表數據進行降序排序的方法。
 那我們不妨以一個線性鏈表進行編程。
 // 單鏈表結構體爲
 typedef struct LNode
 {
 int data;
 struct LNode *next;
 }LNode, *pLinkList;
 
// 單鏈表類
 class LinkList
 {
 private:
 pLinkList m_pList;
 int m_listLength;
 public:
 LinkList();
 ~LinkList();
 bool InsertAfter(int afternode, int data);//插入
 bool RemoveAfter(int removenode);//刪除
 void sort();//排序
 };
 
實現方法
 //insert a node after a specified node
 bool LinkList::InsertAfter(int afternode, int data)
 {
 LNode *pTemp = m_pList;
 int curPos = -1;
 if (afternode > m_listLength ) // 插入點超過總長度
 {
 return false;
 }
 while (pTemp != NULL) // 找到指定的節點
 {
 curPos++;
 if (curPos == afternode)
 break;
 pTemp = pTemp->next;
 }
 if (curPos != afternode) // 節點未尋到,錯誤退出
 {
 return false;
 }
 LNode *newNode = new LNode; // 將新節點插入指定節點後
 newNode->data = data;
 newNode->next = pTemp->next;
 pTemp->next = newNode;
 m_listLength++;
 return true;
 }
 
//remove the node after a specified node
 bool LinkList::RemoveAfter(int removenode)
 {
 LNode *pTemp = m_pList;
 int curPos=-1;
 if (removenode > m_listLength) // 刪除點超過總長度
 {
 return false;
 }
 
// 找到指定的節點後一個節點,因爲刪除的是後一個節點
 while (pTemp != NULL)
 {
 curPos++;
 if (curPos == removenode+1)
 break;
 pTemp = pTemp->next;
 }
 if (curPos != removenode) // 節點未尋到,錯誤退出
 {
 return false;
 }
 LNode *pDel = NULL; // 刪除節點
 pDel = pTemp->next;
 pTemp->next = pDel->next;
 delete pDel;
 m_listLength–;
 return true;
 }
 
//sort the linked list to descending order.
 void LinkList::sort()
 {
 if (m_listLength<=1)
 {
 return;
 }
 LNode *pTemp = m_pList;
 int temp;
 // 選擇法排序
 for(int i=0;i<M_LISTLENGTH-1;I++)
 for(int j=i+1;j<M_LISTLENGTH;J++)
 if (pTemp[i].data<PTEMP[J].DATA)
 {
 temp=pTemp[i].data;
 pTemp[i].data=pTemp[j].data;
 pTemp[j].data=temp;
 }
 }
 前兩個函數實現了要求a,後一個函數sort()實現了要求b
 
 
 
208. Debugging (Mandatory)
 a. For each of the following recursive methods, enter Y in the answer box if the method terminaters (assume i=5), Otherwise enter N.
 (題目意思:判斷下面的遞歸函數是否可以結束)
 static int f(int i){
 return f(i-1)*f(i-1);
 }
 Ansewr: N,明顯沒有返回條件語句,無限遞歸了
 
static int f(int i){
 if(i==0){return 1;}
 else {return f(i-1)*f(i-1);}
 }
 Ansewr:Y,當i=0時可結束遞歸
 
static int f(int i){
 if(i==0){return 1;}
 else {return f(i-1)*f(i-2);}
 }
 Ansewr:N,因爲i=1時,f(i-2)=f(-1),進入一個無限遞歸中
 
 
 
 
 
209.編程
 將整數轉換成字符串:void itoa(int,char);
 例如itoa(-123,s[])則s=“-123”;
 答:
 char* itoa(int value, char* string)
 {
 char tmp[33];
 char* tp = tmp;
 int i;
 unsigned v;
 char* sp;
 // 將值轉爲正值
 if (value < 0)
 v = -value;
 else
 v = (unsigned)value;
 // 將數轉換爲字符放在數組tmp中
 while (v)
 {
 i = v % 10;
 v = v / 10;
 *tp++ = i+’0′;
 }
 // 將tmp裏的字符填入string指針裏,並加上負號(如果有)
 sp = string;
 if (value < 0)
 *sp++ = ‘-’;
 while (tp > tmp)
 *sp++ = *–tp;
 *sp = 0;
 return string;
 }
 
 
 
 
 
210.完成下列程序
 *
 *.*.
 *..*..*..
 *…*…*…*…
 *….*….*….*….*….
 *…..*…..*…..*…..*…..*…..
 *……*……*……*……*……*……*……
 *…….*…….*…….*…….*…….*…….*…….*…….
 #include
 #define N 8
 int main()
 {
 int i;
 int j;
 int k;
 ———————————————————
 │ │
 │ │
 │ │
 ———————————————————
 return 0;
 }
 答:#define N 8
 int main()
 {
 int i;
 int j;
 int k;
 
for(i=0;i<N;I++)
 {
 for(j=0;j<I+1;J++)
 {
 printf(“*”);
 for(k=0;k<I;K++)
 printf(“.”);
 }
 printf(“\n”);
 }
 return 0;
 }
 
211.下列程序運行時會崩潰,請找出錯誤並改正,並且說明原因。
 #include “stdio.h”
 #include “malloc.h”
 typedef struct TNode
 {
 TNode* left;
 TNode* right;
 int value;
 }TNode;
 
TNode* root=NULL;
 void append(int N);
 
int main()
 {
 append(63);
 append(45);
 append(32);
 append(77);
 append(96);
 append(21);
 append(17); // Again, 數字任意給出
 return 0;
 }
 
void append(int N)
 {
 TNode* NewNode=(TNode *)malloc(sizeof(TNode));
 NewNode->value=N;
 NewNode->left=NULL; //新增
 NewNode->right=NULL; //新增
 if(root==NULL)
 {
 root=NewNode;
 return;
 }
 else
 {
 TNode* temp;
 temp=root;
 while((N>=temp->value && temp->left!=NULL)||(Nvalue && temp-
 
>right!=NULL))
 {
 while(N>=temp->value && temp->left!=NULL)
 temp=temp->left;
 while(Nvalue && temp->right!=NULL)
 temp=temp->right;
 }
 if(N>=temp->value)
 temp->left=NewNode;
 else
 temp->right=NewNode;
 return;
 }
 }
 
答:因爲新節點的左右指針沒有賦NULL值,至使下面的while循環不能正確結束而導致內存越界,最後崩潰(注意結束條件是temp->left!=NULL或temp->right!=NULL)。改正就是增加兩條賦值語句,如上文紅色部分字體就是新增的兩條語句。
 
 
 
 
 
 
 
212.打印如下圖案,共19行,只能有一個for循環(題目已經提供)
 * 
 *** 
 ***** 
 ******* 
 ********* 
 ***********
 ************* 
 *************** 
  ***************** 
 *******************
  ***************** 
 *************** 
 ************* 
 *********** 
 ********* 
 ******* 
 ***** 
 *** 
 * 
 for(i=0;i<19;i++)
 {
 
}
 答:
 #include “stdio.h”
 void main()
 {
 for(int i=0;i<19;i++)
 {
 int j=0;
 while (j<19)
 {
 if (i<=9)
 {
 if (j<=9)
 {
 if (i+j>=9)
 printf(“*”);
 else
 printf(” “);
 }
 else
 if (j-i<=9)
 printf(“*”);
 else
 printf(” “);
 }
 else
 {
 if (j<=9)
 {
 if (i-j<=9)
 printf(“*”);
 else
 printf(” “);
 }
 else
 if (j+i<=27)
 printf(“*”);
 else
 printf(” “);
 }
 j++;
 }
 printf(“\n”);
 }
 }
 
213.stack data (棧)存在於
 A.rom, B .flash C .eeprom D.ram E .none of the above
 答:D.ram。這題稍微涉及到一點硬件知識,ROM的全稱是Read Only Memory,即只讀存儲器,flash ,eeprom都是ROM家族的一員,RAM是Random Access Memory的簡稱,意爲隨機存取存儲器,也就是內存了。不管是堆還是棧都是放在內存裏的。
 
214.
 int i;
 int x=0×12345678;
 unsigned char *p=(unsigned char *)&x;
 for(i=0;i<SIZEOF(X);I++)
 printf(“%2x”,*(p+i));
 在80x86pc機器上運行結果?
 答:x在PC機上的內存存放順序爲78 56 34 12,高字節在前,低字節在後,因此輸出78563412
 Sun Sparc Unix上運行結果?
 
 
 
215.
 char a[2][2][3]={{{1,6,3},{5,4,15}},{{3,5,33},{23,12,7}} };
 for(int i=0;i<12;i++)
 printf(“%d “,_______);
 在空格處填上合適的語句,順序打印出a中的數字
 答:*(*(*(a+i/6)+(i/3%2))+i%3)
 這題主要是要將輸出的序號依次寫出一些,如000,001,002,010,011,012,100,101…然後找序號變化規律
 
216.請用標準C語言實現一個雙向循環鏈表的查找與刪除。
 typedef struct doublecyclelink{
 int key;
 struct doublecyclelink *prev;
 struct doublecyclelink *next;
 }DoubleCycleLinkT;
 DoubleCycleLinkT *findKey(DoubleCycleLinkT *link,int key);
 遍歷整個雙向循環鏈表,將第一個與key值相同的結點移出鏈表,並返回。
 若沒有找到則返回NULL。
 
答:
 函數爲
 DoubleCycleLinkT *findKey(DoubleCycleLinkT *link,int key)
 {
 DoubleCycleLinkT *p;
 p=link->next;
 while (p->next!=link) // 鏈表結尾
 {
 if (p->key==key) // 查找到key值相同,刪除該節點,並返回
 {
 p->prev->next=p->next;
 p->next->prev=p->prev;
 free(p);
 return link;
 }
 else
 p=p->next; // 否則查找下一節點
 }
 if (p->next == link) return NULL; //沒找到,返回NULL
 
}
 
217、請用標準C語言實現下列標準庫函數,設計中不得使用其他庫函數。
 char *strstr(char *str1,char *str2);
 在字符串str1中,尋找字串str2,若找到返回找到的位置,否則返回NULL。
 答:
 函數爲
 char * strstr ( const char * str1, const char * str2 )
 {
 char *cp = (char *) str1;
 char *s1, *s2;
 if ( !*str2 )
 return((char *)str1);
 while (*cp)
 {
 s1 = cp;
 s2 = (char *) str2;
 while ( *s1 && *s2 && !(*s1-*s2) )
 s1++, s2++;
 if (!*s2)
 return(cp);
 cp++;
 }
 return(NULL);
 }
 
 
 
218.實現雙向鏈表刪除一個節點P,在節點P後插入一個節點,寫出這兩個函數;
 答:
 假設線性表的雙向鏈表存儲結構
 typedef struct DulNode{
 struct DulNode *prior; //前驅指針
 ElemType data; //數據
 struct DulNode *next; //後繼指針
 }DulNode,*DuLinkList;
 刪除操作
 Status ListDelete_DuL(DuLinkList &L,int i,ElemType &e)
 {
 if(!(p=GetElemP_DuL(L,i)))
 return ERROR;
 e=p->data;
 p->prior->next=p->next;
 p->next->prior=p->pror;
 free(p);
 return OK;
 }
 插入操作
 Status ListInsert_DuL(DuLinkList &L,int i,ElemType &e)
 {
 if(!(p=GetElemP_DuL(L,i)))
 return ERROR;
 if(!(s=(DuLinkList)malloc(sizeof(DuLNode))))
 return ERROR;
 
s->data=e;
 s->prior=p->prior;
 p->prior->next=s;
 s->next=p;
 p->prior=s;
 return OK;
 }
 
219.寫一個函數,將其中的\t都轉換成4個空格。
 答:
 該函數命名爲convert,參數的意義爲:
 *strDest目的字符串,*strSrc源字符串,length源字符串的長度
 函數實現爲:
 char* convert(char *strDest, const char *strSrc,int length)
 {
 char * cp = strDest;
 int i=0;
 while(*strSrc && i
 {
 if (*strSrc==’\t’) //將\t轉換成4個空格
 {
 for(int j=0;j<4;j++)
 *cp++=’ ‘;
 }
 else //否則直接拷貝
 *cp++=*strSrc;
 strSrc++;
 i++;
 }
 return strDest;
 }
 
230.Windows程序的入口是哪裏?寫出Windows消息機制的流程。
 答:
 Windows程序的入口是WinMain函數
 消息機制:系統將會維護一個或多個消息隊列,所有產生的消息都會被放入或是插入隊列中。系統會在隊列中取出每一條消息,根據消息的接收句柄而將該消息發送給擁有該窗口的程序的消息循環。每一個運行的程序都有自己的消息循環,在循環中得到屬於自己的消息並根據接收窗口的句柄調用相應的窗口過程。而在沒有消息時消息循環就將控制權交給系統。
 
231.如何定義和實現一個類的成員函數爲回調函數?
 答:
 所謂的回調函數,就是預先在系統的對函數進行註冊,讓系統知道這個函數的存在,以後,當某個事件發生時,再調用這個函數對事件進行響應。
 定義一個類的成員函數時在該函數前加CALLBACK即將其定義爲回調函數,函數的實現和普通成員函數沒有區別
 
 
 
232.C++裏面是不是所有的動作都是main()引起的?如果不是,請舉例。
 答:不是,比如中斷引起的中斷處理不是直接由main()引起的,而是由外部事件引起的。
 
233.C++裏面如何聲明const void f(void)函數爲C程序中的庫函數
 答:在該函數前添加extern “C”聲明
 
234. 內聯函數在編譯時是否做參數類型檢查
 答:做類型檢查,因爲內聯函數就是在程序編譯時,編譯器將程序中出現的內聯函數的調用表達式用內聯函數的函數體來代替。
 235.請你詳細地解釋一下IP協議的定義,在哪個層上面?主要有什麼作用?TCP與UDP呢?
 答:IP是Internet Protocol的簡稱,是網絡層的主要協議,作用是提供不可靠、無連接的數據報傳送。TCP是Transmit Control Protocol(傳輸控制協議)的縮寫,在運輸層,TCP提供一種面向連接的,可靠的字節流服務;UDP是User Datagram Protocol(用戶數據報協議)的縮寫,在運輸層,UDP提供不可靠的傳輸數據服務
 
236.請問交換機和路由器各自的實現原理是什麼?分別在哪個層次上面實現的?
 答:交換機屬於OSI第二層即數據鏈路層設備。它根據MAC地址尋址,通過站表選擇路由,站表的建立和維護由交換機自動進行。路由器屬於OSI第三層即網絡層設備,它根據IP地址進行尋址,通過路由表路由協議產生。交換機最大的好處是快速,路由器最大的好處是控制能力強。
 
237.全局變量和局部變量有什麼區別?是怎麼實現的?操作系統和編譯器是怎麼知道的?
 答:一些變量在整個程序中都是可見的,它們稱爲全局變量。一些變量只能在一個函數中可知,稱爲局部變量。這就是他們的區別。
 在任何函數外面定義的變量就是全局變量,在函數內部定義的變量是局部變量,這是它們在程序中的實現過程。
 操作系統和編譯器是根據程序運行的內存區域知道他們的,程序的全局數據放在所分配內存的全局數據區,程序的局部數據放在棧區。
 
238. 有兩個文件a.txt,b.txt.a.txt中存儲的是aaaaaa,b.txt中存儲的是bbb。將兩個文件合併成c.txt如果是a並b的話存儲爲abababaaa.要是b並a   的話就是bababaaaa.用c語言編程實現。
 
#include   “stdio.h”
 
void   fmerge(FILE   *fa,FILE   *fb,FILE   *fc)
 
{
 
char   cha,chb;
 
cha=fgetc(fa);
 
chb=fgetc(fb);
 
while   ((cha!=EOF)&&(chb!=EOF))
 
{
 
fputc(cha,fc);
 
fputc(chb,fc);
 
cha=fgetc(fa);
 
chb=fgetc(fb);
 
}
 
while   (cha!=EOF)
 
{
 
fputc(cha,fc);
 
cha=fgetc(fa);
 
}
 
while   (chb!=EOF)
 
{
 
fputc(chb,fc);
 
chb=fgetc(fb);
 
}
 
}
 
int   main()
 
{
 
FILE   *fa,*fb,*fc;
 
fa=fopen(“a.txt”,”r”);
 
fb=fopen(“b.txt”,”r”);
 
fc=fopen(“c.txt”,”w”);
 
fmerge(fa,fb,fc);
 
fclose(fa);
 
fclose(fb);
 
fclose(fc);
 
return   0;
 
}
 
 
 
 
 
239.C++:memset ,memcpy 和strcpy 的根本區別?
 #include “memory.h”
 memset用來對一段內存空間全部設置爲某個字符,一般用在對定義的字符串進行初始化爲‘ ‘或‘\0′;例:char a[100];memset(a, ‘\0′, sizeof(a));
 memcpy用來做內存拷貝,你可以拿它拷貝任何數據類型的對象,可以指定拷貝的數據長度;例:char a[100],b[50]; memcpy(b, a, sizeof(b));注意如用sizeof(a),會造成b的內存地址溢出。
 
strcpy就只能拷貝字符串了,它遇到’\0′就結束拷貝;例:char a[100],b[50];strcpy(a,b);如用strcpy(b,a),要注意a中的字符串長度(第一個‘\0′之前)是否超過50位,如超過,則會造成b的內存地址溢出。
 
strcpy
 原型:extern char *strcpy(char *dest,char *src);
 用法:#include
 功能:把src所指由NULL結束的字符串複製到dest所指的數組中。
 說明:src和dest所指內存區域不可以重疊且dest必須有足夠的空間來容納src的字符串。
 返回指向dest的指針。
 memcpy
 原型:extern void *memcpy(void *dest, void *src, unsigned int count);
 用法:#include
 功能:由src所指內存區域複製count個字節到dest所指內存區域。
 說明:src和dest所指內存區域不能重疊,函數返回指向dest的指針。
 memset
 原型:extern void *memset(void *buffer, char c, int count);
 用法:#include
 功能:把buffer所指內存區域的前count個字節設置成字符c。
 說明:返回指向buffer的指針。
 
240.ASSERT()是幹什麼用的
 
ASSERT() 是一個調試程序時經常使用的宏,在程序運行時它計算括號內的表達式,如果表達式爲FALSE (0), 程序將報告錯誤,並終止執行。如果表達式不爲0,則繼續執行後面的語句。這個宏通常原來判斷程序中是否出現了明顯非法的數據,如果出現了終止程序以免導致 嚴重後果,同時也便於查找錯誤。例如,變量n在程序中不應該爲0,如果爲0可能導致錯誤,你可以這樣寫程序:
 ……
 ASSERT( n != 0);
 k = 10/ n;
 ……
 ASSERT只有在Debug版本中才有效,如果編譯爲Release版本則被忽略。
 assert()的功能類似,它是ANSI C標準中規定的函數,它與ASSERT的一個重要區別是可以用在Release版本中。
 
241. 二分查找算法:
 1、遞歸方法實現:
 int BSearch(elemtype a[],elemtype x,int low,int high)
 /*在下屆爲low,上界爲high的數組a中折半查找數據元素x*/
 {
 int mid;
 if(low>high) return -1;
 mid=(low+high)/2;
 if(x==a[mid]) return mid;
 if(x<a[mid]) return(BSearch(a,x,low,mid-1));
 else return(BSearch(a,x,mid+1,high));
 }
 
2、非遞歸方法實現:
 int BSearch(elemtype a[],keytype key,int n)
 {
 int low,high,mid;
 low=0;high=n-1;
 while(low<=high)
 {
 mid=(low+high)/2;
 if(a[mid].key==key) return mid;
 else if(a[mid].key<key) low=mid+1;
 else high=mid-1;
 }
 return -1;
 }
 
 
 
 
 
242,寫出下面代碼段的輸出結果,並說明理由:
 
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”;
 char *str8 = “abc”;
 
cout << ( str1 == str2 ) << endl;
 cout << ( str3 == str4 ) << endl;
 cout << ( str5 == str6 ) << endl;
 cout << ( str7 == str8 ) << endl;
 
1,  str1,str2,str3,str4是數組變量,它們有各自的內存空間;
 而str5,str6,str7,str8是指針,它們指向相同的常量區域。
 




243. 以下代碼中的兩個sizeof用法有問題嗎?
 void UpperCase( char str[] )
 
{
 for( size_t i=0; i<sizeof(str)/sizeof(str[0]); ++i )
 if( ‘a’<=str[i] && str[i]<=’z’ )
 str[i] -= (‘a’-'A’ );
 }
 char str[] = “aBcDe”;
 cout << “str字符長度爲: ” << sizeof(str)/sizeof(str[0]) << endl;
 UpperCase( str );
 cout << str << endl;
 
函數內的sizeof有問題。根據語法,sizeof如用於數組,只能測出靜態數組的大小,無法檢測動態分配的或外部數組大小。函數外的str是一個靜態定義的數組,因此其大小爲6,函數內的str實際只是一個指向字符串的指針,沒有任何額外的與數組相關的信息,因此sizeof作用於上只將其當指針看,
 


244,下面程序輸出結果是多少:
 
main()
 {
 int a[5]={1,2,3,4,5};
 int *ptr=(int *)(&a+1);
 
   printf(“%d,%d”,*(a+1),*(ptr-1));
 }
 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].
 
 
 
245,請問運行Test函數會有什麼樣的結果?
 void GetMemory(char *p)
 {
 p = (char *)malloc(100);
 }
 void Test(void)
 {
 char *str = NULL;
 GetMemory(str);
 strcpy(str, “hello world”);
 printf(str);
 }
 
 
 
 
 
,請問運行Test函數會有什麼樣的結果?
 char *GetMemory(void)
 {
 char p[] = “hello world”;
 return p;
 }
 void Test(void)
 {
 char *str = NULL;
 str = GetMemory();
 printf(str);
 }
 
 
 
,請問運行Test函數會有什麼樣的結果?
 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函數會有什麼樣的結果?
 void Test(void)
 {
 char *str = (char *) malloc(100);
 strcpy(str, “hello”);
 free(str);
 if(str != NULL)
 {
 strcpy(str, “world”);
 printf(str);
 }
 }




裝箱與拆箱的操作
 · 重載與重寫的意義
 · 多態的理解以及對應的一種設計模式
 · .net 下跨平臺調用的方法
 · 抽象類與接口的區別
 · The difference between C++ and C#
 · Describe the design patterns you’ve appliedto project.
 · Introduce P2P and Chord algorithm.
 · c++指針
 · c++虛構函數
 · 數據庫sql語句
 · 寫一個迴文判斷函數
 · c#變量初始化問題

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