《C++ Primer Plus》 學習筆記-第四章

1、數組(array)

  • 數組聲明:type name[10];注意:數組下標是從0開始,即0、1、2…9。
  • 數組的初始化規則:
  • 數組大小int a[x] x不能是變量(const 或者 固定),但可以使用new解決限制
//只有定義數組時才能使用聲明
float a[3] = {1,2,3};		//ok
float b[3];					//ok
b[3] = {1,2,3}				//not allowed
b = a;							//not allowed
//若只對一部分進行初始化,則其他爲0
int a[500] = {};	//全爲 0
int a[500] = {0};
int a[500] = {1};
int a[500] = {1,3};
//[]內爲空,自動計算其大小
short a[] = {1,2,3,4};
//c++11中初始化
double a[] = {1,2,3,4};
//列表初始化禁止縮窄轉換
  • 數組替代:C++模板類 array vector(後續會有)

字符串

char data[] = {'a','a',' ','a','\0'};		//檢測到空字符\0即停止
char data[] = "HAHAHHAHAHA";			//隱式包含結尾的空字符\0
cout<<"a b c " "d e f";					//拼接字符串常量
include <cstring>				//char 的string
const int Size = 15;
char name1[Size] ;
char name2[Size] = "C++ppp";
strlen(name2);	//字符長度
sizeof(name2);	//數組長度
cin>>name1;
name[3] = '\0';		//截斷name2
//name1顯示cin,name2顯示C++;
  • cin的控制輸入 空格即爲 \0
    cin.get()是保留回車在輸入流隊列中的,
    而cin是丟棄回車的。
  • 混合使用 cin>> 和 cin.get
    將 cin >> 與 cin.get 混合使用可能會導致煩人且難以發現的問題。請看下面的代碼段示例:
char ch;    //定義一個字符變量
int number; //定義一個整型變量
cout << "Enter a number:;
cin >> number;   // 讀取整數 丟棄換行符
cout << "Enter a character: ";
ch = cin.get() ;   // 讀取字符 包含換行符
cout << "Thank You!\n";

這些語句允許用戶輸入一個數字,而不是一個字符。看來第 6 行的 cin.get 語句已經被跳過了。這是因爲 cin>> 和 cin.get 使用略有不同的技術來讀取數據。
在示例代碼段中,當執行第 4 行時,用戶輸入一個數字,然後按回車鍵。假設輸入的是數字 100。按回車鍵會導致一個換行符(’\n’)存儲在鍵盤緩衝區數字 100 之後,如圖

cin.get和cin
第 4 行中的 cin>> 語句讀取用戶輸入的數據時,它會在遇到換行符時停止。換行字符未被讀取,而是仍保留在鍵盤緩衝區中。從鍵盤讀取數據的輸入語句只在鍵盤緩衝區爲空時等待用戶輸入值,但現在不爲空。
cin使用空白(空格、製表符和換行符)來確定字符串的結束位置,cin在獲取字符數組時只讀取一個單詞。

  • 面向行的輸入getline()
    通過回車鍵輸入的換行符來確定輸入結尾。但不保存換行符,而是用空字符來替換換行符。
    cin.getline(name,20);
    第一個參數是數組的名字,第二個參數是要讀取的字符數。20代表最多讀取19個字符,剩下的用於存儲自動添加的空字符。
  • 面向行的輸入get()
    get與getline類似,但是不讀取並丟棄換行符,而是將其留在隊列中。
    使用不帶任何參數的cin.get()調用讀取下一個字符,還可拼接cin.get(name,20).get();
    使用get()時檢查停止讀取的原因,查看下一個字符,若爲換行符,則說明讀取了整行。
    讀取空行時,使用cin.clear();恢復輸入。
  • 混合輸入字符串和數字
    cin讀取數字時,將回車鍵生成的換行符留在了隊列中,再使用cin.getline(),將會認爲是空行,使用cin.get()解決。
    P80頁
cin >> year ;
//添加一行  cin.get();  讀取掉換行符
cin.getline(a,20);

