文章目錄
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 之後,如圖
第 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);
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;
}