[轉]const的用法
1.修飾類的數據成員
const數據成員只是在某個對象的生命周期內是常量.如果創建多個對象,那么每個對象的const數據成員可以不一樣.所以,不能在類聲明中初始化const數據成員.如:
class A
{
?? const int size = 100;// 錯誤
?? int array[size];//錯誤,未知的數組大小
}
const類數據成員,只能在類的構造函數的初始化列表中進行.要想建立整個類都是恒定的常量的數據,可以用類中的枚舉.如:
class A
{
enum {size1 = 100, size2 = 200};
int array[size1];
}
2.只有聲明為const的成員函數才能被一個const對象調用
3.在另一連接文件中引用const常量.
extern const int i
4.對于const對象,c++既允許對其進行靜態初始化,也允許對其進行動態初始化.const對象具有從構造函數完成到析構函數執行之前的不變性.
5.常量與數組的組合有什么特殊嗎?
我們給出下面的代碼:
const int size[3]={10,20,50};
int array[size[2]];
編譯通不過!為什么呢?const可以用于集合,但編譯器不能把一個集合存放在它的符號表里,所以必須分配內存。在這種情況下,const意味著“不能改變的一塊存儲”。然而,其值在編譯時不能被使用,因為編譯器在編譯時不需要知道存儲的內容。自然,作為數組的大小就不行了
你再看看下面的例子:
class A
{
public:
A(int i=0):test[2]({1,2}) {} file://你/認為行嗎?
private:
const int test[2];
};
C++標準有一個規定,不允許無序對象在類內部初始化,數組顯然是一個無序的,所以這樣的初始化是錯誤的!對于他,只能在類的外部進行初始化,如果想讓它通過,只需要聲明為靜態的,然后初始化。
這里我們看到,常量與數組的組合沒有什么特殊!一切都是數組惹的禍!
(7)什么情況下為const分配內存?
以下是我想到的可能情況,當然,有的編譯器進行了優化,可能不分配內存。
A、作為非靜態的類成員時;
B、用于集合時;
C、被取地址時;
D、在main函數體內部通過函數來獲得值時;
E、const的 class或struct有用戶定義的構造函數、析構函數或基類時;。
F、當const的長度比計算機字長還長時;
G、參數中的const;
H、使用了extern時。
(8)與static搭配會不會有問題?
假設有一個類:
class A
{
public:
......
static void f() const { ......}
......
};
我們發現編譯器會報錯,因為在這種情況下static不能夠與const共存!因為static沒有this指針,但是const修飾this指針.
(9)如何修改常量?
有時候我們卻不得不對類內的數據進行修改,但是我們的接口卻被聲明了const,那該怎么處理呢?我對這個問題的看法如下:
1)標準用法:mutable
class A
{
public:
A(int i=0):test(i) { }
void Setvalue(int i)const { test=i; }
private:
mutable int test; file://這/里處理!
};
2)強制轉換:const_cast
class A
{
public:
A(int i=0):test(i) { }
void Setvalue(int i)const
{ const_cast <int>(test)=i; }//這里處理!
private:
int test;
};
(10)最后我們來討論一下常量對象的動態創建。
既然編譯器可以動態初始化常量,就自然可以動態創建,例如:
const int* pi=new const int(10);
這里要注意2點:
1)const對象必須被初始化!所以(10)是不能夠少的。
2)new返回的指針必須是const類型的。
那么我們可不可以動態創建一個數組呢?
答案是否定的,因為new內置類型的數組,不能被初始化。
posted @
2006-06-15 06:59 Jerry Cat 閱讀(543) |
評論 (0) |
編輯 收藏
[轉貼]音頻錄入
一、數字音頻基礎知識
Fourier級數:
任何周期的波形可以分解成多個正弦波,這些正弦波的頻率都是整數倍。級數中其他正線波的頻率是基礎頻率的整數倍?;A頻率稱為一級諧波。
PCM:
pulse code modulation,脈沖編碼調制,即對波形按照固定周期頻率采樣。為了保證采樣后數據質量,采樣頻率必須是樣本聲音最高頻率的兩倍,這就是Nyquist頻率。
樣本大?。翰蓸雍笥糜诖鎯φ穹壍奈粩担瑢嶋H就是脈沖編碼的階梯數,位數越大表明精度越高,這一點學過數字邏輯電路的應該清楚。
聲音強度:
波形振幅的平方。兩個聲音強度上的差常以分貝(db)為單位來度量,
計算公式如下:
20*log(A1/A2)分貝。A1,A2為兩個聲音的振幅。如果采樣大小為8位,則采樣的動態范圍為20*log(256)分貝=48db。如果樣本大小為16位,則采樣動態范圍為20*log(65536)大約是96分貝,接近了人聽覺極限和痛苦極限,是再線音樂的理想范圍。windows同時支持8位和16位的采樣大小。
二、相關API函數,結構,消息
對于錄音設備來說,windows 提供了一組wave***的函數,比較重要的有以下幾個:
打開錄音設備函數
MMRESULT waveInOpen(
LPHWAVEIN phwi, //輸入設備句柄
UINT uDeviceID, //輸入設備ID
LPWAVEFORMATEX pwfx, //錄音格式指針
DWORD dwCallback, //處理MM_WIM_***消息的回調函數或窗口句柄,線程ID
DWORD dwCallbackInstance,
DWORD fdwOpen //處理消息方式的符號位
);
為錄音設備準備緩存函數
MMRESULT waveInPrepareHeader( HWAVEIN hwi, LPWAVEHDR pwh, UINT bwh );
給輸入設備增加一個緩存
MMRESULT waveInAddBuffer( HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh );
開始錄音
MMRESULT waveInStart( HWAVEIN hwi );
清除緩存
MMRESULT waveInUnprepareHeader( HWAVEIN hwi,LPWAVEHDR pwh, UINT cbwh);
停止錄音
MMRESULT waveInReset( HWAVEIN hwi );
關閉錄音設備
MMRESULT waveInClose( HWAVEIN hwi );
Wave_audio數據格式
typedef struct {
WORD wFormatTag; //數據格式,一般為WAVE_FORMAT_PCM即脈沖編碼
WORD nChannels; //聲道
DWORD nSamplesPerSec; //采樣頻率
DWORD nAvgBytesPerSec; //每秒數據量
WORD nBlockAlign;
WORD wBitsPerSample;//樣本大小
WORD cbSize;
} WAVEFORMATEX;
waveform-audio 緩存格式
typedef struct {
LPSTR lpData; //內存指針
DWORD dwBufferLength;//長度
DWORD dwBytesRecorded; //已錄音的字節長度
DWORD dwUser;
DWORD dwFlags;
DWORD dwLoops; //循環次數
struct wavehdr_tag * lpNext;
DWORD reserved;
} WAVEHDR;
相關消息
MM_WIM_OPEN:打開設備時消息,在此期間我們可以進行一些初始化工作
MM_WIM_DATA:當緩存已滿或者停止錄音時的消息,處理這個消息可以對緩存進行重新分配,實現不限長度錄音
MM_WIM_CLOSE:關閉錄音設備時的消息。
相對于錄音來說,回放就簡單的多了,用到的函數主要有以下幾個:
打開回放設備
MMRESULT waveOutOpen(LPHWAVEOUT phwo, UINT uDeviceID, LPWAVEFORMATEX pwfx, DWORD dwCallback, DWORD dwCallbackInstance, DWORD fdwOpen );
為回放設備準備內存塊
MMRESULT waveOutPrepareHeader(HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh );
寫數據(放音)
MMRESULT waveOutWrite(HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh );
相應的也有三個消息,用法跟錄音的類似:
三、程序設計
一個錄音程序的簡單流程: 打開錄音設備waveInOpen===>準備wave數據頭waveInPrepareHeader===>
準備數據塊waveInAddBuffer===>開始錄音waveInStart===>停止錄音(waveInReset) ===>
關閉錄音設備(waveInClose)
當開始錄音后當buffer已滿時,將收到MM_WIM_DATA消息,處理該消息可以保存已錄好數據。
回放程序比這個要簡單的多: 打開回放設備waveOutOpen===>準備wave數據頭waveOutPrepareHeader===>寫wave數據waveOutWrite===>
停止放音(waveOutRest) ===>關閉回放設備(waveOutClose)
如何處理MM消息: MSDN告訴我們主要有 CALLBACK_FUNCTION、CALL_BACKTHREAD、CALLBACK_WINDOW 三種方式,常用的是
Thread,window方式。
線程模式
waveInOpen(&hWaveIn,WAVE_MAPPER,&waveform,m_ThreadID,NULL,CALLBACK_THREAD),我們可以繼承MFC的CwinThread類,只要相應的處理線程消息即可。
MFC線程消息的宏為:
ON_THREAD_MESSAGE,
可以這樣添加消息映射: ON_THREAD_MESSAGE(MM_WIM_CLOSE, OnMM_WIM_CLOSE)
窗口模式
類似于線程模式,參見源程序即可
posted @
2006-06-15 06:57 Jerry Cat 閱讀(1138) |
評論 (0) |
編輯 收藏
[轉]某些公司的筆試題
1.想想結果是如何出來的:
?int main()??
{
?? unsigned?? char?? i=1;??
?? i-=3;??
?? printf("the?? value?? of?? i?? is:%d",i);??
}??
結果:the?? value?? of?? i?? is:254
答案:
??? 0000?? 0001??
-?? 0000?? 0011??
------------------??
??? 1111?? 1110???????? 而???? 1111?? 1110?????? 化為十制進正好是254!?
2.看看下列的程序有什么問題
void GetMemory(char *p)
{
p = (char *)malloc(100);
}
void Test(void)
{
char *str = NULL;
GetMemory(str);
strcpy(str, "hello world");
printf(str);
}
請問運行Test函數會有什么樣的結果?為什么?
答案:1.內存泄漏 2.str仍然是空指針
3.
int n = 10;
為什么sizeof ( n ) = 4?
?答案:sizeof(x)返回x的類型占用的字節數,該機器是在32位下
4.請問C++的類和C里面的struct有什么區別?
5.請講一講析構函數和虛函數的用法和作用?
6.全局變量和局部變量有什么區別?是怎么實現的?
7.設計函數 int atoi(char *s)。
8.int i=(j=4,k=8,l=16,m=32); printf(“%d”, i); 輸出是多少?
9.解釋局部變量、全局變量和靜態變量的含義
10.解釋堆和棧的區別。
11.論述含參數的宏與函數的優缺點。
12.實現雙向鏈表刪除一個節點P,在節點P后插入一個節點,寫出這兩個函數。
13.寫一個函數,將其中的 都轉換成4個空格。
14.Windows程序的入口是哪里?寫出Windows消息機制的流程。
15.如何定義和實現一個類的成員函數為回調函數?
16.C++里面是不是所有的動作都是main()引起的?如果不是,請舉例。
17.C++里面如何聲明const void f(void)函數為C程序中的庫函數?
18.下列哪兩個是等同的
int b;
A const int* a = &b;
B const* int a = &b;
C const int* const a = &b;
D int const* const a = &b;
19.內聯函數在編譯時是否做參數類型檢查?
void g(base & b)
????? {
b.play;
}
void main()
????? {
son s;
??????????? g(s);
??????????? return;
}
20.請你分別劃劃OSI的七層網絡結構圖,和TCP/IP的五層結構圖?
21.請你詳細的解釋一下IP協議的定義,在哪個層上面,主要有什么作用? TCP與UDP呢?
22.請問交換機和路由器分別的實現原理是什么?分別在哪個層次上面實現的?
頭文件中<>? 和“”的區別?
4、定義一個宏,輸入兩個參數,輸出積。
1. 以下三條輸出語句分別輸出什么?[C易] (視編譯器而定)
char str1[] = "abc";
char str2[] = "abc";
const char str3[] = "abc";
const char str4[] = "abc";
const char* str5 = "abc";
const char* str6 = "abc";
cout << boolalpha << ( str1==str2 ) << endl; // 輸出什么?
cout << boolalpha << ( str3==str4 ) << endl; // 輸出什么?
cout << boolalpha << ( str5==str6 ) << endl; // 輸出什么?
答:分別輸出false,false,true。str1和str2都是字符數組,每個都有其自己的存儲區,它們的值則是各存儲區首地址,不等;str3 和str4同上,只是按const語義,它們所指向的數據區不能修改。str5和str6并非數組而是字符指針,并不分配存儲區,其后的“abc”以常量形式存于靜態數據區,而它們自己僅是指向該區首地址的指針,相等。
12. 以下代碼中的兩個sizeof用法有問題嗎?[C易]
void UpperCase( char str[] ) // 將 str 中的小寫字母轉換成大寫字母
{
for( size_t i=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作用于上只將其當指針看,一個指針為4個字節,因此返回4。
[color=#DC143C]13. 非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& ); // 賦值操作,雖不是正宗的隱式類型轉換,但也可以勉強算一個[/color]
4. 以下代碼有什么問題?[C++易]
struct Test
{
Test( int ) {}
Test() {}
void fun() {}
};
void main( void )
{
Test a(1);
a.fun();
Test b();
b.fun();
}
答:變量b定義出錯。按默認構造函數定義對象,不需要加括號。
5. 以下代碼有什么問題?[C++易]
cout << (true?1:"1") << endl;
答:三元表達式“?:”問號后面的兩個操作數必須為同一類型。
8. 以下代碼能夠編譯通過嗎,為什么?[C++易]
unsigned int const size1 = 2;
char str1[ size1 ];
unsigned int temp = 0;
cin >> temp;
unsigned int const size2 = temp;
char str2[ size2 ];
答:str2定義出錯,size2非編譯器期間常量,而數組定義要求長度必須為編譯期常量。
2. 以下反向遍歷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;
}
答:首先數組定義有誤,應加上類型參數:vector array。其次vector::size_type被定義為unsigned int,即無符號數,這樣做為循環變量的i為0時再減1就會變成最大的整數,導致循環失去控制。
[color=#DC143C]9. 以下代碼中的輸出語句輸出0嗎,為什么?[C++易]
struct CLS
{
int m_i;
CLS( int i ) : m_i(i) {}
CLS()
{
CLS(0);
}
};
CLS obj;
cout << obj.m_i << endl;
答:不能。在默認構造函數內部再調用帶參的構造函數屬用戶行為而非編譯器行為,亦即僅執行函數調用,而不會執行其后的初始化表達式。只有在生成對象時,初始化表達式才會隨相應的構造函數一起調用。[/color]
[color=#DC143C]10. C++中的空類,默認產生哪些類成員函數?[C++易]
答:
class Empty
{
public:
Empty(); // 缺省構造函數
Empty( const Empty& ); // 拷貝構造函數
~Empty(); // 析構函數
Empty& operator=( const Empty& ); // 賦值運算符
Empty* operator&(); // 取址運算符
const Empty* operator&() const; // 取址運算符 const
};[/color]
[color=#DC143C]3. 以下兩條輸出語句分別輸出什么?[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; // 輸出什么?
答:分別輸出false和true。注意轉換的應用。(int)a實際上是以浮點數a為參數構造了一個整型數,該整數的值是1,(int&)a則是告訴編譯器將a當作整數看(并沒有做任何實質上的轉換)。因為1以整數形式存放和以浮點形式存放其內存數據是不一樣的,因此兩者不等。對b的兩種轉換意義同上,但是0的整數形式和浮點形式其內存數據是一樣的,因此在這種特殊情形下,兩者相等(僅僅在數值意義上)。
注意,程序的輸出會顯示(int&)a=1065353216,這個值是怎么來的呢?前面已經說了,1以浮點數形式存放在內存中,按 ieee754規定,其內容為0x0000803F(已考慮字節反序)。這也就是a這個變量所占據的內存單元的值。當(int&)a出現時,它相當于告訴它的上下文:“把這塊地址當做整數看待!不要管它原來是什么。”這樣,內容0x0000803F按整數解釋,其值正好就是1065353216 (十進制數)。
通過查看匯編代碼可以證實“(int)a相當于重新構造了一個值等于a的整型數”之說,而(int&)的作用則僅僅是表達了一個類型信息,意義在于為cout<<及==選擇正確的重載版本。
[/color]
6. 以下代碼有什么問題?[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 );
}
答:同樣有缺少類型參數的問題。另外,每次調用“array.erase( itor );”,被刪除元素之后的內容會自動往前移,導致迭代漏項,應在刪除一項后使itor--,使之從已經前移的下一個元素起繼續遍歷。
[color=#DC143C]11. 寫一個函數,完成內存之間的拷貝。[考慮問題是否全面]
答:
void* mymemcpy( void *dest, const void *src, size_t count )
{
char* pdest = static_cast( dest );
const char* psrc = static_cast( src );
if( pdest>psrc && pdest
{
for( size_t i=count-1; i!=-1; --i )
pdest[i] = psrc[i];
}
else
{
for( size_t i=0; i
pdest[i] = psrc[i];
}
return dest;
}[/color]
?
原題如下:
#i nclude
struct bit
{
int a:3;
int b:2;
int c:3;
};
int main(int argc, char* argv[])
{
bit s;
char *c = (char*)&s;
*c = 0x99;
cout <<<<<<
return 0;
}
Output:?
答案:
此題在在X86 little-endian 下是 1 -1 -4
在powerPC等big endian機器下,還要重新考慮
因為0x99在內存中表示為 100 11 001 , a = 001, b = 11, c = 100
當c為有符號數時, c = 100, 最高位1表示c為負數,負數在計算機用補碼表示,所以c = -4;同理
b = -1;當c為有符合數時, c = 100,即 c = 4,同理 b = 3
位域的概念
有些信息在存儲時,并不需要占用一個完整的字節, 而只需占幾個或一個二進制位。例如在存放一個開關量時,只有0和1 兩種狀態,用一位二進位即可。為了節省存儲空間,并使處理簡便,C語言又提供了一種數據結構,稱為“位域”或“位段”。所謂“位域”是把一個字節中的二進位劃分為幾個不同的區域, 并說明每個區域的位數。每個域有一個域名,允許在程序中按域名進行操作。這樣就可以把幾個不同的對象用一個字節的二進制位域來表示。一、位域的定義和位域變量的說明位域定義與結構定義相仿,其形式為:
struct 位域結構名
{ 位域列表 };
其中位域列表的形式為: 類型說明符 位域名:位域長度
例如:
struct bs
{
int a:8;
int b:2;
int c:6;
};
位域變量的說明與結構變量說明的方式相同。 可采用先定義后說明,同時定義說明或者直接說明這三種方式。例如:
struct bs
{
int a:8;
int b:2;
int c:6;
}data;
說明data為bs變量,共占兩個字節。其中位域a占8位,位域b占2位,位域c占6位。對于位域的定義尚有以下幾點說明:
1. 一個位域必須存儲在同一個字節中,不能跨兩個字節。如一個字節所??臻g不夠存放另一位域時,應從下一單元起存放該位域。也可以有意使某位域從下一單元開始。例如:
struct bs
{
unsigned a:4
unsigned :0 /*空域*/
unsigned b:4 /*從下一單元開始存放*/
unsigned c:4
}
在這個位域定義中,a占第一字節的4位,后4位填0表示不使用,b從第二字節開始,占用4位,c占用4位。
2. 由于位域不允許跨兩個字節,因此位域的長度不能大于一個字節的長度,也就是說不能超過8位二進位。
3. 位域可以無位域名,這時它只用來作填充或調整位置。無名的位域是不能使用的。例如:
struct k
{
int a:1
int :2 /*該2位不能使用*/
int b:3
int c:2
};
從以上分析可以看出,位域在本質上就是一種結構類型, 不過其成員是按二進位分配的。
二、位域的使用位域的使用和結構成員的使用相同,其一般形式為: 位域變量名·位域名 位域允許用各種格式輸出。
main(){
struct bs
{
unsigned a:1;
unsigned b:3;
unsigned c:4;
} bit,*pbit;
pbit = new bs;
bit.a=1;
bit.b=7;
bit.c=15;
pbit->a = 1;
pbit->b = 2;
pbit->c = 3;
printf("%d, %d, %d",bit.a, bit.b, bit.c);
printf("%d, %d, %d",pbit->a, pbit->b, pbit->c);
}
?
一、 單項選擇題(從四個備選答案中選擇一個正確答案,每小題1分,共20分)
1. C++中,關鍵字struct和class的區別僅僅在于( C )。
(A)struct 用來定義結構體, 而class用來定義類;
(B)struct 用來定義類, 而class用來定義類結構體;
(C)struct定義的類的缺省成員為公有的,而class定義的類的缺省成員為私有的;
(D)struct定義的類的成員須全部為公有的,而class定義的類的成員可以為私有的;
2. 以下程序執行后,輸出結果為( C ).
#i nclude
int Var=3 ;
void main(void)
{ int Var=10;
::Var++;
cout<<”Var=”<<<”, ::Var=”<<::Var<
}
(A)Var=11, ::Var=11 (B)Var=11, ::Var=3
(C)Var=10, ::Var=4 (D)Var=4, ::Var=10
3. 抽象基類是指( C )。
(A)嵌套類 (B)派生類
(C)含有純虛函數 (D)多繼承類
4.如果有#define AREA(a,b)a+b 則語句int s=AREA(3,4)*AREA(3,4)執行后變量s值為( D )。
(A) 24 (B)49 (C)144 (D)19
5. C++中條件表達式的值為( C )。
(A)–1或者+1 (B)–231~231 –1 (C)0或者1 (D) 0~231–1
6. 現在有以下語句:
struct MyBitType
{ int a:3;
unsigned b:3;
unsigned c:20;
int d;
};
int sz=sizeof(MyBitType);
則執行后,變量sz的值將得到( B )。
(A)2 (B)8 (C)28 (D)58
7. 假設有一個C++類名為Country, 則此類的析構函數為( C ).
(A)::Country() (B)void ~Country(void)
(C)~Country() (D)void ~Country()
8. 如果定義一個C++類CDate, 語句“CDate *p = new CDate;”的含義是( A )。
(A)調用CDate類的缺省構造函數從內存中分配一個CDate類型的對象,并將該對象地址賦值給指針p;
(B)調用CDate類的拷貝構造函數從內存中分配一個CDate類型的對象,并將該對象地址賦值給指針p;
(C)調用CDate類的析構函數從內存中分配一個CDate類型的對象,并將該對象地址賦值給指針p;
(D)從內存中釋放指針p所指向的CDate類的對象;
9.如果有一個類CRect及語句“CRect x1, x2;” 要使語句 “x1=x2;”合法,可在類中定義成員函數( C )。
(A) int operator(x2) (B)int operator=(x2)
(C) void operator=(CRect &); (D) void operator=()
10. 結構體變量S實際所占內存的大小為( A )字節。
(A)sizeof(S) (B)strlen(S)
(C)結構體中最長成員的長度 (D)結構體中最短成員的長度
11.在C++中,下列算符( D )不能重載。
(A)<< (B)>> (C)delete (D)::
12.下列正確的是( D )
(A)結構不能有構造函數、析構函數; (B)缺省時類的成員是公有的;
(C)類中如果定義了析構函數,則必須定義構造函數;
(D)缺省時結構的成員是公有的;
13. 下列關于靜態數據成員正確的是( B )
(A)可以通過this指針訪問靜態數據; (B)可以用類名和作用域訪問靜態數據;
(C)靜態數據在類內聲明并初始化; (D)只能由該類的靜態成員函數訪問;
14. 下列關于友元正確的說法是( D )
(A)友元只能在類的public區聲明;(B)友元具有this指針;
(C)類的成員函數不能聲明為另一個類的友元;
(D)一個函數如果被聲明為一個類的友元,則該函數具有訪問該類私有成員的權利。
15. 基類的( A )在派生類內不能被訪問。
(A)私有成員 (B)保護成員
(C)公有數據成員 (D)公有靜態數據成員
16. 下列關于運算符重載的描述中正確的是( D )
(A)運算符重載可以改變該運算符的優先級;
(B)運算符重載可以改變該運算符目數,即該算符運算的操作數個數;
(C)運算符重載函數只能在類中定義;
(D)new和delete允許重載;
17.左值是指( A )
(A)賦值算符左邊的變量; (B)賦值算符左邊的表達式的值;
(D)出現在賦值算符右邊的表達式的值;
(E)二元算符左邊表達式的值;
18. 下列為純虛函數的正確聲明的是( B )
(A)void virtual print()=0; (B)virtual void print()=0;
(C)virtual void print(){ }; (D)virtual void print();
19. 如果在類對象a的類中重載運算符“+”,則a+5的顯示調用方式為( C )
(A)a.operator(5) (B)a->operator+(5);
(C)a.operator+(5) (D)5.operator+(a)
20.一個類如果有一個以上的基類就叫做( B )?! ?
(A)循環繼承 (B)單繼承
(C)非法繼承 (D)多繼承
二、 多項選擇題(從五個備選答案中選擇2~5個正確答案,每小題2分,共10分)
1. 如果已定義了一個C++類CMyList并有以下語句:
CMyList list(3);
以下說法正確的是( AC )。
?。ˋ)該語句會創建一個CMyList類的一個對象;
?。˙)該語句會創建一個CMyList類的3個對象;
(C)必須為類CMyList定義一個構造函數;
(D)必須為類CMyList定義一個析構函數;
(E) 必須定義函數CMyList list(int);
2. 以下說法正確的是( ABCDE )。
(A)內聯(inline)函數改善了函數調用的執行效率。
(B)類A的友元(friend)函數可以訪問類A的私有成員。
(C)類A的友元(friend)類B可以訪問類A的私有成員。
(D)類A的靜態數據成員為類A的所有對象所共享。
(E)類A的靜態成員函數沒有傳遞this 指針作為參數。
3.類B從類A派生,則類B可以訪問類A中的( AC )成員。
(A)public成員 (B)private成員 (C)protected成員
(D)數據成員 (E)函數成員
4. 面向對象的程序設計語言具有( ABE )等共同特性。
(A)封裝性 (B)多態性 (C)簡單性 (D)復雜性
(E)繼承性
5. 現有一個程序如下:
#i nclude
class A
{ public:
void f(){ cout<< "A::f()"<
};
class B
{ public:
void f(){ cout<< "B:f()"<
void g(){ cout<< "B:g()"<
};
class C:public A, public B
{ public:
void g(){ cout<<"C::g()"<
void h()
{ cout<<"C::h()"<
f(); //語句1
}
};
void main()
{ C obj;
obj.f(); //語句2
obj.A::f(); //語句3
obj.B::f(); //語句4
obj.g(); //語句5
}
則編譯時會產生錯誤的語句有( AB )。
(A)語句1 (B)語句2 (C)語句3
(D)語句4 (E)語句5
三、 判斷分析題(正確的畫上√,錯誤的畫上×,每小題1分,共10分)
1.如果一個類的所有對象都共享某一個變量,則應當將該變量定義為該類的static成員。 ( √ )
2.語句“ typedef struct _MYSTRUC { int x; int y; double z; } MYSTRUC; ”是非法語句。 ( × )
3.語句“ int (*p)(int x, int y);”說明了p是一個指向整數的指針。 ( × )
4.Visual C++集成開發環境中,一個Workspace中只能創建一個Project。 ( × )
5.能訪問一個類CMyClass中的private成員的可以是類CMyClass的成員函數,友元函數和友元類中的函數。 ( √ )
6. 所有的MFC應用程序都必須有一個且只有一個CWinApp對象。 ( √ )
7.C++中的多態性就是指在編譯時,編譯器對同一個函數調用,根據情況調用不同的實現代碼。 ( × )
8.在for循環中,是先執行循環體后再判斷循環條件。 ( × )
9.C++中,如果條件表達式值為-1, 則表示邏輯為假。 ( × )
10. 在C++中用new分配的內存空間,在不需要時一般用free將該空間釋放。 ( × )
四、 填空題(每空2分,共20分)
1.以下函數完成求表達式 的值,請填空使之完成此功能。
float sum( float x )
{ float s=0.0;
int sign=1;
float t=1.0;
for(int i=1; i<=100; i++)
{
t=t*x;
s=s+-sign*i/(t+sign*i);
sign=-sign;
}
return s;
}
2.以下程序中實現類CSort, 完成對其成員p所指向的整數數組進行從小到大排序,該數組的元素個數由num表示,請填空完善該程序。
#i nclude
class CSort
{
int *p;
int num;
public:
void Order();
CSort(int *, int);
void Disp();
};
CSort::CSort(int *arry, int n)
:p(arry), num(n)
{ }
void CSort::Order() //函數Order原型
{ int m, tmp;
for(int i=0; i
{ m=i;
for(int j=i+1; j
{ if(p[j]
m=j;
}
if(m!=i)
{ tmp=p[i];
p[i]=p[m];
p[m]=tmp;
}
}
}
void CSort::Disp()
{ for(int i=0; i
cout<<<",";
cout<<
}
void main( )
{ static int a[]={10, -15, -3, 5, -4, 7,2};
CSort obj(a,2);
obj.Disp(); //應輸出一行:10,-15,-3,5,-4,7,2
obj.Order(); //對數組排序
obj.Disp(); //應輸出一行:-15,-4,-3,2,5,7,10
}
3.以下函數完成求兩個數n1和n2的最大公約數。
#i nclude
int fac(int n1, int n2)
{ int tmp;
if( n1 < n2 )
{ tmp=n1;
n1=n2 ;
n2=tmp ;
}
while(n1%n2!=0)
{ tmp=n1%n2; n1=n2; n2=tmp;
}
return n2;
}
2005年華為招聘--C語言筆試試題
?
一、判斷題(對的寫T,錯的寫F并說明原因,每小題4分,共20分)
1、有數組定義int a[2][2]={{1},{2,3}};則a[0][1]的值為0。(???? )
2、int (*ptr) (),則ptr是一維數組的名字。(???? )
3、指針在任何情況下都可進行>,<,>=,<=,==運算。(???? )
4、switch(c) 語句中c可以是int ,long,char ,float ,unsigned int 類型。(?? )
5、#define print(x)? printf("the no, "#x",is ")
?
二、填空題(共30分)
1、在windows下,寫出運行結果,每空2分,共10分。
char str[ ]= "Hello";
char *p=str;
int n=10;
sizeof(str)=(????? )
sizeof(p)=(?????? )
sizeof(n)=(?????? )
void func(char str[100])
{??? }
sizeof(str)=(???? )
?
2、void setmemory(char **p, int num)
{ *p=(char *) malloc(num);}
void test(void)
{? char *str=NULL;
?? getmemory(&str,100);
?? strcpy(str,"hello");
?? printf(str);
}
運行test函數有什么結果?(??????????????????????????????? )10分
?
3、設int arr[]={6,7,8,9,10};
???? int *ptr=arr;
?? *(ptr++)+=123;
?printf("%d,%d",*ptr,*(++ptr));
(?????????????????????????????????? ) 10分
?
二、編程題(第一小題20,第二小題30分)
1、? 不使用庫函數,編寫函數int strcmp(char? *source, char *dest)
相等返回0,不等返回-1;
?
2、? 寫一函數int fun(char *p)判斷一字符串是否為回文,是返回1,不是返回0,出錯返回-1
?
五、 閱讀程序題(每個小題5分,共20分)
1.閱讀以下程序,概括地寫出程序的功能。
#i nclude
double Exp(double x)
{ double sum=1.0;
double term=x;
double i=1 ;
while (term>=1.0E-8)
{ sum+=term ;
i++;
term=term*x/i ;
}
return sum ;
}
void main()
{ double s;
s=Exp(1.0)+Exp(2.0);
cout.precision(8);
cout<<"s="<<
}
zz
2. 閱讀程序,寫出程序執行時輸出結果。
#i nclude
const int SIZE=10;
class stack
{ char stck[SIZE];
int top;
public:
void init();
void push(char ch);
char pop();
};
void stack::init()
{ top=0; }
void stack::push(char ch)
{ if(top==SIZE)
{ cout<<"Stack is full.\n";
return ;
}
stck[top++]=ch;
}
char stack::pop()
{ if(top==0)
{ cout<<"Stack is empty.\n";
return 0;
}
return stck[--top];
}
void main()
{ stack s1, s2;
s1.init();
s2.init();
s1.push('a');
s1.push('b');
s1.push('c');
s2.push('x');
s2.push('y');
s2.push('z');
for(int i=0; i<3; i++)
cout<<"Pop s1:"<<
for(i=0; i<3; i++)
cout<<"Pop s2:"<<
}
程序結果:
Pop s1: c
Pop s1: b
Pop s1: a
Pop s2: z
Pop s2: y
Pop s2: z
3.閱讀程序,寫出程序運行時輸出結果。
#i nclude
class Tdate
{ public:
Tdate();
Tdate(int d);
Tdate(int m, int d);
Tdate(int m, int d, int y);
protected:
int month;
int day;
int year;
};
Tdate::Tdate()
{ month=4;
day=15;
year=1995;
cout<<<"/" <<<"/" <<
}
Tdate::Tdate(int d)
{ month=4;
day=d;
year=1996;
cout<<<"/" <<<"/" <<
}
Tdate::Tdate(int m, int d)
{ month=m;
day=d;
year=1997;
cout<<<"/" <<<"/" <<
}
Tdate::Tdate(int m, int d, int y)
{ month=m;
day=d;
year=y;
cout<<<"/" <<<"/" <<
}
void main()
{ Tdate aday;
Tdate bday(10);
Tdate cday(2,12);
Tdate dday(1,2,1998);
}
運行結果:
4/15/1995
4/10/1996
2/12/1997
1/2/1998
4.閱讀程序,寫出程序運行時輸出結果。
#i nclude
#i nclude
class shape
{ public:
shape(double x, double y):xCoord(x), yCoord(y){}
virtual double Area()const {return 0.0; }
protected:
double xCoord, yCoord;
};
class AA :public shape
{ public:
AA(double x, double y, double r): shape(x,y), rad(r){}
virtual double Area()const { return 3.0 * rad * rad; }
protected:
double rad;
};
class BB :public shape
{ public:
BB(double x1, double y1, double x2, double y2)
:shape(x1, y1), x2Coord(x2), y2Coord(y2){ }
virtual double Area()const;
protected:
double x2Coord, y2Coord;
};
double BB:Area()const
{ return fabs((xCoord-x2Coord)* (yCoord - y2Coord));
//庫函數fabs(double t)求得t的絕對值
}
void fun(const shape& sp)
{ cout<<
}
void main()
{ AA aa(2.0, 5.0, 4.0);
fun(aa);
BB bb(2.0, 8.0, 12.0, 17.0);
fun(bb);
}
運行結果:
48
30
六、 編寫程序題(每小題10分,共20分)
1.編寫一個函數int Judge(int *pArray, int n),判斷一個n×n二維整數數組pArray 是否為“魔方陣”,若是返回1,否則返回0。所謂魔方陣就是將1到n2的各個數字組成的方陣,它的每一行、每一列以及兩個對角線上數字之和均相等。例如,3×3的中,A是魔方陣,而B不是魔方陣。然后在主程序中調用Judge函數判斷數組A是否為魔方陣。
參考程序
#i nclude
int Judge(int *pArray, int n)
{ int s1, s2, s3,s4,sum=0;
int *p=pArray;
for(int i=1; i<= n*n; i++)
{ int Found=0; //為0,不在方陣中;
for(int j=0; j
if(p[j]==i)
{ Found=1; //為1,在方陣中
break;
}
if(Found==0) return 0; // 值為 i 的元素不在數組中,顯然不是魔方陣
}
for( i=1; i<=n*n; i++)
sum=sum+i;
sum=sum / n; // 各行、各列、對角線元素應當得到的和
s3=0;
s4=0;
for( i=0; i
{ s1=0, s2=0;
p=pArray;
for(int j=0; j
{ s1=s1+p[i*n+j]; //第i行的元素和
s2=s2+p[j*n+i]; //第i列的元素和
}
if ( s1!=sum)
return 0;
if ( s2!=sum)
return 0;
s3=s3+pArray[i*n+i]; // 對角線一元素和
s4=s4+pArray[i*n+(n-1-i)]; // 對角線二元素和
}
if(s3!=sum)
return 0;
if(s4 != sum)
return 0;
return 1;
}
void main()
{ int Array[3][3]={{ 8, 1, 6},{ 3, 5, 7},{ 4, 9, 2}};
當 x 輸入值為9999時,函數返回值為多少?
int fun ( unsigned int x )
{
int count = 0;
while(x)
{
x = x & (x-1);
count++;
}
return count;
}
答案:此函數是在計算 x 中含有1的個數,所以返回值為8。
if(Judge((int*)Array, 3))
cout<<"Yes, it's a magic array"<
else
cout<<"No, it isn't a magic array"<
}
/*********************************
* 兩個超大數相乘算法
*********************************/
#i nclude
void main()
{
int a[30],b[30],c[60];
int i,j;
/* 給乘數和被乘數賦值,并把結果賦零 */
for (i=0;i<30;i++)
{
a[i]=i%10;
b[i]=i%10;
c[2*i]=0;
c[2*i+1]=0;
}
/* 給每位結果賦值,這里應該考慮清楚為什么這么寫
還有這里的位的值的最大限度應該是-128 -- +127
所以就算是10*10也可以滿足存進去一個char類型里 */
for(i=0;i<30;i++)
for(j=0;j<30;j++)
c[i+j]+=a[i]*b[j];
/* 這里把每個位>10的數進位和把余數重新賦值給這一位 */
for(i=0;i<59;i++)
{
c[i+1]+=c[i]/10;
c[i]=c[i]%10;
}
/* 打印出來 */
for(i=0;i<30;i++)
printf("%d",a[30-i-1]);
printf("\n");
for(i=0;i<30;i++)
printf("%d",b[30-i-1]);
printf("\n");
for(i=0;i<60;i++)
printf("%d",c[60-i-1]);
printf("\n");
}
posted @
2006-06-15 06:54 Jerry Cat 閱讀(1017) |
評論 (0) |
編輯 收藏
/********************************************\
|????歡迎轉載, 但請保留作者姓名和原文鏈接, 祝您進步并共勉!???? |
\********************************************/
讀VC++內幕之體悟 - 03
作者: Jerry Cat
時間: 2006/06/14
鏈接:?http://www.shnenglu.com/jerysun0818/archive/2006/06/14/8526.html
3.??? 包含控件的窗口稱為包容器:)
posted @
2006-06-14 02:41 Jerry Cat 閱讀(628) |
評論 (1) |
編輯 收藏
/********************************************\
|????歡迎轉載, 但請保留作者姓名和原文鏈接, 祝您進步并共勉!???? |
\********************************************/
讀VC++內幕之體悟 - 02
作者: Jerry Cat
時間: 2006/06/10
鏈接:?
http://www.shnenglu.com/jerysun0818/archive/2006/06/10/8391.html
2.?? 普通控件給對話框發送通知命令消息。如果希望控件執行一個動作,可以調用C++控件類的成員函數,實際上該函數也是給控件發送一個Windows消息。普通控件的另一種情況為定制控件,它由程序員創建,其行為與普通控件一樣,也給父窗口發送WM_COMMAND消息,并接受用戶定義的消息。
posted @
2006-06-10 19:09 Jerry Cat 閱讀(1236) |
評論 (4) |
編輯 收藏
/********************************************\
|????歡迎轉載, 但請保留作者姓名和原文鏈接, 祝您進步并共勉!???? |
\********************************************/
讀VC++內幕之體悟 - 01
作者: Jerry Cat
時間: 2006/06/10
鏈接:?
http://www.shnenglu.com/jerysun0818/archive/2006/06/10/8365.html
第八章???? 使用ActiveX控件
1.?? VBX即VB控件,大部分用C語言實現,其標準建立在16位段式結構基礎上,不適合32位環境。ActiveX控件之前常稱為OLE控件,即OCX,它基于Microsoft的COM技術,可以代替以前的VBX。ActiveX控件可以用C++語言實現,還可以有MFC庫的支持或者ActiveX模板庫ATL的支持。
posted @
2006-06-10 02:47 Jerry Cat 閱讀(557) |
評論 (0) |
編輯 收藏
/********************************************\
|????歡迎轉載, 但請保留作者姓名和原文鏈接, 祝您進步并共勉!???? |
\********************************************/
常用C函的匯編實現(注: AT&T匯編)
作者: Jerry Cat
時間: 2006/06/07
鏈接:?http://www.shnenglu.com/jerysun0818/archive/2006/06/07/8253.html
//字符串拷貝
void strcpy(const char *src, char *dest)
{
?????? char ch;
?????? __asm
?????? {
???????? loop:
????????????? ldrb?????? ch, [src], #1
????????????? strb?????? ch, [dest], #1
????????????? cmp??????? ch, #0
????????????? bne???????? loop
?????? }
}
//int轉字符串
void I2S(int isource, char* desstr)
{
?char ch, i=sizeof(isource)*2, temp = 0, is =0;
?if(isource==0)
?{
??*desstr = '0';
??*(desstr+1)=0;
??return;
?}
?if(isource<0)
?{
??*desstr='-';
??desstr++;
??isource=-isource;
?}
?desstr--;
?__asm
?{
?loop:
??mov ch, #'0'
??add ch, ch, isource, lsr#28
??mov isource, isource, lsl#4
??sub temp,ch, #'0'
??orr is, temp, is
??cmp is, #0
??beq loop1
??mov is, #0xFF
??strb ch, [desstr,#1]!
?loop1:
??sub i, i, #1
??cmp i, #0
??bne loop
?}
?
?*(++desstr) = 0;
}
posted @
2006-06-07 18:11 Jerry Cat 閱讀(575) |
評論 (0) |
編輯 收藏
Linux下的mount命令
‘fstab’的用處
‘/etc/fstab’是‘mount’命令重要的配置文件。您可以‘root’身份通過‘diskdrake’(Mandrake Linux 控制中心 - 載入點),或用編輯器修改這個文件。
‘/etc/fstab’有幾個用處:
??? *
????? 決定開機時自動掛載哪些介質;
??? *
????? 指定每個介質掛載時的可選項、載入點;
??? *
????? 系統用來掛載幾個虛擬文件系統。
開機時掛載介質
默認下,開機時‘fstab’中列出的所有介質都將被掛載。如果其中某個介質出了問題,‘mount’會顯示出錯信息,然后繼續下一條目。請注意,這對于網絡介質,比如 NFS 或 SMB 共享,也有效。如果想取消開機時的自動掛載,您得在‘/etc/fstab’給相應條目提供‘noauto’可選項。
指定掛載的可選項和載入點
如果閱讀了上一篇,您就已經知道‘mount’命令有兩種可選項:常規可選項、文件系統的特殊可選項。
特殊可選項針對特定的文件系統。如果您在‘fstab’中給某個條目提供了特殊可選項(比如用于 Windows FAT 文件系統的 umask=0),只有相應文件系統的介質才可以通過該條目被掛載。如果您想掛載其他文件系統的介質,要么再設置那個可選項,要么創建單獨的條目。
指定載入點有個好處,以后可以省略掛載/卸載時的設備文件名。
mount mount_point
就將在‘/etc/fstab’尋找相應載入點的條目,并按照預先設定完成掛載。
虛擬文件系統
根據系統配置,‘fstab’含有一些虛擬文件系統的條目,這些條目沒有列出相應的設備文件。不管如何,請不要動這些條目!
??? *
????? ‘proc’掛載的是“進程樹”(process tree) ,提供一些系統的信息;
??? *
????? ‘pts’啟用“偽終端支持”(pseudo terminal support),這是 Unix 的兼容功能;
??? *
????? ‘shm’開啟“POSIX shared memory”,僅有一小部分程序會用到,不會有負面影響。
* section index * top
* ‘fstab’中條目的介紹
本地的固定系統分區
您看到,‘/etc/fstab’中已有幾個系統分區(如‘/’)的條目。 就拿這個為例:
/dev/hda3 / ext2 defaults 1 1
語法為:
/dev/hda3 / ext2 defaults 1 1
device_name mount_point file_system options 'dumpe2fs' 'fsck'
這兒有介質(硬盤的分區)的設備名、載入點(/)、文件系統(ext2)。
defaults 包括若干‘mount’的可選項:rw 可讀寫、 suid 允許設置用戶標識符(set-user-identifier)、exec 允許運行程序、auto 開機時自動掛載、nouser 只有‘root’有權卸載、async 允許磁盤延遲存取(caching) 。
最后兩個可選項是文件系統工具‘dumpe2fs’、‘fsck’用到的標志。
‘dump’域可設成‘1’(啟用)和‘0’(禁用)。由于備份 ext2/ext3 文件系統的程序要用到‘dump’,因此文件系統為 ext2/ext3 的條目要設成‘1’,所有其他條目都為‘0’。
‘fsck’域可設成‘0’(不檢查文件系統)、‘1’(先檢查)、‘2’(檢查)。所有非 Linux 文件系統、可移動的和網絡介質、虛擬文件系統都要設成‘0’;由于根分區要先被掛載(接著檢查),‘/’條目要設成‘1’;而所有其他不可移動的及 Linux 文件系統的本地介質都要設成‘2’。
可移動介質
可移動的數據存儲體,比如光盤,需要不同的可選項(如果您沒有用‘supermount’):
/dev/cdrom /mnt/cdrom auto user,noauto,exec,ro 0 0
user 允許用戶進行掛載、卸載,否則只有‘root’有此權利。請注意,這個可選項會關閉 exec ,您得在 user 可選項后指定 exec ,以使在用戶可在掛載的介質中運行程序,這些和上例是一致的。noauto 指開機時不掛載該介質,一些可移動介質就需要這個可選項。 ro 掛載的介質“只讀”(read-only) ?!甦ump’、‘fsck’都被關閉了。
雖然光盤沒有設成自動掛載,但由于‘/etc/fstab’中的這一條目,使得接下來的掛載變得很簡單:放入光盤,然后輸入:
mount /mnt/cdrom
‘mount’將在‘/etc/fstab’查找和這個載入點聯系的那個條目,并采用列出的可選項,因此,這樣您就可以省些輸入。在 KDE 中,放入光盤后,您只要用鼠標點擊那個光盤圖標,就能自動運行‘mount’命令。
掛載后的光盤將鎖住光驅,要彈出光盤的話,您得先卸載:umount /mnt/cdrom 。
要配置其他可移動介質,您要知道他們的設備文件名,可以看一下 devices.txt 或閱讀 有關可移動存儲設備的文章 。
本地的固定非系統分區
MS-Windows 分區的條目看起來是什么樣呢?假設是在第一塊 IDE 硬盤的第二個分區,而且您想要自動掛載:
/dev/hda2 /mnt/win_d vfat umask=0,quiet 0 0
如果是 Windows NT 的 NTFS 分區,就要把‘vfat’換成‘ntfs’。請注意,目前在 Linux 下,只能對 NTFS 的文件系統讀,而不能寫。
‘umask’可選項將關閉權限監查,沒有這項的話,就只有‘root’能存取該設備上的文件。當向這個介質移動文件時,由于無法設置權限,會顯示惱人的出錯信息,用‘quiet’就可以不顯示這些無關緊要的信息。
如果 Windows 分區中的文件名看起來很奇怪,那您就得再添兩個可選項:‘iocharset’和‘codepage’。默認下,‘mount’用‘iso8859-1’字符集和 codepage 437 。修改后,可以實現字符轉換。man charsets 列出了可用的字符集,將 codepage 設成 850 (codepage=850)就可以解決一些問題。
(注:要顯示簡體中文的話,得添上 charsets=gb2312,codepage=936)
一個分區掛載在一個已存在的目錄上,這個目錄可以不為空,但掛載后這個目錄下以前的內容將不可用。
對于其他操作系統建立的文件系統的掛載也是這樣。但是需要理解的是:光盤、軟盤、其他操作系統使用的文件系統的格式與linux使用的文件系統格式是不一樣的。光盤是ISO9660;軟盤是fat16或ext2;windows NT是fat16、NTFS;windows98是fat16、fat32;windows2000和windowsXP是fat16、fat32、 NTFS。掛載前要了解linux是否支持所要掛載的文件系統格式。
掛載時使用mount命令:
格式:mount [-參數] [設備名稱] [掛載點]
其中常用的參數有
-t<文件系統類型> 指定設備的文件系統類型,常見的有:
minix linux最早使用的文件系統
ext2 linux目前常用的文件系統
msdos MS-DOS的fat,就是fat16
vfat windows98常用的fat32
nfs 網絡文件系統
iso9660 CD-ROM光盤標準文件系統
ntfs windows NT 2000的文件系統
hpfs OS/2文件系統
auto 自動檢測文件系統
-o<選項> 指定掛載文件系統時的選項。有些也可用在/etc/fstab中。常用的有
codepage=XXX 代碼頁
iocharset=XXX 字符集
ro 以只讀方式掛載
rw 以讀寫方式掛載
nouser 使一般用戶無法掛載
user 可以讓一般用戶掛載設備
提醒一下,mount命令沒有建立掛載點的功能,因此你應該確保執行mount命令時,掛載點已經存在。(不懂?說白了點就是你要把文件系統掛載到哪,首先要先建上個目錄。這樣OK?)
例子:windows98裝在hda1分區,同時計算機上還有軟盤和光盤需要掛載。
# mk /mnt/winc
# mk /mnt/floppy
# mk /mnt/cdrom
# mount -t vfat /dev/hda1 /mnt/winc
# mount -t msdos /dev/fd0 /mnt/floppy
# mount -t iso9660 /dev/cdrom /mnt/cdrom
現在就可以進入/mnt/winc等目錄讀寫這些文件系統了。
要保證最后兩行的命令不出錯,要確保軟驅和光驅里有盤。(要是硬盤的磁盤片也可以經常隨時更換的話,我想就不會犯這樣的錯誤了 :-> )
如果你的windows98目錄里有中文文件名,使用上面的命令掛載后,顯示的是一堆亂碼。這就要用到 -o 參數里的codepage iocharset選項。codepage指定文件系統的代碼頁,簡體中文中文代碼是936;iocharset指定字符集,簡體中文一般用cp936或 gb2312。
當掛載的文件系統linux不支持時,mount一定報錯,如windows2000的ntfs文件系統。可以重新編譯linux內核以獲得對該文件系統的支持。關于重新編譯linux內核,就不在這里說了。
自動掛載
每次開機訪問windows分區都要運行mount命令顯然太煩瑣,為什么訪問其他的linux分區不用使用mount命令呢?
其實,每次開機時,linux自動將需要掛載的linux分區掛載上了。那么我們是不是可以設定讓linux在啟動的時候也掛載我們希望掛載的分區,如windows分區,以實現文件系統的自動掛載呢?
這是完全可以的。在/etc目錄下有個fstab文件,它里面列出了linux開機時自動掛載的文件系統的列表。我的/etc/fstab文件如下:
/dev/hda2 / ext3 defaults 1 1
/dev/hda1 /boot ext3 defaults 1 2
none /dev/pts devpts gid=5,mode=620 0 0
none /proc proc defaults 0 0
none /dev/shm tmpfs defaults 0 0
/dev/hda3 swap swap defaults 0 0
/dev/cdrom /mnt/cdrom iso9660 noauto,codepage=936,iocharset=gb2312 0 0
/dev/fd0 /mnt/floppy auto noauto,owner,kudzu 0 0
/dev/hdb1 /mnt/winc vfat defaults,codepage=936,iocharset=cp936 0 0
/dev/hda5 /mnt/wind vfat defaults,codepage=936,iocharset=cp936 0 0
在/etc/fstab文件里,第一列是掛載的文件系統的設備名,第二列是掛載點,第三列是掛載的文件系統類型,第四列是掛載的選項,選項間用逗號分隔。第五六列不知道是什么意思,還望高手指點。
在最后兩行是我手工添加的windows下的C;D盤,加了codepage=936和iocharset=cp936參數以支持中文文件名。參數defaults實際上包含了一組默認參數:
rw 以可讀寫模式掛載
suid 開啟用戶ID和群組ID設置位
dev 可解讀文件系統上的字符或區塊設備
exec 可執行二進制文件
auto 自動掛載
nouser 使一般用戶無法掛載
async 以非同步方式執行文件系統的輸入輸出操作
大家可以看到在這個列表里,光驅和軟驅是不自動掛載的,參數設置為noauto。(如果你非要設成自動掛載,你要確保每次開機時你的光驅和軟驅里都要有盤,呵呵。)
posted @
2006-06-06 00:36 Jerry Cat 閱讀(551) |
評論 (0) |
編輯 收藏
Windows調試命令 NTSD
http://www.shnenglu.com/jerysun0818/archive/2006/06/06/8193.html
問
:
怎么才能關掉一個用任務管理器關不了的進程?我前段時間發現我的機子里多了一個進程,只要開機就在,我用任務管理器卻怎么關也關不了
答
1:
殺進程很容易,隨便找個工具都行。比如
IceSword
。關鍵是找到這個進程的啟動方式,不然下次重啟它又出來了。順便教大家一招狠的。其實用
Windows
自帶的工具就能殺大部分進程:
c:\>ntsd -c q -p PID
只有
System
、
SMSS.EXE
和
CSRSS.EXE
不能殺。前兩個是純內核態的,最后那個是
Win32
子系統,
ntsd
本身需要它。
ntsd
從
2000
開始就是系統自帶的用戶態調試工具。被調試器附著
(attach)
的進程會隨調試器一起退出,所以可以用來在命令行下終止進程。使用
ntsd
自動就獲得了
debug
權限,從而能殺掉大部分的進程。
ntsd
會新開一個調試窗口,本來在純命令行下無法控制,但如果只是簡單的命令,比如退出
(q)
,用
-c
參數從命令行傳遞就行了。
NtsdNtsd
按照慣例也向軟件開發人員提供。只有系統開發人員使用此命令。有關詳細信息,請參閱
NTSD
中所附的幫助文件。用法
:
開個
cmd.exe
窗口,輸入:
ntsd -c q -p PID
把最后那個
PID
,改成你要終止的進程的
ID
。如果你不知道進程的
ID
,任務管理器-進程選項卡-
>
查看-
>
選擇列-
>
勾上
"PID
(進程標識符)
"
,然后就能看見了。
答
2
:
xp
下還有兩個好東東
tasklist
和
tskill
。
tasklist
能列出所有的進程,和相應的信息。
tskill
能查殺進程,語法很簡單:
tskill
程序名!
posted @
2006-06-06 00:11 Jerry Cat 閱讀(270) |
評論 (0) |
編輯 收藏
[轉]Track'em Down...
http://www.shnenglu.com/jerysun0818/archive/2006/06/04/8153.html
P.S. 很多朋友都抱怨說STL出問題的時候debug很難,編譯期錯誤算是輕的,大不了一串串令人頭暈的出錯信息,至少還能雙擊定位到錯誤行。而神秘的運行期崩潰才是真正令人頭大的問題。下面就是一個比較典型的、五臟俱全的運行期崩潰事件,從幾行簡簡單單的代碼,似乎根本不可能崩潰,一直到最后揪出隱藏在背后的機制。其中的思維分析過程是怎樣的呢?希望對一些朋友有點幫助。標題起作”Track’em Down”一方面是暗指整個分析跟蹤的過程,而是最后所揭露出的機制的確是個tracking機制:-)
很久沒寫blog了,一來是諸事纏身,二來也是實在不像以前那么有熱情坐下來好好寫篇技術文章了。很多時候只是做個旁觀者,四處潛水而已。昨天又跟老婆鬧了矛盾,心里郁悶,于是給自己一個理由四處亂逛,跑到許久未去的cpper(
http://www.cpper.com/c/
)上,cpper還是一如既往的冷清,看來一個論壇要想火起來光靠技術是不行的,cpper(前身為allaboutprogram)圈子里有一批技術很牛的朋友,也許是太牛了,這兩年都開始一個個牛得沒影兒了。二來cpper不像CSDN這樣有一個門戶,主頁上有亂七八糟的好玩信息,新聞,八卦,等等不一而足。國內C++社群的大部分朋友想必是不知道cpper的,尤其是初學者。實在是個不小的遺憾…等等…似乎扯遠了,剛才說到逛到cpper上,看到tomato的一個帖子,提到一段行為怪異的代碼,行為是崩潰,而且是在l析構的時候崩潰:
#include <list>
????????
??????????
int main(int argc, char* argv[])
{
? ? std::list<int> l;
? ? std::list<int>::iterator* it1 = new std::list<int>::iterator(l.begin());
? ? memset(it1, 1, sizeof(std::list<int>::iterator));
? ? l.push_back(1);
? ? l.begin();
? ? return0;
以上是原貼里的代碼,我就不簡化了。大伙看著辦吧,呵呵。
乍看上去這段代碼似乎不應該有什么問題(至少不會崩潰)。最可疑的當然是那行memset,但memset只是把it1指向的一個new出來的iterator給corrupt掉了,況且這個it1也沒被delete,所以也就不會因析構而崩潰了(雖然有內存泄漏,但tomato說的是崩潰),另外it1跟l看上去是井水不犯河水。所以怎么看不像有問題的樣子。
以上是眼睜睜瞪著代碼看出來的結果,然而當我把代碼塞到IDE里面,編譯運行之后卻發現果然如tomato所說,在list析構時程序崩潰了(很湊巧我跟tomato用的IDE都是VC8,這是一個關鍵條件)。對于這類問題,一般我是先黑箱再白箱。這么短的程序,要出問題肯定出在memset那行,邏輯上可以大致這么說:“由于memset把it1的內存corrupt掉了,結果導致l在析構的時候崩潰?!甭牭阶约合逻@么個結論我都覺得有點哭笑不得,這壓根兒風馬牛不相及嘛,it1被corrupt與l析構崩潰有屁關系?!it1只不過是個指向l的迭代器,說穿了就是裹著個指向l中的某個node的指針而已,它的死活怎么會影響到l的析構呢?
但福爾摩斯大致說過,去掉那些絕對不可能的,剩下的就是可能。這里這是唯一的可能,只不過問題是,這個邏輯還不夠細致,需要豐滿起來。進一步,要想使得l在析構的時候崩潰,這個memset肯定以某種方式影響到了l。又因為memset直接影響的是it1,那么必然是it1和l的某種聯系導致memset間接對l產生了影響。于是再來看,it1和l有什么聯系呢?得!這下看出來了,it1在構造的時候是通過l.begin()拷貝構造的,哈!問題似乎有點眉目了,但到此我還是想不通,根據常識,iterator的拷貝構造會產生出一個與源iterator不相干的副本,對這個副本干什么事怎么會影響到源呢?更別提影響到源iterator所指向的容器了。開玩笑!甭管他,既然已經肯定下來這是唯一的可能,那么推論只能是:背后還隱藏著什么不為人之的東西。于是進一步注釋掉“(l.begin())”,使it1變成缺省構造的迭代器,果然,不再崩潰了。于是,現在可以肯定作出的結論是:“… it1 = new std::list<int>::iterator(l.begin());這行代碼使得it1所指向的迭代器與l發生了某些關系(當然,不是it1指向l這樣的白癡關系)。很顯然,這個關系的建立點不可能是在l.begin(),因為這里還沒有涉及到it1,所以唯一的可能就是,這個關系是在std::list<int>::iterator的拷貝構造函數階段發生的。這次拷貝構造以l.begin()為參數,而l.begin()推測起來應當帶了l的信息,因而it1就利用這個機會與l建立起了“某種關系”。OK,到目前為止這個“某種關系”只是一個模糊的概念,我們并不明確知道究竟是什么關系,竟然導致list析構會失敗。看來是時候進入白箱了,F5,break,看斷在什么地方了,說實話P.J Plauger寫的STL代碼至少在外觀上不像SGI的那么親近人,nevermind,我看到了我想看到的信息——一個名為_HAS_ITERATOR_DEBUGGING的宏,哈,想起來了,這一版的STL是帶有iterator debugging功能的,所以當然能夠發現iterator被corrupt掉的情況。疑問來了,怎么發現的呢?直接的答案是,肯定有某種追蹤機制,而且根據前面的推理,由于是l在析構的時候發生的崩潰(it1并不析構,因為并沒有對它進行delete),所以l在析構的時候必然能以某種方式訪問到it1并發現它被corrupt掉的事實,再推廣之,l肯定能夠訪問到所有指向它的迭代器(這才叫iterator debugging嘛),而it1在構建的時候的確是拷貝構造l.begin()來的,也就是說指向l,所以l必然應當知道(跟蹤)它(it1)的存在,又因為接下來的memset是個相當low level/native的操作,所以l對此肯定不知情,還以為it1一直好端端的指著它的begin()處呢,最后當它一個個察訪指向它內部的迭代器,當查訪到it1時就發現it1被corrupt掉了,于是崩潰。呼~一切到這里似乎都串起來了。剩下的就是去發現list<int>::iterator的拷貝構造函數究竟在背后搗了什么鬼才使得l最終能夠訪問到it1的,在開始之前我就設想一個場景:肯定是l里面有一個鏈表,把所有指向它內部的迭代器串起來了,這樣它就能夠逐一檢查這些迭代器,看看比如說它們是否越界之類的。而it1在拷貝構造的時候由于是以l.begin()為參數的,l.begin()肯定帶有l的信息,說白了,指向l的指針,或l的引用,于是it1的拷貝構造函數就可以把自身鏈入l內部的鏈表中去。想到這里似乎情況十分明朗了,剩下的就是跟蹤進去驗證一下了…但是等一下…剛才說到,程序的現象是…崩潰!如果是在l對它的迭代器check的時候發現錯誤,大腦沒毛病的庫設計者肯定會拋出一個異常吧,不會是崩潰的癥狀…what the hell。反正我已經知道問題的核心在list<int>::iterator的拷貝構造函數那里,那是唯一同時擁有it1與l信息的地方。于是F11到list<int>::iterator的拷貝構造處,即“… it1 = new std::list<int>::iterator(l.begin());”這行代碼處,郁悶的是,調試器在這里一跳而過,似乎它擁有的是一個trivial的拷貝構造函數(從后來的結果來看這似乎是VC2005的一個小問題),而且我”go to disassembly”居然也就看到聊聊幾行代碼,除了一個對list<int>::begin()的調用之外就沒有其它調用了,傻眼了,似乎真的是個trivial的copy ctor?如果真是這樣的話,就不可能在這里建立起it1跟l之間的聯系了,因為trivial的copy constructing只會是把成員按位復制一下,沒有其它代碼,不涉及函數調用,怎么可能會有機會干其它事情呢?而后面又沒有任何地方同時涉及it1跟l的,那又怎么會最終導致l析構崩潰呢?簡單的推理,反推上去,既然l最終析構崩潰了,那么這個邏輯的某一環肯定錯了,最可能的就是,這并非trivial copy ctor,調試器欺騙了我的眼睛,背后肯定調用了某個拷貝構造函數,然后干了些勾當。于是靜態跟蹤派上了用場,幸好VS2005的intelli-sense非常強大,兩次“go to definition”就置身于了list<int>::iterator的定義里面,剛才不是說關鍵就在list<int>::iterator的拷貝構造函數里面嗎?于是瀏覽一下list<int>::iterator的定義,VC帶的STL的代碼真難看啊,好在這個類比較短,很遺憾,沒有拷貝構造函數,只有構造函數,不過碰巧,在其中一個由_HAS_ITERATOR_DEBUGGING條件控制的構造函數里面發現了一行寶貴的代碼:this->_Adopt(_Plist);,如果沒猜錯,這肯定是把這個迭代器自身鏈到它所指向的容器內的跟蹤鏈表中去的。_Plist(該構造函數的第二個參數)是什么?跟蹤到l.begin()調用里面就會發現,喂給list<int>::iterator的構造函數的第二個參數(也就是_Plist)是this,呵呵,看來this->_Adopt(_Plist)實際上就是把this(迭代器)“收養(adopt)”給_Plist啊。沒猜錯,果然是這樣的跟蹤機制。那么,照理說list<int>::iterator的拷貝構造函數也應該有相應的動作才對啊,不然拷貝構造出的新的iterator就會沒人“收養”了(而我們的跟蹤機制是應當跟蹤到每個“在世”的iterator的,否則就沒意義了)。剛才提到,list<int>::iterator本身沒有拷貝構造函數,那么只有一種可能,要么其成員具有non-trivial的拷貝構造函數,要么在基類里面。實際上list<int>::iterator只有一個成員,一如我們意料之中的,指向list的node的ptr。所以秘密肯定在基類中,順著基類一路找下去,_Const_iterator->_Bidit->_Iterator_base。說實話到_Bidit差點放棄,因為我以為_Bidit里面肯定就是一些typedef,就像unary_function那樣。事實卻不是這樣,下面還隱藏了一層_Iterator_base,而這個_Iterator_base就是一切秘密所在了。它是有拷貝構造函數的,代碼我就不列了,如果你跟蹤到這里,真相也就大白了,簡單的來說,它根據源iterator找到其所指的容器,然后取出該容器里面的用于跟蹤迭代器的鏈表頭指針,然后把自身(this)鏈到這個鏈表里面去。由于一個iterator誕生的方式一共就兩種,一種是從某個容器誕生,這時是調用的它的一般構造函數,容器會把自身的指針當作參數傳遞給這個iterator,后者通過這個容器指針來將其自身鏈接到容器的跟蹤鏈表中。第二個誕生方式就是這里說的,拷貝構造,拷貝構造時會將其自身鏈到源iterator所指向的容器內的跟蹤鏈表中去。反正就是,一切現有的iterator都會恰當被它所指的容器跟蹤著。
那么是時候揭穿謎底了吧,為什么memset會闖下這么大的禍?因為一個iterator要被鏈到鏈表里面,它肯定有next指針,這樣才能鏈成一個鏈表嘛。而memset粗暴地將這個next指針給重置了(事實上它把it1指向的迭代器整個給memset了,當然包括里面的next指針),這里,next指針被重置為了1(如果memset成0就不會崩潰了,原因很簡單,想想看),顯然,這就指向了一塊無意義的內存。于是,l在析構的時候,試圖遍歷并check它所跟蹤的iterator鏈表,隨著它通過next指針一節節跳轉,當到了我們的it1的時候,由于其next指針的值是1,所以試圖再跳(next)的時候就非法內存訪問了!崩潰!所以,這里的問題并不在于最后的check失敗了,而是在于迭代器鏈表被corrupt掉了,才導致的崩潰。這就解除了前面的關于未發生異常的疑惑。事情到此就大致結束了。
當然,這里還隱藏了很多的細節。例如最后l析構時并不是要去“check”每個迭代器。另外這個iterator tracking的機制還是很有代表性的,boost::signal里面就用了如出一轍的手法,這個手法充分顯示出了C++的強大和靈活。原來看上去毫不起眼的構造函數在背后還能做那么多工作。這里就不方方面面總結這一技術了,一是困了,二是這不是這篇blog的初衷,寫這篇blog一是為了平靜一下郁悶的心情,二是為了顯示一個從現象開始分析推理問題,最終接近答案的過程。程序員的大部分時間是在debug,這篇blog其實介紹的就相當于一個debug的思維過程,或許它并不是最好的,但希望你能夠在其中發現一些有用的東西。
P.S. 看上去啰啰嗦嗦一大通,實際上在腦子里轉來轉去是一瞬間的工夫,加上跟蹤(靜態/動態)也就十來分鐘,而寫這篇blog倒花了我四十多分鐘(這也是越來越不寫blog的原因吧),人類自然語言的表達力某些時候是十分啰唆冗余的…
posted @
2006-06-04 19:52 Jerry Cat 閱讀(320) |
評論 (0) |
編輯 收藏