string類

include <string>
string str1 ;
string str2 = "hahahhaha";
cin>>str1;		//str1創建一個長度爲0的string對象,但讀取輸入之後,將自動調整str1的長度。
string str = str1 +str2;
cout<<str1.size();		//string類的size函數
getline(cin,str1);		//string類中的getline函數 ,讀取一行

C++11新的字符串類型

  • wchar_t、char16_t、char32_t
//三種類型分別加前綴 L,u,U 表示
wchar_t a[] = L"Chief";
char16_t a[] = u"hahha";
char32_t a[] = U"asaaaaaaaaaaaaaaa";
  • raw原始字符串:用R"( )"標識
    cout<<R"(hAHHHH "\n" )" 不會轉義;

2、結構

(例子:球隊成員名字,身高體重等)

#include <iostream>
#include <string>
using namespace std;
struct product 
{
	char name[10];
	string description;
	float volum;
	double price;
};
int main()
{
	product a =
	{
		"aaa","111",12,45
	};
	product b =
	{
		"bbb","222",23,545
	};
	cout << a.name << b.name << endl;
	getchar();
	return 0;
}

共用體

是一種數據格式,但是在某一句話中只能存儲一種類型的數據

union exam
{
	int a;
	double b;
}
exam.a = 15;
exam.b = 332.3;		//int丟失

枚舉

  • enum是一種新的創建符號常量的工具,可以替代const,還允許定義新類型
    enum spectrum(red=0, orange, yellow, green, blue, violet, indigo, ultraviolet)
    int i = red;
    spectrum:(枚舉)enumeration
    red等稱爲枚舉量 :對應爲0-7
  • 枚舉常量代表該枚舉類型的變量可能取的值,編譯系統爲每個枚舉常量指定一個整數值,默認狀態下,這個整數就是所列舉元素的序號,序號從0開始。 可以在定義枚舉類型時爲部分或全部枚舉常量指定整數值,在指定值之前的枚舉常量仍按默認方式取值,而指定值之後的枚舉常量按依次加1的原則取值。 各枚舉常量的值可以重複。
  • 枚舉常量只能以標識符形式表示,而不能是整型、字符型等文字常量
enum letter_set {'a','d','F','s','T'}; //枚舉常量不能是字符常量
enum year_set{2000,2001,2002,2003,2004,2005}; //枚舉常量不能是整型常量

3、指針和自由存儲空間

指針與C++基本原理

面向對象編程與傳統的過程性編程的區別在於,OOP強調的是在*運行階段(而不是編譯階段)進行決策。運行階段指的是程序正在運行時,編譯階段指的是編譯器將程序組合起來時。運行階段決策就好比度假時,選擇參觀那些景點取決於天氣和當時的心情;而編譯階段決策更像不管在什麼條件下,都堅持預先設定的日程安排。
運行階段決策提供了靈活性,可以根據當時的情況進行調整。例如,考慮爲數組分配內存的情況。傳統的方法是聲明一個數組。要在C+中聲明數組,必須指定數組的長度。因此,數組長度在程序編譯時就設定好了;這就是編輯階段決策。雖有可能在80%的情況下,一個包含20個元素的數組足夠了,但程序有時需要處理200個元素。爲了安全起見,使用了一個包含200個元素的數組。這樣,程序在大多數情況下都浪費了內存。OOP通過將這樣的決策推遲給運行階段進行,使程序更靈活。在程序運行後,可以這次告訴它只需要20個元素,而且還可以下次的時候告訴它需要205個元素。
總之,使用OOP時,您可以在運行階段確定數組的長度。爲了使用這種方法,語言必須允許在程序運行時創建數組。C++採用的方法是,使用關鍵字new請求正確數量的內存以及使用指針來跟蹤新分配的內存的位置。在運行階段作決策並非OOP獨有的,單使用C++編寫這樣的代碼比使用C語言簡單。

  • 使用常規變量:值是指定的量,而地址是派生量
  • 使用指針變量:地址是指定的量,而值是派生量
    int *p = 10;
    p:地址
    *p:地址所指向的量的值 (即:解除引用)
    (星號*取指針的值,&號取變量的地址)

