天天看點

C++:數組、字元串、結構體、共用體、枚舉和指針字元串字元串結構體共用體枚舉指針和自由存儲空間

C++:數組、字元串和指針

  • 字元串
  • 字元串
    • C-風格字元串
    • 基于string類庫的字元串
  • 結構體
  • 共用體
  • 枚舉
  • 指針和自由存儲空間

字元串

要建立數組可以使用聲明語句。數組語句應該包含三個要素:

  • 存儲在每個元素中的值的類型;
  • 數組名;
  • 數組中的元素數

    通用格式為:

具體例子如下:

另外對數組使用sizeof函數可以得到數組的位元組數。

數組的初始化方式如下:

int demo1[]{ 1,2,3,4 };//等價于int number[4]={ 1,2,3,4 };
	int demo2[4]{};//在大括号中什麼都不加代表全0
           

如果隻初始化一部分元素則剩下的元素預設為0。

字元串

C++中字元串有兩種形式,一種是C-風格字元串,另一種基于string類庫的字元串。

C-風格字元串

對于C-風格字元串,其最後總是以’\0’結尾,是以在确定字元串數組的最短長度時,’\0’字元也應該被計算在内。如下所示:

char animal1[4] = { 'd','o','g','s' };//僅僅是一個char數組
	char animal2[4] = { 'c','a','t','\0' };//是一個字元串
	cout << animal1 << endl;//使用cout會導緻持續輸出直到遇到\0
	cout << animal2 << endl;//正常輸出
           

其初始化還有更加簡便的方法——字元串常量:

char animal3[] = "fish";
	cout << sizeof(animal3) << endl;
	//長度為5,最後一位為0,如果數組長度大于字元串常量長度,多餘的位置全部被指派為\0;得出結論:數組大小至少等于字元串長度+1
           

這裡"fish"就是一個字元串常量,其表示的實際上是該字元串常量(由’f’,‘i’,‘s’,‘h’,’\0’組成)所在的記憶體位址。

字元串可以進行拼接,将需要拼接的字元串放在一起即可,如下所示:

對于C-風格字元串我們常常使用sizeof和stlen計算其長度,其差別為:

  • sizeof運算指出的是整個字元串數組的長度,即初始化和未初始化的元素長度之和,機關為位元組;
  • strlen傳回的是儲存在字元串數組中字元串的長度(不包括’\0’),是以字元串的實際長度應該是strlen的傳回值加1。該函數的原理是從第一個元素開始依次掃描直到遇到’\0’,是以如果将未初始化的字元串數組傳入該函數,由于值不确定,傳回的長度也是不确定的。

将輸入的字元串傳入字元串數組中有多種方式,第一種就是使用cin,但是該方法有一個缺陷,那就是直接使用cin,其傳入的字元串會在遇到空白時結束,空白後面的剩餘字元串無法被存儲到字元串數組中。

另一個方法是使用cin.getline,第一個參數為用于存儲輸入字元串的數組名稱,第二個為需要讀取字元串的長度(包括’\0’)。

char name[20];
	cin.getline(name,20);//讀取20個字元儲存在name中,如果在讀取到第20個字元之前遇到了換行符則提前停止,并将遇到的換行符丢棄;
	cout << name;
           

與cin.getline類似的還有cin.get。cin.get遇到換行符停止後不會丢棄換行符。是以連續兩個get可能會導緻第二個get無法讀取到任何字元(碰到換行直接停止)。如果get不包含任何參數則會讀取一個字元,使用cin.get()可以來處理換行。

char name[20];
	cin.get(name, 20).get();//cin.get()會傳回一個cin對象,之後調用get讀取換行符
	int year;
	cin >> name;
	cout << name << "len:"<<strlen(name)<<endl;
           

基于string類庫的字元串

對于基于string類庫的字元串,使用前需要包含頭檔案stirng,未初始化之前長度為0,使用size()方法可以擷取字元串長度,其大小根據所賦的值由系統自行調整,是以更加安全。

其初始化可以直接使用字元串常量。

通過輸入來為字元串指派也有多種方法,其中一種就是直接使用cin,其缺點與C-風格字元串使用cin來初始化類似,遇到空白會自動停止。

也可以使用getline來對string進行初始化,其輸入的參數與cin.getline有差別,如下所示:

string str;
getline(cin, str);//第一個參數為輸入源,第二個為指派對象
           

C++ 11中加入了原始字元串的概念,原始字元串中不會進行轉義操作。其格式為以大寫R開頭,以"(開頭,以)"結尾。

結構體

結構的定義如下所示:

struct inflatable
	{
		char name[20];
		float volume;
		double price;
	};
           

結構體的聲明、内部元素的通路以及結構體數組的聲明如下所示:

inflatable hat = {"lee",1.88,29.99}; //初始化,等号也可以省略,不允許縮窄轉換
	hat.volume;//通路結構體中的元素
	//結構數組與其他數組類似,構造方式如下:
	inflatable guest[2] = {
		{"Bambi",0.5,21.99},
		{"Godzilla",2000,565.99}
	};
           

共用體

共用體Union,可以儲存不同類型的資料,但是同時隻能存儲一種,這樣可以達到節省記憶體的效果。

其聲明形式如下:

union one4all
	{
		int int_val;
		long long_val;
		double double_val;
	};
           

可以使用上述共用體存儲int、long或者double類型的資料,但是同一時刻隻能存儲一種資料。可以加入到結構體中。如果想要

匿名結構體:沒有名稱,裡面的成員是相同記憶體位址處的變量,其通路方式如下:

struct widget
	{
		char brand[20];
		int type;
		union
		{
			long id_num;
			char id_char[20];
		};
	};
	widget prize;
	if (prize.type == 1)  //直接将兩個變量看作是prize的兩個成員
	{
		cin >> prize.id_num;
	}
	else
	{
		cin >> prize.id_char;
	}
           

枚舉

使用枚舉類型可以輕易的定義常量,定義方式如下:

該語句首先定義了一種枚舉類型spectrum,其中read、orange、yellow則作為符号常量,分别代表0~7。

枚舉類型的值可以被提升為int型,但是不能反向轉換。是以該變量可以使用red、orange等等變量為其指派,但是不可以使用0~7為其指派(除非使用強制轉換)。如果隻打算使用定義的常量而不需要使用枚舉類型的變量,則枚舉類型的名稱可以省略:

enum {paramsError,memoryError,unkonwError}; //0~2分别代表參數錯誤、記憶體錯誤以及未知的錯誤
	cout << memoryError;
           

指針和自由存儲空間

在C++在變量名前加上&符号可以檢視該變量名的位址,儲存着記憶體位址的變量稱為指針,‘*’代表解除引用運算符,将其加在指針變量前則可以檢視儲存在對應記憶體位址的值。

聲明指針的格式為:

int* p1, * p2;//每聲明一個指針都要在前方加上*
	int foo = 100;
	p1 = &foo;//也可在聲明時直接指派
           

指針也存在着安全隐患,聲明一個指針隻會為其配置設定用于存儲位址的記憶體,但是不會為其配置設定指針所指向資料的記憶體,是以在對指針使用解除引用運算符(*)之前一定要對其進行初始化。

如果想對指針直接使用數字指派,則在這之前需要進行強制的類型轉換:

我們可以使用new進行動态記憶體的配置設定,在使用完成後應該使用delete對配置設定的記憶體進行釋放,數組和實體的delete方式有差別:

int arraySize = 20;
	int* pArray = new int[arraySize];//為數組動态配置設定記憶體
	delete []pArray;//釋放記憶體
	int* p = new int;//為一個實體配置設定記憶體
	delete p;//釋放記憶體
           

總之,new和delete之前必須遵守如下規則:

  • 不要使用delete來釋放不是new配置設定的記憶體;
  • 不要使用delete釋放同一塊記憶體兩次
  • 如果使用new[]為數組配置設定記憶體,則應該使用delete []來釋放
  • 如果使用new為一個實體配置設定記憶體,應使用delete(沒有方括号)來釋放。
  • 對空指針(指針中存儲的位址為0)使用delete是安全的

動态數組的通路:通路方式與數組的通路方式類似,事實上C++中數組和指針基本等價,不同的地方是可以修改指針的值但是不可以修改數組名的值,另外對數組使用sizeof函數傳回的将是數組的長度,而對指針使用則傳回的是指針的長度。對于整數變量,其加1之後其值會加1;而對于指針,其加1之後增加的兩等于它指向的類型的位元組數

pArray += 1;//此時應該指向的是第二個元素
	pArray -= 1;//此時應該指向的是第一個元素
           

如果使用cout顯示字元串指針,則會顯示字元串指針指向的内容,如果需要顯示字元串指針的位址則需要進行強制轉換。

char fruit[10] = "apple";
	char* pointer;
	pointer = fruit;
	cout << pointer << (int*)pointer << endl; //第一次輸入的是apple,第二次輸出的是位址
	pointer = new char[strlen(fruit) + 1];
	strcpy(pointer,fruit);//将fruit儲存的字元串複制到pointer指向的記憶體位址
	cout << pointer << (int*)pointer << endl;//發現位址改變
	char* newPointer = new char[10];
	strcpy(newPointer, "hello");
	cout << newPointer << endl;
           

對于指向結構體的指針,通路結構體成員應該使用->,如:inflatable *ps = new inflatable; ps->price//通路成員price。

繼續閱讀