『壹』 C++ 類的前置聲明為什麼有時不起作用,VC6.0編譯器
你應該列出你認為不起作用的對應代碼
前置聲明只說明有這么個類,類的具體定義是未知的。如果你使用類的任何信息,都是錯誤的。你只能用它的指針或者引用
『貳』 Qt:在頭文件中既包含QDialog的頭文件,也採用了對QCheckBox類的前置聲明,可以都採用頭文件或前置聲明嗎
包含頭文件可以,前置聲明也行,採用前置聲明是為了提高編譯速度,因為編譯器只需知道該類已經被定義了,而無需了解定義的細節
『叄』 C++:如何通過編碼技巧加快大項目重新編譯的速度
如果你覺得重新編譯文件的時間很短或者時間長一點無所謂,反正需要重新編譯,那麼你也可以選擇略過此文,不過也建議瀏覽。 如果你想學習或者關心這塊內容,那麼此文必定會給你帶來收獲。 首先我不給出依存關系的定義,我給出一個例子。 1 class Peopel{ 2 public: 3 People(const std::string & name,const Date& brithday,Image Img) 4 std::string name( ) const; 5 Date birthDate( ) const; 6 Image img( ) const; 7 … 8 private: 9 std::string theName; //名字 10 Date theBirthDate; //生日 11 Image img; //圖片 12 }; 如果編譯器沒有知道類string,Date和Image的定義,class People是無法通過編譯的。一般該定義式是由#include包含的頭文件所提供的,所以一般People上面有這些預處理命令 1 #include <string> 2 #include "date.h" 3 #inblude "image.h" 4 class Peopel{ 5 public: 6 People(const std::string & name,const Date& brithday,Image Img) 7 std::string name( ) const; 8 Date birthDate( ) const; 9 Image img( ) const; 10 … 11 private: 12 std::string theName; //名字 13 Date theBirthDate; //生日 14 Image img; //圖片 15 }; 那麼這樣People定義文件與該三個文件之間就形成了一種編譯依存關系。如果這些頭文件任何一個文件被改變,或這些頭文件所依賴其他頭文件任何改變,那麼每一個包含People類的文件就需要重新編譯,使用People類文件也需要重新編譯。想想如果一個項目包含一個上千的文件,每個文件包含其他幾個文件,依次這樣下來,改動一個文件內容,那麼就需要幾乎重新編譯整個項目了,這可以說很槽糕了。 我們可以進行如下改動 1 namespace std { 2 class string; 3 } 4 class Date; 5 class Image; 6 7 class Peopel{ 8 public: 9 People(const std::string & name,const Date& brithday,Image& Img) 10 std::string name( ) const; 11 Date birthDate( ) const; 12 Image img( ) const; 13 … 14 private: 15 std::string theName; //名字 16 Date theBirthDate; //生日 17 Image img; //圖片 18 }; 這樣只有People該介面被改變時才會重新編譯,但是這樣有連個問題,第一點string不是class,它是個typedef basic_string<char> string.因此上述前置聲明不正確(附其在stl完全代碼);,正確的前置聲明比較復雜。其實對於標准庫部分,我們僅僅通過#include預處理命令包括進來就可以了。 1 #ifndef __STRING__ 2 #define __STRING__ 3 4 #include <std/bastring.h> 5 6 extern "C++" { 7 typedef basic_string <char> string; 8 // typedef basic_string <wchar_t> wstring; 9 } // extern "C++" 10 11 #endif 前置聲明還有一個問題,就是編譯器必須在編譯期間知道對象的大小,以便分配空間。 例如: 1 int main(int argv,char * argc[ ]) 2 { 3 int x; 4 People p( 參數 ); 5 … 6 } 當編譯器看到x的定義式,它知道必須分配多少內存,但是看到p定義式就無法知道了。但是如果設置為指針的話,就清楚了,因為指針本身大小編譯器是知道的。 #include <string> #include <memory> class PeopleImpl; class Date; class Image; class People{ public: People(const std::string & name, const Date& brithday, const Image &Img); std::string name( ) const; Date birthDate( ) const; Imge img( ) const; … private: PeopleImpl * pImpl; } PeopleImpl包含下面這三個數據,而People的成員變數指針指向這個PeopleImpl,那麼現在編譯器通過People定義就知道了其分配空間的大小了,一個指針的大小。 1 public PeopleImpl 2 { 3 public: 4 PeopleImple(…) 5 … 6 private: 7 std::string theName; //名字 8 Date theBirthDate; //生日 9 Image img; //圖片 10 } 這樣,People就完全與Date、Imge以及People的實現分離了上面那些類任何修改都不需要重新編譯People文件了。另外這樣寫加強了封裝。這樣也就降低了文件的依存關系。 這里總結下降低依存性方法: 1、如果可以類聲明就不要使用類定義了。 2、將數據通過一個指向該數據的指針表示。 3、為聲明式和定義式提供不同的頭文件。 這兩個文件必須保持一致性,如果有個聲明式被改變了,兩個文件都得改變。因此一般會有一個#include一個聲明文件而不是前置聲明若干函數。 像People這樣定 1 #include "People.h" 2 #include "PeopleImpl.h" 3 4 People::People(const std::string& name, const Date& brithday, const Image& Img) 5 :pImpl(new PersonImpl(name,brithday,addr)) 6 { } 7 std::string People::name( ) const 8 { 9 return pImpl->name( ); 10 } 而另外一種Handle類寫法是令People成為一種特殊的abstract base class稱為Interface類。看到interface這個關鍵字或許熟悉C#、java的同學可能已經恍然大悟了。這種介面它不帶成員變數,也沒有構造函數,只有一個virtual析構函數,以及一組純虛函數,用來表示整個介面。針對People而寫的interface class看起來是這樣的。 1 class People{ 2 public: 3 virtual ~People( ); 4 virtual std::string name( ) const = 0; 5 virtual Date brithDate( ) const =0; 6 virtual Image address( ) const =0; 7 … 8 }; 怎麼創建對象呢?它們通常調用一個特殊函數。這樣的函數通常稱為工廠函數或者虛構造函數。它們返回指針指向動態分配所得對象,而該對象支持interface類的介面。 1 class People { 2 public: 3 … 4 static People* create(const std::string& name,const Date& brithday, const Image& Img); 5 }; 支持interface類介面的那個類必須定義出來,而且真正的構造函數必須被調用 1 class RealPeople:public People{ 2 public: 3 RealPeople(const std::string& name,const Date& birthday,const Image& Img) 4 :theName(name),theBrithDate(brithday),theImg(Img) 5 {} 6 virtual ~RealPeople() { } 7 std::string name( ) const; 8 Date birthDate( ) const; 9 Image img( ) const; 10 private: 11 std::string theName; 12 Date theBirthDate; 13 Image theImg; 14 } 有了RealPeople類,我們People::create可以這樣寫 1 People* People::create(const std::string& name, const Date& birthday, const Image& Img) 2 { 3 return static_cast<People *>(new RealPerson(name,birthday,Img)); 4 } Handle類與interface類解除了介面和實現之間的耦合關系,從而降低了文件間的編譯依存性。但同時也損耗了一些性能與空間。
『肆』 為什麼我們前置聲明時,只能使用類型的指針和引用
你好:
對於前置的聲明,編譯器只檢查參數個數與類型,不檢查參數名,沒有分配內存。所以,只需要類型與個數即可。
祝你順利。
『伍』 如何加快C++代碼的編譯速度
一、代碼角度
1、在頭文件中使用前置聲明,而不是直接包含頭文件。
不要以為你只是多加了一個頭文件,由於頭文件的"被包含"特性,這種效果可能會被無限放大。所以,要盡一切可能使頭文件精簡。很多時候前置申明某個namespace中的類會比較痛苦,而直接include會方便很多,千萬要抵制住這種誘惑;類的成員,函數參數等也盡量用引用,指針,為前置聲明創造條件。
2、使用Pimpl模式
Pimpl全稱為Private Implementation。傳統的C++的類的介面與實現是混淆在一起的,而Pimpl這種做法使得類的介面與實現得以完全分離。如此,只要類的公共介面保持不變,對類實現的修改始終只需編譯該cpp;同時,該類提供給外界的頭文件也會精簡許多。
3、高度模塊化
模塊化就是低耦合,就是盡可能的減少相互依賴。這里其實有兩個層面的意思。一是文件與文件之間,一個頭文件的變化,盡量不要引起其他文件的重新編譯;二是工程與工程之間,對一個工程的修改,盡量不要引起太多其他工程的編譯。這就要求頭文件,或者工程的內容一定要單一,不要什麼東西都往裡面塞,從而引起不必要的依賴。這也可以說是內聚性吧。
以頭文件為例,不要把兩個不相關的類,或者沒什麼聯系的宏定義放到一個頭文件里。內容要盡量單一,從而不會使包含他們的文件包含了不需要的內容。記得我們曾經做過這么一個事,把代碼中最"hot"的那些頭文件找出來,然後分成多個獨立的小文件,效果相當可觀。
其實我們去年做過的refactoring,把眾多DLL分離成UI與Core兩個部分,也是有著相同的效果的 - 提高開發效率。
4、刪除冗餘的頭文件
一些代碼經過上十年的開發與維護,經手的人無數,很有可能出現包含了沒用的頭文件,或重復包含的現象,去掉這些冗餘的include是相當必要的。當然,這主要是針對cpp的,因為對於一個頭文件,其中的某個include是否冗餘很難界定,得看是否在最終的編譯單元中用到了,而這樣又可能出現在一個編譯單元用到了,而在另外一個編譯單元中沒用到的情況。
之前曾寫過一個Perl腳本用來自動去除這些冗餘的頭文件,在某個工程中竟然去掉多達了5000多個的include。
5、特別注意inline和template
這是C++中兩種比較"先進"的機制,但是它們卻又強制我們在頭文件中包含實現,這對增加頭文件的內容,從而減慢編譯速度有著很大的貢獻。使用之前,權衡一下。
二、綜合技巧
1、預編譯頭文件(PCH)
把一些常用但不常改動的頭文件放在預編譯頭文件中。這樣,至少在單個工程中你不需要在每個編譯單元里一遍又一遍的load與解析同一個頭文件了。
2、Unity Build
Unity Build做法很簡單,把所有的cpp包含到一個cpp中(all.cpp) ,然後只編譯all.cpp。這樣我們就只有一個編譯單元,這意味著不需要重復load與解析同一個頭文件了,同時因為只產生一個obj文件,在鏈接的時候也不需要那麼密集的磁碟操作了,估計能有10x的提高,看看這個視頻感受一下其做法與速度吧。
3、ccache
compiler cache, 通過cache上一次編譯的結果,使rebuild在保持結果相同的情況下,極大的提高速度。我們知道如果是build,系統會對比源代碼與目標代碼的時間來決定是否要重新編譯某個文件,這個方法其實並不完全可靠(比如從svn上拿了上個版本的代碼),而ccache判斷的原則則是文件的內容,相對來講要可靠的多。
很可惜的是,Visual Studio現在還不支持這個功能 - 其實完全可以加一個新的命令,比如cache build,介於build與rebuild之間,這樣,rebuild就可以基本不用了。
4、不要有太多的Additional Include Directories
編譯器定位你include的頭文件,是根據你提供的include directories進行搜索的。可以想像,如果你提供了100個包含目錄,而某個頭文件是在第100個目錄下,定位它的過程是非常痛苦的。組織好你的包含目錄,並盡量保持簡潔。
三、編譯資源
要提高速度,要麼減少任務,要麼加派人手,前面兩個方面講得都是減少任務,而事實上,在提高編譯速度這塊,加派人手還是有著非常重要的作用的。
1、並行編譯
買個4核的,或者8核的cpu,每次一build,就是8個文件並行著編,那速度,看著都爽。 要是你們老闆不同意,讓他讀讀這篇文章:Hardware is Cheap, Programmers are Expensive
2、更好的磁碟
我們知道,編譯速度慢很大一部分原因是磁碟操作,那麼除了盡可能的減少磁碟操作,我們還可以做的就是加快磁碟速度。比如上面8個核一塊工作的時候,磁碟極有可能成為最大的瓶頸。買個15000轉的磁碟,或者SSD,或者RAID0的,總之,越快越好。
3、分布式編譯
一台機子的性能始終是有限的,利用網路中空閑的cpu資源,以及專門用來編譯的build server來幫助你編譯才能從根本上解決我們編譯速度的問題,想想原來要build 1個多小時工程的在2分鍾內就能搞定,你就知道你一定不能沒有它 - Incredibuild。
4、並行,其實還可以這么做。
這是一個比較極端的情況,如果你用了Incredibuild,對最終的編譯速度還是不滿意,怎麼辦?其實只要跳出思維的框架,編譯速度還是可以有質的飛躍的 - 前提是你有足夠多的機器:
假設你有solution A和solution B,B依賴於A,所以必須在A之後Build B。其中A,B Build各需要1個小時,那麼總共要2個小時。可是B一定要在A之後build嗎?跳出這個思維框架,你就有了下述方案:
◦同時開始build A和B 。
◦A的build成功,這里雖然B的build失敗了,但都只是失敗在最後的link上。
◦重新link B中的project。
這樣,通過讓A的build與B的編譯並行,最後link一下B中的project,整個編譯速度應該能夠控制在1個小時15分鍾之內。
『陸』 將對靜態數據成員初始化語句刪除或者移到主函數體內,編譯程序會出現什麼現象
可以通過以下幾個例子更形象的說明這個問題:
//test.cpp
#include <stdio.h>
class A {
public:
static int a; //聲明但未定義
};
int main() {
printf("%d", A::a);
return 0;
}
編譯以上代碼會出現「對『A::a』未定義的引用」錯誤。這是因為靜態成員變數a未定義,也就是還沒有分配內存,顯然是不可以訪問的。
再看如下例子:
//test.cpp
#include <stdio.h>
class A {
public:
static int a; //聲明但未定義
};
int A::a = 3; //定義了靜態成員變數,同時初始化。也可以寫"int A:a;",即不給初值,同樣可以通過編譯
int main() {
printf("%d", A::a);
return 0;
}
這樣就對了,因為給a分配了內存,所以可以訪問靜態成員變數a了。
因為類中的靜態成員變數僅僅是聲明,暫時不需分配內存,所以我們甚至可以這樣寫代碼:
//a.cpp
class B; //這里我們使用前置聲明,完全不知道B是什麼樣子
class A {
public:
static B bb;//聲明了一個類型為B的靜態成員,在這里編譯器並未給bb分配內存。
//因為僅僅是聲明bb,所以編譯器並不需要知道B是什麼樣子以及要給其對應的對象分配多大的空間。
//所以使用前置聲明"class B"就可以保證編譯通過。
};
使用命令"g++ -c -o a.o a.cpp"通過編譯。
對於類來說,new一個類對象不僅會分配內存,同時會調用構造函數進行初始化,所以類對象的定義和初始化總是關聯在一起。
『柒』 有關C++的問題~~請教
1、就是在dlg2.h的文件中為何非得加上class CDlg1;??
當然需要,在dlg2中也要加上對dlg1的引用,用class CDlg1是為避免循環重復引用。
2、道理同上。
看下面的詳細解釋:
一、類嵌套的疑問
C++頭文件重復包含實在是一個令人頭痛的問題,前一段時間在做一個簡單的數據結構演示程序的時候,不只一次的遇到這種問題。假設我們有兩個類A和B,分別定義在各自的有文件A.h和B.h中,但是在A中要用到B,B中也要用到A,但是這樣的寫法當然是錯誤的:
class B;
class A
{
public:
B b;
};
class B
{
public:
A a;
};
因為在A對象中要開辟一塊屬於B的空間,而B中又有A的空間,是一個邏輯錯誤,無法實現的。在這里我們只需要把其中的一個A類中的B類型成員改成指針形式就可以避免這個無限延伸的怪圈了。為什麼要更改A而不是B?因為就算你在B中做了類似的動作,也仍然會編譯錯誤,表面上這僅僅上一個先後順序的問題。
為什麼會這樣呢?因為C++編譯器自上而下編譯源文件的時候,對每一個數據的定義,總是需要知道定義的數據的類型的大小。在預先聲明語句class B;之後,編譯器已經知道B是一個類,但是其中的數據卻是未知的,因此B類型的大小也不知道。這樣就造成了編譯失敗,VC++6.0下會得到如下編譯錯誤:
error C2079: 『b』 uses undefined class 『B』
將A中的b更改為B指針類型之後,由於在特定的平台上,指針所佔的空間是一定的(在Win32平台上是4位元組),這樣可以通過編譯。
二、不同頭文件中的類的嵌套
在實際編程中,不同的類一般是放在不同的相互獨立的頭文件中的,這樣兩個類在相互引用時又會有不一樣的問題。重復編譯是問題出現的根本原因。為了保證頭文件僅被編譯一次,在C++中常用的辦法是使用條件編譯命令。在頭文件中我們常常會看到以下語句段(以VC++6.0自動生成的頭文件為例):
#if !defined(AFX_STACK_H__1F725F28_AF9E_4BEB_8560_67813900AE6B__INCLUDED_)
#define AFX_STACK_H__1F725F28_AF9E_4BEB_8560_67813900AE6B__INCLUDED_
//很多語句……
#endif
其中首句#if !defined也經常做#ifndef,作用相同。意思是如果沒有定義過這個宏,那麼就定義它,然後執行直到#endif的所有語句。如果下次在與要這段代碼,由於已經定義了那個宏,因此重復的代碼不會被再次執行。這實在是一個巧妙而高效的辦法。在高版本的VC++上,還可以使用這個命令來代替以上的所有:
#pragma once
它的意思是,本文件內的代碼只被使用一次。
但是不要以為使用了這種機制就全部搞定了,比如在以下的代碼中:
//文件A.h中的代碼
#pragma once
#include 「B.h」
class A
{
public:
B* b;
};
//文件B.h中的代碼
#pragma once
#include 「A.h」
class B
{
public:
A* a;
};
這里兩者都使用了指針成員,因此嵌套本身不會有什麼問題,在主函數前面使用#include 「A.h」之後,主要編譯錯誤如下:
error C2501: 『A』 : missing storage-class or type specifiers
仍然是類型不能找到的錯誤。其實這里仍然需要前置聲明。分別添加前置聲明之後,可以成功編譯了。代碼形式如下:
//文件A.h中的代碼
#pragma once
#include 「B.h」
class B;
class A
{
public:
B* b;
};
//文件B.h中的代碼
#pragma once
#include 「A.h」
class B;
class B
{
public:
A* a;
};
這樣至少可以說明,頭文件包含代替不了前置聲明。有的時候只能依靠前置聲明來解決問題。我們還要思考一下,有了前置聲明的時候頭文件包含還是必要的嗎?我們嘗試去掉A.h和B.h中的#include行,發現沒有出現新的錯誤。那麼究竟什麼時候需要前置聲明,什麼時候需要頭文件包含呢?
三、兩點原則
頭文件包含其實是一想很煩瑣的工作,不但我們看著累,編譯器編譯的時候也很累,再加上頭文件中常常出現的宏定義。感覺各種宏定義的展開是非常耗時間的,遠不如自定義函數來得速度。我僅就不同頭文件、源文件間的句則結構問題提出兩點原則,僅供參考:
第一個原則應該是,如果可以不包含頭文件,那就不要包含了。這時候前置聲明可以解決問題。如果使用的僅僅是一個類的指針,沒有使用這個類的具體對象(非指針),也沒有訪問到類的具體成員,那麼前置聲明就可以了。因為指針這一數據類型的大小是特定的,編譯器可以獲知。
第二個原則應該是,盡量在CPP文件中包含頭文件,而非在頭文件中。假設類A的一個成員是是一個指向類B的指針,在類A的頭文件中使用了類B的前置聲明並便宜成功,那麼在A的實現中我們需要訪問B的具體成員,因此需要包含頭文件,那麼我們應該在類A的實現部分(CPP文件)包含類B的頭文件而非聲明部分(H文件)。
『捌』 C++類的前置聲明問題
因為編碼器在讀到X obj;時還不知道X的大小,無法為class Y分配內存空間。
如果把聲明順序反一下就可以通過了。
class Y;
class X{
private: Y* ptr; //這里雖然Y還沒有聲明,但編碼器知道這是一個指針,至於指向什麼數據可以先不關心。
};
class Y{
X obj;
};
int main()
{
Y y;
return 0;
}
『玖』 還是 關於一個C++的小問題
我也是網上搜集的,對你的問題逐個進行解答
一。
1、什麼是const?
常類型是指使用類型修飾符const說明的類型,常類型的變數或對象的值是不能被更新的。
為什麼引入const?
const 推出的初始目的,正是為了取代預編譯指令,消除它的缺點,同時繼承它的優點。
3、cons有什麼主要的作用?
(1)可以定義const常量,具有不可變性。 例如:
const int Max=100; int Array[Max];
(2)便於進行類型檢查,使編譯器對處理內容有更多了解,消除了一些隱患。例如: void f(const int i) { .........} 編譯器就會知道i是一個常量,不允許修改; (3)可以避免意義模糊的數字出現,同樣可以很方便地進行參數的調整和修改。 同宏定義一樣,可以做到不變則已,一變都變!如(1)中,如果想修改Max的內容,只需要:const int Max=you want;即可!
(4)可以保護被修飾的東西,防止意外的修改,增強程序的健壯性。 還是上面的例子,如果在函數體內修改了i,編譯器就會報錯; 例如:
void f(const int i) { i=10;//error! }
(5) 為函數重載提供了一個參考。
class A { ......
void f(int i) {......} //一個函數
void f(int i) const {......} //上一個函數的重載 ......
};
(6) 可以節省空間,避免不必要的內存分配。 例如:
#define PI 3.14159 //常量宏
const doulbe Pi=3.14159; //此時並未將Pi放入ROM中 ......
double i=Pi; //此時為Pi分配內存,以後不再分配!
double I=PI; //編譯期間進行宏替換,分配內存
double j=Pi; //沒有內存分配
double J=PI; //再進行宏替換,又一次分配內存!
const定義常量從匯編的角度來看,只是給出了對應的內存地址,而不是象#define一樣給出的是立即數,所以,const定義的常量在程序運行過程中只有一份拷貝,而#define定義的常量在內存中有若干個拷貝。
(7) 提高了效率。 編譯器通常不為普通const常量分配存儲空間,而是將它們保存在符號表中,這使得它成為一個編譯期間的常量,沒有了存儲與讀內存的操作,使得它的效率也很高。
4、如何使用const?
(1)修飾一般常量 一般常量是指簡單類型的常量。這種常量在定義時,修飾符const可以用在類型說明符前,也可以用在類型說明符後。 例如:
int const x=2; 或 const int x=2;
(2)修飾常數組 定義或說明一個常數組可採用如下格式:
int const a[5]={1, 2, 3, 4, 5};
const int a[5]={1, 2, 3, 4, 5};
(3)修飾常對象 常對象是指對象常量,定義格式如下:
class A; const A a;
A const a; 定義常對象時,同樣要進行初始化,並且該對象不能再被更新,修飾符const可以放在類名後面,也可以放在類名前面。
(4)修飾常指針
const int *A; //const修飾指向的對象,A可變,A指向的對象不可變
int const *A; //const修飾指向的對象,A可變,A指向的對象不可變
int *const A; //const修飾指針A, A不可變,A指向的對象可變
const int *const A;//指針A和A指向的對象都不可變
(5)修飾常引用 使用const修飾符也可以說明引用,被說明的引用為常引用,該引用所引用的對象不能被更新。其定義格式如下:
const double & v;
(6)修飾函數的常參數 const修飾符也可以修飾函數的傳遞參數,格式如下:
void Fun(const int Var); 告訴編譯器Var在函數體中的無法改變,從而防止了使用者的一些無意的或錯誤的修改。
(7)修飾函數的返回值: const修飾符也可以修飾函數的返回值,是返回值不可被改變,格式如下:
const int Fun1(); const MyClass Fun2();
(8)修飾類的成員函數: const修飾符也可以修飾類的成員函數,格式如下:
class ClassName {
public:
int Fun() const; .....
}; 這樣,在調用函數Fun時就不能修改類裡面的數據
(9)在另一連接文件中引用const常量
extern const int i;//正確的引用
extern const int j=10;//錯誤!常量不可以被再次賦值 另外,還要注意,常量必須初始化! 例如: const int i=5;
具體請參看http://..com/question/91670015.html?si=1
二。區別是第一個3是實參,他在作為函數調用的時候傳遞給形參,第二個是函數的定義,括弧內的區別就是形參和實參的區別,其中t可以省略,如果傳遞的實參是3,那麼將3轉化為浮點形式的3.00000
三,這個問題看不開懂,你是問強制轉化的方向嗎?那麼是浮點型>整型>字元型
就是低精度的向高精度的轉化
四,sizeof用與測試變數類型長度(即所佔位元組數),格式sizeof( 變數類型 )
例如:測試整形int所佔位元組數 ,sizeof( int ),顯示結果:4
五,傳統 C/C++
#include <assert.h> //設定插入點
#include <ctype.h> //字元處理
#include <errno.h> //定義錯誤碼
#include <float.h> //浮點數處理
#include <fstream.h> //文件輸入/輸出
#include <iomanip.h> //參數化輸入/輸出
#include <iostream.h> //數據流輸入/輸出
#include <limits.h> //定義各種數據類型最值常量
#include <locale.h> //定義本地化函數
#include <math.h> //定義數學函數
#include <stdio.h> //定義輸入/輸出函數
#include <stdlib.h> //定義雜項函數及內存分配函數
#include <string.h> //字元串處理
#include <strstrea.h> //基於數組的輸入/輸出
#include <time.h> //定義關於時間的函數
#include <wchar.h> //寬字元處理及輸入/輸出
#include <wctype.h> //寬字元分類
//////////////////////////////////////////////////////////////////////////
標准 C++ (同上的不再注釋)
#include <algorithm> //STL 通用演算法
#include <bitset> //STL 位集容器
#include <cctype>
#include <cerrno>
#include <clocale>
#include <cmath>
#include <complex> //復數類
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque> //STL 雙端隊列容器
#include <exception> //異常處理類
#include <fstream>
#include <functional> //STL 定義運算函數(代替運算符)
#include <limits>
#include <list> //STL 線性列表容器
#include <map> //STL 映射容器
#include <iomanip>
#include <ios> //基本輸入/輸出支持
#include <iosfwd> //輸入/輸出系統使用的前置聲明
#include <iostream>
#include <istream> //基本輸入流
#include <ostream> //基本輸出流
#include <queue> //STL 隊列容器
#include <set> //STL 集合容器
#include <sstream> //基於字元串的流
#include <stack> //STL 堆棧容器
#include <stdexcept> //標准異常類
#include <streambuf> //底層輸入/輸出支持
#include <string> //字元串類
#include <utility> //STL 通用模板類
#include <vector> //STL 動態數組容器
#include <cwchar>
#include <cwctype>
using namespace std;
//////////////////////////////////////////////////////////////////////////
C99 增加
#include <complex.h> //復數處理
#include <fenv.h> //浮點環境
#include <inttypes.h> //整數格式轉換
#include <stdbool.h> //布爾環境
#include <stdint.h> //整型環境
#include <tgmath.h> //通用類型數學宏
六,strlen 是個函數,是求字元串的長度,不包括結尾的'\0'
格式 strlen(字元串指針); 比如r=strlen("student"),那麼r的值為7
strlen()+1就是自加1而已
好了,如果覺得可以就給分吧