聲明和初始化指針

*左右空格可選
int* a;C++常用( int*(新的類型):即指向int的指針)
int *a;
int * a;
int* a,b 創建了一個*a ,一個b,需要都加*

  • 使用指針的金科玉律
    在指針解除引用計算*之前,將指針初始化爲一個確定的、適當的地址。
int* p;
p = 0x800000;

這裏左邊是int*型,右邊是int型,不能賦值。
需要p = (int*)x0800000

new 和 delete

指針真正的用武之地在於,在運行階段分配未命名的內存以存儲值。
C語言中,採用malloc()函數分配內存,C++使用更好地new運算符
int* p = new int;
分析:告知new運算符需要分配什麼類型的內存,然後new返回一個地址再賦值給p(int類型)
但不存在p所指向量的名稱
P102
(**記住:int
是一種數據類型**)

  • new所分配的內存塊通常與常規變量分配的內存塊不同:
    常規變量:存儲在被稱爲棧(stack)的內存區域中
    new:存儲在被稱爲堆(heap)的自由存儲區
  • 內存耗盡
  • delete釋放內存
    delete p
    不要嘗試釋放已經釋放的內存
    避免兩個指針指向同一個內存塊;
    new和delete匹配使用,不能去釋放通過常規量定義的指針,例如
int a = 10;
int* p = &a;
delete p;	//wrong
  • new創建動態數組和使用元素
    靜態編聯(stastic binding):編譯時創建數組分配內存,固定內存位置和長度
    動態編聯(dynamic bingding):使用new創建,如果在運行階段需要數組,則創建,若不需要,則不創建,還可以在運行時選擇長度
int *p1 = new int;
int *p2 = new int [3];
//將指針名作爲數組名使用
p2[0] = 0;
p2[1] = 1;
p2[2] = 2;
p2 = p2 +1; //p2指向數組中第二個元素,則p2[0] = 1;(指向字節數加4或其他)  (數組的名字就是數組地址)P108
delete p1;
delete [] p2;	//new和delete格式需要匹配,都需要 []

P109 :指針小結

  • 指針和字符串
  • 使用new創建動態結構
  • 自動存儲:在函數的週期內存在
  • 靜態存儲:在整個程序中都存在 static double a = 100;
  • 動態存儲:new 和 delete 自由存儲區
  • 棧、堆和內存泄漏 什麼是堆,棧,內存泄漏和內存溢出?

數組的替代品

1.模板類vector

長度可以不固定

include<vector>
vector<type> a;
vector<type> a(n);
a.pushback(name);

vector用法

2.模板類array(C++11)

vector的功能比數組強大,但付出代價是效率較低,如果需要長度固定的數組,建議使用array,array是固定大小的,使用棧分配內存。優點是比數組更方便、更安全。

include<array>
array<type,num> a = {......};

都可以使用標準數組表示法來讀取元素:例如a[2]
C++不檢查數組指針超界錯誤

練習題

4.7

#include <iostream>
#include <string>
#include <vector>
#include <array>
using namespace std;

struct Pizza
{
	string name;
	double length;
	double weight;
};

int main()
{
	vector<int> v1;
	array<int, 10> a1;
	Pizza* p1 = new Pizza;
	cout << "please enter p1's paragrams\n";
	cout << "name: "; 
	getline(cin,p1->name);		//得到一行,包括空格
	cout << "length: "; cin >> p1->length;
	cout << "weight: "; cin >> p1->weight;
	cout << "name: " << p1->name << endl;
	cout << "length: " << p1->length << endl;
	cout << "weight: " <<  p1->weight << endl;
	delete p1;
	for (int i = 0; i < 10; i++)
	{
		v1.push_back(i);
		a1[i] = i;
	}
	for (int j = 0; j < 10; j++)
	{
		cout << v1[j] << "and" << a1[j] << endl;
	}
	getchar();
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章