g++編譯說明
程序 g++ 是將 gcc 默認語言設爲 C++ 的一個特殊的版本,鏈接時它自動使用 C++ 標準庫而不用 C 標準庫。通過遵循源碼的命名規範並指定對應庫的名字,用 gcc 來編譯鏈接 C++ 程序是可行的,如下例所示:
$ gcc main.cpp -lstdc++ -o main
編譯方式
單文件
$ g++ helloworld.cpp
注意: 由於命令行中沒有指定可執行文件名,編譯器默認採用`a.out`作爲文件名
編譯成功的程序執行方式
# linux
$ ./a.out
可以指定 `-o`參數指定文件名
$ g++ hello.cpp -o hello
$ ./hello
具有多個文件c++編譯
$ g++ main1.cpp main2.cpp -o main
g++有些系統默認是使用 C++98,可以指定C++11來編輯cpp文件
$ g++ -g -Wall -std=c++11 main.cpp
g++常用命令選項
選項 | 解釋 |
---|---|
-ansi | 只支持 ANSI 標準的 C 語法。這一選項將禁止 GNU C 的某些特色, 例如 asm 或 typeof 關鍵詞 |
-c | 只編譯並生成目標文件 |
-DMACRO=DEFN | 以字符串"DEFN"定義 MACRO 宏 |
-E | 只運行c預編譯器 |
-g | 生成調試信息。GNU 調試器可利用該信息 |
-IDIRECTORY | 指定額外的頭文件搜索路徑DIRECTORY |
-LDIRECTORY | 指定額外的函數庫搜索路徑DIRECTORY |
-lLIBRARY | 連接時搜索指定的函數庫LIBRARY |
-m486 | 針對 486 進行代碼優化 |
-o | FILE 生成指定的輸出文件。用在生成可執行文件時。 |
-O0 | 不進行優化處理。 |
-O | 或 -O1 優化生成代碼 |
-O2 | 進一步優化 |
-O3 | -O2 更進一步優化,包括 inline 函數 |
-shared | 生成共享目標文件。通常用在建立共享庫時 |
-static | 禁止使用共享連接。 |
-UMACRO | 取消對 MACRO 宏的定義 |
-w | 不生成任何警告信息 |
-Wall | 生成所有警告信息。 |
三字符組
三字符組就是用於表示另一個字符的三個字符序列,又稱爲三字符序列。三字符序列總是以兩個問號開頭。
三字符序列不太常見,但 C++ 標準允許把某些字符指定爲三字符序列。以前爲了表示鍵盤上沒有的字符,這是必不可少的一種方法。
三字符序列可以出現在任何地方,包括字符串、字符序列、註釋和預處理指令。
下面列出了最常用的三字符序列:
三字符組 | 替換 |
---|---|
??= | # |
??/ | \ |
??’ | ^ |
??( | [ |
??) | ] |
??! | | |
??< | { |
??> | } |
??- | ~ |
如果希望在源程序中有兩個連續的問號,且不希望被預處理器替換,這種情況出現在字符常量、字符串字面值或者是程序註釋中,可選辦法是用字符串的自動連接:"…?""?..“或者轉義序列:”…?\?.."。
從Microsoft Visual C++ 2010版開始,該編譯器默認不再自動替換三字符組。如果需要使用三字符組替換(如爲了兼容古老的軟件代碼),需要設置編譯器命令行選項/Zc:trigraphs
g++仍默認支持三字符組,但會給出編譯警告。
c++註釋
單行註釋
// 單行註釋1
/* 單行註釋2 */
多行註釋
/*
* 多行註釋
*
*/
數據類型
基本類型
類型 | 關鍵字 |
---|---|
布爾型 | bool |
字符型 | char |
整型 | int |
浮點型 | float |
雙浮點型 | double |
無類型 | void |
寬字符型 | wchar_t |
寬字符型
typedef short int wchar_t;
一些基本類型可以使用一個或多個類型修飾符進行修飾;
- signed
- unsigned
- short
- long
類型 | 字節 | 範圍 |
---|---|---|
char | 1 | -128 到 127 或者 0 到 255 |
unsigned char | 1 | 0 到 255 0x00 0xFF |
signed char | 1 | -128 到 127 |
int | 4 | -2147483648 到 2147483647 |
unsigned int | 4 | 0 到 4294967295 (0x00000000 0x FFFFFFFF) |
signed int | 4 | -2147483648 到 2147483647 |
short int | 2 | -32768 到 32767 |
unsigned short int | 2 | 0 到 65,535 |
signed short int | 2 | -32768 到 32767 |
long int | 8 | -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807 |
signed long int | 8 | -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807 |
unsigned long int | 8 | 0 到 18,446,744,073,709,551,615 |
float | 4 | 精度型佔4個字節(32位)內存空間,+/- 3.4e +/- 38 (~7 個數字) |
double | 8 | 雙精度型佔8 個字節(64位)內存空間,+/- 1.7e +/- 308 (~15 個數字) |
long double | 16 | 長雙精度型 16 個字節(128位)內存空間,可提供18-19位有效數字。 |
wchar_t | 2 或 4 | 1 個寬字符 |
變量的大小會根據編譯器和所使用的電腦而有所不同。
下面實例會輸出您電腦上各種數據類型的大小。
#include<iostream>
#include <limits>
using namespace std;
int main()
{
cout << "type: \t\t" << "************size**************"<< endl;
cout << "bool: \t\t" << "所佔字節數:" << sizeof(bool);
cout << "\t最大值:" << (numeric_limits<bool>::max)();
cout << "\t\t最小值:" << (numeric_limits<bool>::min)() << endl;
cout << "char: \t\t" << "所佔字節數:" << sizeof(char);
cout << "\t最大值:" << (numeric_limits<char>::max)();
cout << "\t\t最小值:" << (numeric_limits<char>::min)() << endl;
cout << "signed char: \t" << "所佔字節數:" << sizeof(signed char);
cout << "\t最大值:" << (numeric_limits<signed char>::max)();
cout << "\t\t最小值:" << (numeric_limits<signed char>::min)() << endl;
cout << "unsigned char: \t" << "所佔字節數:" << sizeof(unsigned char);
cout << "\t最大值:" << (numeric_limits<unsigned char>::max)();
cout << "\t\t最小值:" << (numeric_limits<unsigned char>::min)() << endl;
cout << "wchar_t: \t" << "所佔字節數:" << sizeof(wchar_t);
cout << "\t最大值:" << (numeric_limits<wchar_t>::max)();
cout << "\t\t最小值:" << (numeric_limits<wchar_t>::min)() << endl;
cout << "short: \t\t" << "所佔字節數:" << sizeof(short);
cout << "\t最大值:" << (numeric_limits<short>::max)();
cout << "\t\t最小值:" << (numeric_limits<short>::min)() << endl;
cout << "int: \t\t" << "所佔字節數:" << sizeof(int);
cout << "\t最大值:" << (numeric_limits<int>::max)();
cout << "\t最小值:" << (numeric_limits<int>::min)() << endl;
cout << "unsigned: \t" << "所佔字節數:" << sizeof(unsigned);
cout << "\t最大值:" << (numeric_limits<unsigned>::max)();
cout << "\t最小值:" << (numeric_limits<unsigned>::min)() << endl;
cout << "long: \t\t" << "所佔字節數:" << sizeof(long);
cout << "\t最大值:" << (numeric_limits<long>::max)();
cout << "\t最小值:" << (numeric_limits<long>::min)() << endl;
cout << "unsigned long: \t" << "所佔字節數:" << sizeof(unsigned long);
cout << "\t最大值:" << (numeric_limits<unsigned long>::max)();
cout << "\t最小值:" << (numeric_limits<unsigned long>::min)() << endl;
cout << "double: \t" << "所佔字節數:" << sizeof(double);
cout << "\t最大值:" << (numeric_limits<double>::max)();
cout << "\t最小值:" << (numeric_limits<double>::min)() << endl;
cout << "long double: \t" << "所佔字節數:" << sizeof(long double);
cout << "\t最大值:" << (numeric_limits<long double>::max)();
cout << "\t最小值:" << (numeric_limits<long double>::min)() << endl;
cout << "float: \t\t" << "所佔字節數:" << sizeof(float);
cout << "\t最大值:" << (numeric_limits<float>::max)();
cout << "\t最小值:" << (numeric_limits<float>::min)() << endl;
cout << "size_t: \t" << "所佔字節數:" << sizeof(size_t);
cout << "\t最大值:" << (numeric_limits<size_t>::max)();
cout << "\t最小值:" << (numeric_limits<size_t>::min)() << endl;
cout << "string: \t" << "所佔字節數:" << sizeof(string) << endl;
// << "\t最大值:" << (numeric_limits<string>::max)() << "\t最小值:" << (numeric_limits<string>::min)() << endl;
cout << "type: \t\t" << "************size**************"<< endl;
return 0;
}
//本實例使用了 endl,這將在每一行後插入一個換行符,<< 運算符用於向屏幕傳多個值。我們也使用 sizeof() 函數來獲取各種數據類型的大小。
//當上面的代碼被編譯和執行時,它會產生以下的結果,結果會根據所使用的計算機而有所不同:
type: ************size**************
bool: 所佔字節數:1 最大值:1 最小值:0
char: 所佔字節數:1 最大值: 最小值:?
signed char: 所佔字節數:1 最大值: 最小值:?
unsigned char: 所佔字節數:1 最大值:? 最小值:
wchar_t: 所佔字節數:4 最大值:2147483647 最小值:-2147483648
short: 所佔字節數:2 最大值:32767 最小值:-32768
int: 所佔字節數:4 最大值:2147483647 最小值:-2147483648
unsigned: 所佔字節數:4 最大值:4294967295 最小值:0
long: 所佔字節數:8 最大值:9223372036854775807 最小值:-9223372036854775808
unsigned long: 所佔字節數:8 最大值:18446744073709551615 最小值:0
double: 所佔字節數:8 最大值:1.79769e+308 最小值:2.22507e-308
long double: 所佔字節數:16 最大值:1.18973e+4932 最小值:3.3621e-4932
float: 所佔字節數:4 最大值:3.40282e+38 最小值:1.17549e-38
size_t: 所佔字節數:8 最大值:18446744073709551615 最小值:0
string: 所佔字節數:24
type: ************size**************
typedef
使用 typedef爲變量起別名
// typedef type newname;
typedef int myint;
typedef char ** mychar;
myint a;
mychar c;
枚舉類型
/*
定義格式
enum name{
value1[=int];
value2[=int];
...
}
*/
enum color{
red,green,blue
};
color c =red;
// c = 0;
enum color{
red,green=5,blue
//red=0 green=5; blue=6
};
默認情況下,第一個名稱的值爲 0,第二個名稱的值爲 1,第三個名稱的值爲 2,以此類推。但是,您也可以給名稱賦予一個特殊的值,只需要添加一個初始值即可。默認情況下,每個名稱都會比它前面一個名稱大 1
變量的聲明
變量聲明向編譯器保證變量以給定的類型和名稱存在,這樣編譯器在不需要知道變量完整細節的情況下也能繼續進一步的編譯。變量聲明只在編譯時有它的意義,在程序連接時編譯器需要實際的變量聲明。
當您使用多個文件且只在其中一個文件中定義變量時(定義變量的文件在程序連接時是可用的),變量聲明就顯得非常有用。您可以使用 extern 關鍵字在任何地方聲明一個變量。雖然您可以在 C++ 程序中多次聲明一個變量,但變量只能在某個文件、函數或代碼塊中被定義一次。
#include <iostream>
using namespace std;
// 變量聲明
extern int a, b;
extern int c;
extern float f;
int main ()
{
// 變量定義
int a, b;
int c;
float f;
// 實際初始化
a = 10;
b = 20;
c = a + b;
cout << c << endl ;
f = 70.0/3.0;
cout << f << endl ;
return 0;
}
初始化
- 當局部變量被定義時,系統不會對其初始化
- 定義全局變量時,系統會自動初始化爲下列值:
數據類型 | 初始化默認值 |
---|---|
int | 0 |
char | ‘\0’ |
float | 0 |
double | 0 |
pointer | NULL |
正確地初始化變量是一個良好的編程習慣,否則有時候程序可能會產生意想不到的結果。
常量
整數常量
整數常量可以是十進制、八進制或十六進制的常量。前綴指定基數:0x 或 0X 表示十六進制,0 表示八進制,不帶前綴則默認表示十進制。
整數常量也可以帶一個後綴,後綴是 U 和 L 的組合,U 表示無符號整數(unsigned),L 表示長整數(long)。後綴可以是大寫,也可以是小寫,U 和 L 的順序任意。
下面列舉幾個整數常量的實例:
212 // 合法的
215u // 合法的
0xFeeL // 合法的
078 // 非法的:8 不是八進制的數字
032UU // 非法的:不能重複後綴
以下是各種類型的整數常量的實例:
85 // 十進制
0213 // 八進制
0x4b // 十六進制
30 // 整數
30u // 無符號整數
30l // 長整數
30ul // 無符號長整數
浮點常量
浮點常量由整數部分、小數點、小數部分和指數部分組成。您可以使用小數形式或者指數形式來表示浮點常量。
當使用小數形式表示時,必須包含整數部分、小數部分,或同時包含兩者。當使用指數形式表示時, 必須包含小數點、指數,或同時包含兩者。帶符號的指數是用 e 或 E 引入的。
下面列舉幾個浮點常量的實例:
3.14159 // 合法的
314159E-5L // 合法的
510E // 非法的:不完整的指數
210f // 非法的:沒有小數或指數
.e55 // 非法的:缺少整數或分數
字符常量
字符常量是括在單引號中。如果常量以 L(僅當大寫時)開頭,則表示它是一個寬字符常量(例如 L’x’),此時它必須存儲在 wchar_t 類型的變量中。否則,它就是一個窄字符常量(例如 ‘x’),此時它可以存儲在 char 類型的簡單變量中。
字符常量可以是一個普通的字符(例如 ‘x’)、一個轉義序列(例如 ‘\t’),或一個通用的字符(例如 ‘\u02C0’)。
在 C++ 中,有一些特定的字符,當它們前面有反斜槓時,它們就具有特殊的含義,被用來表示如換行符(\n)或製表符(\t)等。下表列出了一些這樣的轉義序列碼:
轉義序列 | 含義 |
---|---|
\ | \ 字符 |
’ | ’ 字符 |
" | " 字符 |
? | ? 字符 |
\a | 警報鈴聲 |
\b | 退格鍵 |
\f | 換頁符 |
\n | 換行符 |
\r | 回車 |
\t | 水平製表符 |
\v | 垂直製表符 |
\ooo | 一到三位的八進制數 |
\xhh . . . | 一個或多個數字的十六進制數 |
字符串常量
字符串字面值或常量是括在雙引號 “” 中的。一個字符串包含類似於字符常量的字符:普通的字符、轉義序列和通用的字符。
您可以使用空格做分隔符,把一個很長的字符串常量進行分行。
下面的實例顯示了一些字符串常量。下面這三種形式所顯示的字符串是相同的。
"hello, dear"
"hello, \
dear"
"hello, " "d" "ear"
定義常量
在 C++ 中,有兩種簡單的定義常量的方式:
- 使用 #define 預處理器。
- 使用 const 關鍵字。
#define
#include <iostream>
using namespace std;
#define LENGTH 10
#define WIDTH 5
#define NEWLINE '\n'
int main()
{
int area;
area = LENGTH * WIDTH;
cout << area;
cout << NEWLINE;
return 0;
}
const
#include <iostream>
using namespace std;
int main()
{
const int LENGTH = 10;
const int WIDTH = 5;
const char NEWLINE = '\n';
int area;
area = LENGTH * WIDTH;
cout << area;
cout << NEWLINE;
return 0;
}
C++ 修飾符類型
C++ 允許在 char、int 和 double 數據類型前放置修飾符。修飾符用於改變基本類型的含義,所以它更能滿足各種情境的需求。
下面列出了數據類型修飾符:
- signed
- unsigned
- long
- short
修飾符 signed、unsigned、long 和 short 可應用於整型,signed 和 unsigned 可應用於字符型,long 可應用於雙精度型。
修飾符 signed 和 unsigned 也可以作爲 long 或 short 修飾符的前綴。例如:unsigned long int。
C++ 允許使用速記符號來聲明無符號短整數或無符號長整數。您可以不寫 int,只寫單詞 unsigned、short 或 unsigned、long,int 是隱含的。例如,下面的兩個語句都聲明瞭無符號整型變量。
unsigned x;
unsigned int y;
#include <iostream>
using namespace std;
/*
* 這個程序演示了有符號整數和無符號整數之間的差別
*/
int main()
{
short int i; // 有符號短整數
short unsigned int j; // 無符號短整數
j = 50000;
i = j;
cout << i << " " << j;
return 0;
}
當上面的程序運行時,會輸出下列結果:
-15536 50000
上述結果中,無符號短整數 50,000 的位模式被解釋爲有符號短整數 -15,536。
C++ 中的類型限定符
類型限定符提供了變量的額外信息。
限定符 | 含義 |
---|---|
const | const 類型的對象在程序執行期間不能被修改改變。 |
volatile | 修飾符 volatile 告訴編譯器不需要優化volatile聲明的變量,讓程序可以直接從內存中讀取變量。對於一般的變量編譯器會對變量進行優化,將內存中的變量值放在寄存器中以加快讀寫效率。 |
restrict | 由 restrict 修飾的指針是唯一一種訪問它所指向的對象的方式。只有 C99 增加了新的類型限定符 restrict。 |
C++ 存儲類
存儲類定義 C++ 程序中變量/函數的範圍(可見性)和生命週期。這些說明符放置在它們所修飾的類型之前。下面列出 C++ 程序中可用的存儲類:
- auto
- register
- static
- extern
- mutable
- thread_local (C++11)
從 C++ 17 開始,auto 關鍵字不再是 C++ 存儲類說明符,且 register 關鍵字被棄用。
auto 存儲類
自 C++ 11 以來,auto 關鍵字用於兩種情況:聲明變量時根據初始化表達式自動推斷該變量的類型、聲明函數時函數返回值的佔位符。
C++98標準中auto關鍵字用於自動變量的聲明,但由於使用極少且多餘,在C++11中已刪除這一用法。
根據初始化表達式自動推斷被聲明的變量的類型,如:
auto f=3.14; //double auto s("hello"); //const char* auto z = new auto(9); // int* auto x1 = 5, x2 = 5.0, x3='r';//錯誤,必須是初始化爲同一類型
register 存儲類
register 存儲類用於定義存儲在寄存器中而不是 RAM 中的局部變量。這意味着變量的最大尺寸等於寄存器的大小(通常是一個詞),且不能對它應用一元的 ‘&’ 運算符(因爲它沒有內存位置)。
{ register int miles; }
寄存器只用於需要快速訪問的變量,比如計數器。還應注意的是,定義 ‘register’ 並不意味着變量將被存儲在寄存器中,它意味着變量可能存儲在寄存器中,這取決於硬件和實現的限制。
static 存儲類
static 存儲類指示編譯器在程序的生命週期內保持局部變量的存在,而不需要在每次它進入和離開作用域時進行創建和銷燬。因此,使用 static 修飾局部變量可以在函數調用之間保持局部變量的值。
static 修飾符也可以應用於全局變量。當 static 修飾全局變量時,會使變量的作用域限制在聲明它的文件內。
在 C++ 中,當 static 用在類數據成員上時,會導致僅有一個該成員的副本被類的所有對象共享。
#include <iostream> // 函數聲明 void func(void);
static int count = 10; /* 全局變量 */
int main() {
while(count--)
{
func();
}
return 0;
}
// 函數定義
void func( void )
{
static int i = 5; // 局部靜態變量
i++;
std::cout << "變量 i 爲 " << i ;
std::cout << " , 變量 count 爲 " << count << std::endl;
}
當上面的代碼被編譯和執行時,它會產生下列結果:
變量 i 爲 6 , 變量 count 爲 9
變量 i 爲 7 , 變量 count 爲 8
變量 i 爲 8 , 變量 count 爲 7
變量 i 爲 9 , 變量 count 爲 6
變量 i 爲 10 , 變量 count 爲 5
變量 i 爲 11 , 變量 count 爲 4
變量 i 爲 12 , 變量 count 爲 3
變量 i 爲 13 , 變量 count 爲 2
變量 i 爲 14 , 變量 count 爲 1
變量 i 爲 15 , 變量 count 爲 0
extern 存儲類
extern 存儲類用於提供一個全局變量的引用,全局變量對所有的程序文件都是可見的。當您使用 ‘extern’ 時,對於無法初始化的變量,會把變量名指向一個之前定義過的存儲位置。
當您有多個文件且定義了一個可以在其他文件中使用的全局變量或函數時,可以在其他文件中使用 extern 來得到已定義的變量或函數的引用。可以這麼理解,extern 是用來在另一個文件中聲明一個全局變量或函數。
extern 修飾符通常用於當有兩個或多個文件共享相同的全局變量或函數的時候,如下所示:
第一個文件:main.cpp
#include <iostream>
int count ;
extern void write_extern();
int main()
{
count = 5;
write_extern();
}
第二個文件:support.cpp
#include <iostream>
extern int count;
void write_extern(void)
{
std::cout << "Count is " << count << std::endl;
}
在這裏,第二個文件中的 extern 關鍵字用於聲明已經在第一個文件 main.cpp 中定義的 count。現在 ,編譯這兩個文件,如下所示:
$ g++ main.cpp support.cpp -o write
這會產生 write 可執行程序,嘗試執行 write,它會產生下列結果:
$ ./write
Count is 5
mutable 存儲類
mutable 說明符僅適用於類的對象,這將在本教程的最後進行講解。它允許對象的成員替代常量。也就是說,mutable 成員可以通過 const 成員函數修改。
thread_local 存儲類
使用 thread_local 說明符聲明的變量僅可在它在其上創建的線程上訪問。 變量在創建線程時創建,並在銷燬線程時銷燬。 每個線程都有其自己的變量副本。
thread_local 說明符可以與 static 或 extern 合併。
可以將 thread_local 僅應用於數據聲明和定義,thread_local 不能用於函數聲明或定義。
以下演示了可以被聲明爲 thread_local 的變量:
thread_local int x; // 命名空間下的全局變量
class X
{
static thread_local std::string s; // 類的static成員變量
};
static thread_local std::string X::s; // X::s 是需要定義的
void foo()
{
thread_local std::vector<int> v; // 本地變量
}
指針
指針變量的大小
sizeof(int *);
// 在64位操作系統下是8
// 在32位操作系統下是4
空指針
地址爲0的指針爲空指針
空指針無法訪問
0-255之間的內存編號是系統佔用的,不可訪問
int a =10;
int *p;
int *p2=NULL:
cout<<p<<endl; //出錯
cout<<p2<<endl; //輸出000000000000
*p2=100;//出錯,空指針無法訪問
野指針
野指針 指向非法的內存空間的指針, 不是程序申請的地址
int *p = (int *)0x1100;
cout<< *p <<endl;
const修飾指針
三種情況
- const修飾指針 —常量指針;
- const修飾常量 —指針常量
- const即修飾指針,又修飾常量
int a=10;
int b=20;
// 常量指針,指向常量的指針,指針指向可以改變,但是解引用後的值不可以改變
const int * p1 =&a;
p1=&b; //正確
*p=40; //錯誤
//指針常量,指針指向不可以改變,但是指向的值可以改變
int * const p2=&a;
p2=&b; //錯誤
*p2=40; //正確
// 指針指向和指向的值都不可以改變
const int * const p3 = &a;
p3=&b; //錯誤
*p3=40; //錯誤
c++內存
-
程序運行前
-
代碼區
存放二進制代碼,由操作系統管理
-
全局區
存放全局變量和靜態變量以及全局常量
-
-
運行時
- 棧:編譯器自動分配釋放,函數的參數,局部變量等
- 堆:程序員手動管理
代碼區
- CPU執行的指令
- 共享、只讀
全局
- 全局變量、靜態變量
- 常量、字符串常量
棧區
局部變量,自動釋放
int* fun() {
int a = 10;
return &a;
}
int main() {
int* p = fun();
cout << *p << endl; // 輸出10,編譯器保留一次局部變量
cout << *p << endl; //輸出亂碼,內存被覆蓋
cout << *p << endl;
cout << *p << endl;
system("pause");
return 0;
}
輸出
10
-858993460
-858993460
-858993460
請按任意鍵繼續. . .
堆區
- 程序員手動管理
- 使用new關鍵字開闢空間
int* fun() {
int *a = new int(10);
//a 對應的數據保存在堆裏,函數結束後不會被自動釋放掉
return a;
}
int main() {
int* p = fun();
cout << *p << endl;
cout << *p << endl;
cout << *p << endl;
cout << *p << endl;
system("pause");
return 0;
}
輸出
10
10
10
10
請按任意鍵繼續. . .
new&delete
//開闢內存
int *p = new int(10); //int
int *array =new int[10] //數組
//釋放內存
delete p;
delete[] arrary;
引用
引用:給變量起別名
type &name = sname
代碼示意
int a=10;
int &b=a;
b=20;
cout<<a<<endl; //a=10
使用注意事項
- 引用聲明時必須初始化
- 引用初始化後不可改變
引用函數傳參
聲明方式 void swap(int& a, int& b)
在函數內修改形參,實參也會改變
void swap(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
int main(){
int a = 10;
int c = 50;
cout << "a=" << a << " b=" << c << endl; //a=10 c=50
swap(a, c);
cout << "a=" << a << " b=" << c << endl; //a=50 c=10
system("pause");
return 0;
}
引用做函數返回值
- 不要返回局部變量的引用
- 函數的調用可以作爲左值
- 引用的本質是一個指針常量
代碼示例
int& fun1() {
int a = 10;
return a; //返回局部變量的引用
}
int& fun2() {
static int a = 10;
return a; //返回靜態變量的引用
}
int main(){
int& ref1=fun1();
int& ref2=fun2();
cout<<ref1<<endl;
cout<<ref1<<endl;
cout<<ref1<<endl;
fun2()==1000;
cout<<ref2<<endl;
cout<<ref2<<endl;
cout<<ref2<<endl;
}
常量引用
- 引用時必須引用合法內存空間
int a=10;
int& ref=a; //合法,a是在
int& ref2 = 10; //錯誤
const int& ref3 = 10; //正確
/*
相當於以下代碼
int temp =10;
int& ref3 =temp;
*/
ref3 = 10; //錯誤,const修飾,無法修改
-
常用情景
函數參數(const int& ref)
void print(const int& v) {
//v++; const修飾,v的值不能更改
cout << v << endl;
}
int main(){
int a = 10;
print(a);
system("pause");
return 0;
}
函數
函數參數默認值
方式: 參數=默認值
int function_default(int a,int b=10,int c=20) {
return a + b + c;
}
int main() {
cout << function_default(12, 23, 24) << endl; //59
cout << function_default(10, 20) << endl; //50
cout << function_default(12) << endl; //42
system("pause");
return 0;
}
- 有默認值的參數後面的所有參數都必須有默認值
- 如果函數的聲明有默認參數,則函數實現就不能有默認參數,反之亦然
- 如果函數實現有默認參數,會出現
默認參數重定義
的錯誤
- 如果函數實現有默認參數,會出現
佔位參數
void fun1(int a, int); //
//調用
fun1(10,20);
void func2(int a , int =10); //佔位參數默認值
//調用
fun2(10,20);
fun2(10);
函數重載
注意事項
1、引用重載
void func1(int & f) {
cout << "int &" << endl;
}
void func1(const int& f) {
cout << "const int &" << endl;
}
int main() {
int a = 10;
func1(a); //輸出 “int &”
func1(10); //輸出 "const int &"
system("pause");
return 0;
}
2、默認值引起歧義
void func1(int a,int b=10) {
cout << "int a,int b=10" << endl;
}
void func1(int a) {
cout << "int a" << endl;
}
int main() {
int a = 10;
func1(a); //編譯出錯
system("pause");
return 0;
}
文件操作
- 頭文件 <fstream>
- ofstream:寫操作
- ifstream:讀操作
- fstream:讀寫操作
文本文件
-
步驟
-
#包含頭文件< fstream>
-
創建流對象
ofstream ofs;
-
打開文件
- ofs.open(“文件路徑”,打開方式)
注:文件打開方式
-
打開方式 | 含義 |
---|---|
ios::in | 讀文件 |
ios::out | 寫文件 |
ios::ate | 初始位置:文件尾 |
ios::app | 追加方式寫文件 |
ios::trunc | 文件存在先刪除,再創建 |
ios::binary | 二進制方式打開 |
文件打開方式可以結合使用,使用|
操作符
- 寫數據
- ofs<<“要寫入的數據”;
- 關閉文件
- ofs.close()
代碼示例
寫文本文件
#include <iostream>
#include <fstream>
#include<string>
int main() {
ofstream ofs;
ofs.open("temp.txt", ios::out| ios::app);
ofs << "Hello world"<<endl;
ofs.close();
}
讀文本文件
#include <iostream>
#include <fstream>
#include<string>
using namespace std;
int main() {
ifstream ifs;
ifs.open("temp.txt", ios::in);
if (!ifs.is_open()) {
cout << "文件打開失敗,程序退出!" << endl;
return -1;
}
// read 1
// 依次讀取內容,填充buf 以空格或者回車作爲間隔
char buf[1024];
while (ifs>>buf) {
cout << buf<<endl;
}
// read 2
// getline()每次讀取一行
char buf[1024] = {0};
while (ifs.getline(buf,sizeof(buf)))
{
cout << buf << endl;
}
//read 3
string buf;
while (getline(ifs,buf))
{
cout << buf << endl;
}
//ifs.close();
//read 4
//逐字符讀取,效率低
char c;
while ((c=ifs.get())!=EOF)
{
cout << c;
}
//system("pause");
return 0;
}
二進制文件
寫文件
int main() {
ofstream ofs("binaryTest.bin", ios::out | ios::binary);
if (!ofs.is_open()) {
cout << "文件打開失敗,自動退出" << endl;
return -1;
}
int index = 12;
double price = 14;
char name[10] = "曹志堅"; //寫最好使用char[]數組類型,使用string會出問題
Person p(new char[64]{ "袁華" }, 12);
ofs.write((const char *)&index,sizeof(index));
ofs.write((const char *)&price,sizeof(price));
ofs.write((const char *)&name,sizeof(name));
ofs.write((const char *)&p,sizeof(p));
ofs.close();
}
讀文件
int main(){
ifstream ifs("binaryTest.bin", ios::in | ios::binary);
if (!ifs.is_open()) {
cout << "文件打開失敗,自動退出" << endl;
return -1;
}
int index2;;
double price2;
char name2[10];
Person p2;
ifs.read((char*)&index2, sizeof(int));
ifs.read((char*)&price2, sizeof(double));
ifs.read((char*)name2, sizeof(char[10]));
ifs.read((char*)&p2, sizeof(Person));
cout << "index=" << index2 << endl << "price=" << price2 << endl << "name=" << name2 << endl;
cout << "person name=" << p2.name << " age=" << p2.age << endl;
ifs.close();
}