一、初識C++
1.0 ---------------
1.1 注釋
- 單行注釋:
// 描述信息
- 多行注釋:
/* 描述信息 */
1.2 變量
作用:給一段指定的內存空間起名,方便操作這段內存
語法:數據類型 變量名 = 初始值;
1.3 常量
作用:用於記錄程序中不可更改的數據
語法:
1. #define 宏常量: `#define 常量名 常量值` -- 通常定義在程序的最上方
2. const修飾的變量 `const 數據類型 常量名 = 常量值` -- 修飾該變量為常量,不可修改
1.4 關鍵字
作用:關鍵字是C++中預先保留的單詞(標識符)
在定義變量或者常量時候,不要用關鍵字
C++關鍵字如下:
asm | do | if | return | typedef |
---|---|---|---|---|
auto | double | inline | short | typeid |
bool | dynamic_cast | int | signed | typename |
break | else | long | sizeof | union |
case | enum | mutable | static | unsigned |
catch | explicit | namespace | static_cast | using |
char | export | new | struct | virtual |
class | extern | operator | switch | void |
const | false | private | template | volatile |
const_cast | float | protected | this | wchar_t |
continue | for | public | throw | while |
default | friend | register | true | |
delete | goto | reinterpret_cast | try |
提示:在給變量或者常量起名稱時候,不要用C++得關鍵字,否則會產生歧義。
1.5 標識符命名規則
作用:C++規定給標識符(變量、常量)命名時,有一套自己的規則
- 標識符不能是關鍵字
- 標識符只能由字母、數字、下划線組成
- 第一個字符必須為字母或下划線
- 標識符中字母區分大小寫
建議:給標識符命名時,爭取做到見名知意的效果,方便自己和他人的閱讀
二、數據類型
C++規定在創建一個變量或者常量時,必須要指定出相應的數據類型,否則無法給變量分配內存
2.0 ---------------
2.1 sizeof關鍵字
作用: 統計數據類型所占內存大小
語法: sizeof( 數據類型 / 變量)
2.2 整型
作用:整型變量表示的是整數類型
的數據
C++中能夠表示整型的類型有以下幾種方式,區別在於所占內存空間不同:
數據類型 | 占用空間 | 取值范圍 |
---|---|---|
short(短整型) | 2字節 | (-2^15 ~ 2^15-1) |
int(整型) | 4字節 | (-2^31 ~ 2^31-1) |
long(長整形) | Windows為4字節,Linux為4字節(32位),8字節(64位) | (-2^31 ~ 2^31-1) |
long long(長長整形) | 8字節 | (-2^63 ~ 2^63-1) |
平時程序中沒有特殊說明一般用int就夠了
2.3 實型(浮點型)
作用:表示小數
浮點型變量分為兩種:
- 單精度float --
創建時在初始化數字后加上f能減少一次轉換
- 雙精度double --
小數默認是double
- 科學計數法 --
3e-2代表3乘10的-2次方
兩者的區別在於表示的有效數字范圍不同。 正常顯示都是6位有效數字
數據類型 | 占用空間 | 有效數字范圍 |
---|---|---|
float | 4字節 | 7位有效數字 |
double | 8字節 | 15~16位有效數字 |
2.4 字符型
作用: 字符型變量用於顯示單個字符
語法:char ch = 'a';
注意1:在顯示字符型變量時,用單引號將字符括起來,不要用雙引號
注意2:單引號內只能有一個字符,不可以是字符串
- C和C++中字符型變量只占用 1個字節 。
- 字符型變量並不是把字符本身放到內存中存儲,而是將對應的ASCII編碼放入到存儲單元
使用
int(ch)
查看 ch 對應的字符 a 的 ASCII碼
2.5 轉義字符
作用: 用於表示一些 不能顯示出來的ASCII字符
現階段我們常用的轉義字符有: \n \\ \t
\t 水平制表符,占4個位置(包括其前邊的字符,可疊加)
轉義字符 | 含義 | ASCII碼值(十進制) |
---|---|---|
\a | 警報 | 007 |
\b | 退格(BS) ,將當前位置移到前一列 | 008 |
\f | 換頁(FF),將當前位置移到下頁開頭 | 012 |
\n | 換行(LF) ,將當前位置移到下一行開頭 | 010 |
\r | 回車(CR) ,將當前位置移到本行開頭 | 013 |
\t | 水平制表(HT) (跳到下一個TAB位置) | 009 |
\v | 垂直制表(VT) | 011 |
\\ | 代表一個反斜線字符 \ | 092 |
' | 代表一個單引號(撇號)字符 | 039 |
" | 代表一個雙引號字符 | 034 |
? | 代表一個問號 | 063 |
\0 | 數字0 | 000 |
\ddd | 8進制轉義字符,d范圍0~7 | 3位8進制 |
\xhh | 16進制轉義字符,h范圍09,af,A~F | 3位16進制 |
2.6 字符串型
作用:用於表示一串字符
兩種風格
- C風格字符串:
char 變量名[] = "字符串值"
注意:字符串名字后加[]; 字符串要用雙引號括起來
- C++風格字符串:
string 變量名 = "字符串值"
注意:C++風格字符串,需要加入頭文件
#include <string>
2.7 布爾類型 bool
作用: 布爾數據類型代表真或假的值
bool類型只有兩個值:true(本質是1); false(本質是0)
bool類型占1個字節大小
2.8 數據的輸入
作用:用於從鍵盤獲取數據
關鍵字: cin
語法: cin >> 變量
在vscode輸出面板中無法完成輸入操作,需要運行代碼后去終端執行
cmd /c "xxx.exe"
后輸入
三 運算符
3.0 ---------------
3.1 算術運算符
作用:用於處理四則運算
算術運算符包括以下符號:
運算符 | 術語 | 示例 | 結果 |
---|---|---|---|
+ | 正號 | +3 | 3 |
- | 負號 | -3 | -3 |
+ | 加 | 10 + 5 | 15 |
- | 減 | 10 - 5 | 5 |
* | 乘 | 10 * 5 | 50 |
/ | 除 | 10 / 5 | 2 |
% | 取模(取余) | 10 % 3 | 1 |
++ | 前置遞增 | a=2; b=++a; | a=3; b=3; |
++ | 后置遞增 | a=2; b=a++; | a=3; b=2; |
-- | 前置遞減 | a=2; b=--a; | a=1; b=1; |
-- | 后置遞減 | a=2; b=a--; | a=1; b=2; |
兩個整數相除結果依然是整數
兩個小數不可以進行取模運算
前置計算是先對變量進行計算,再計算表達式,后置遞增相反
#include<iostream>
using namespace std;
int main(){
int a1 = 10;
// 前置運算符,先對變量計算,再計算公式 110
int b = ++a1 * 10;
cout << a1 << endl;
cout << b << endl;
// 后置運算符,先計算公式,再對變量計算 100
int a2 = 10;
int c = a2++ *10;
cout << a2 << endl;
cout << c << endl;
return 0;
}
3.2 賦值運算符
作用: 用於將表達式的值賦給變量
賦值運算符包括以下幾個符號:
運算符 | 術語 | 示例 | 結果 |
---|---|---|---|
= | 賦值 | a=2; b=3; | a=2; b=3; |
+= | 加等於 | a=0; a+=2; | a=2; |
-= | 減等於 | a=5; a-=3; | a=2; |
*= | 乘等於 | a=2; a*=2; | a=4; |
/= | 除等於 | a=4; a/=2; | a=2; |
%= | 模等於 | a=3; a%2; | a=1; |
a += 2 可以理解為 a = a+2 的縮寫
3.3 比較運算符
作用: 用於表達式的比較,並返回一個真值或假值
比較運算符有以下符號:
運算符 | 術語 | 示例 | 結果 |
---|---|---|---|
== | 相等於 | 4 == 3 | 0 |
!= | 不等於 | 4 != 3 | 1 |
< | 小於 | 4 < 3 | 0 |
> | 大於 | 4 > 3 | 1 |
<= | 小於等於 | 4 <= 3 | 0 |
>= | 大於等於 | 4 >= 1 | 1 |
真返回1,假返回0
3.4 邏輯運算符
作用: 用於根據表達式的值返回真值或假值
邏輯運算符有以下符號:
運算符 | 術語 | 示例 | 結果 |
---|---|---|---|
! | 非 | !a | 如果a為假,則!a為真; 如果a為真,則!a為假。 |
&& | 與 | a && b | 如果a和b都為真,則結果為真,否則為假。 |
|| | 或 | a || b | 如果a和b有一個為真,則結果為真,二者都為假時,結果為假。 |
四 程序流程結構
C/C++支持最基本的三種程序運行結構:順序結構、選擇結構、循環結構
- 順序結構:程序按順序執行,不發生跳轉
- 選擇結構:依據條件是否滿足,有選擇的執行相應功能
- 循環結構:依據條件是否滿足,循環多次執行某段代碼
4.0 ---------------
4.1 選擇結構
4.1.1 if語句
作用: 執行滿足條件的語句
if語句的三種形式
- 單行格式if語句:
if(條件){ 條件滿足執行的語句 }
- 多行格式if語句:
if(條件){ 條件滿足執行的語句 }else{ 條件不滿足執行的語句 }
- 多條件的if語句:
if(條件1){ 條件1滿足執行的語句 }else if(條件2){條件2滿足執行的語句}... else{ 都不滿足執行的語句}
4.1.2 三目運算符
作用: 通過三目運算符實現簡單的判斷
語法:表達式1 ? 表達式2 :表達式3
解釋:
如果表達式1的值為真,執行表達式2,並返回表達式2的結果;
如果表達式1的值為假,執行表達式3,並返回表達式3的結果。
示例:
int main() {
int a = 10;
int b = 20;
int c = 0;
c = a > b ? a : b;
cout << "c = " << c << endl;
//C++中三目運算符返回的是變量,可以繼續賦值
(a > b ? a : b) = 100;
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl;
system("pause");
return 0;
}
總結:和if語句比較,三目運算符優點是短小整潔,缺點是如果用嵌套,結構不清晰
4.1.3 switch語句
作用: 執行多條件分支語句
語法:
switch(表達式)
{
case 結果1:執行語句;break;
case 結果2:執行語句;break;
...
default:執行語句;break;
}
注意1:switch語句中表達式類型只能是整型或者字符型
注意2:case里如果沒有break,那么程序會一直向下執行
總結:與if語句比,對於多條件判斷時,switch的結構清晰,執行效率高,缺點是switch不可以判斷區間
4.2 循環結構
4.2.1 while循環語句
作用: 滿足循環條件,執行循環語句
語法: while(循環條件){ 循環語句 }
while循環練習案例:猜數字
案例描述: 系統隨機生成一個1到100之間的數字,玩家進行猜測,如果猜錯,提示玩家數字過大或過小,如果猜對恭喜玩家勝利,並且退出游戲。
// 系統隨機生成1-100的數字,猜測對了輸出,錯了說明大還是小后繼續猜測
# include <iostream>
# include <ctime>
using namespace std;
int main(){
// 生成種子 記住就行
srand((unsigned int)time(NULL));
// 程序不認識time 需要添加頭文件ctime
// 生成一個1-100之間的隨機數 rand()%100是0-99
int a = rand()%100 + 1;
// 如果只是這么生成的是偽隨機數,即第一次生成后之后的結果都一樣,因此要添加種子,利用當前系統時間生成隨機數
int num = 0;
cout << "請輸入您猜測的數字" << endl;
while(1){
cin >> num;
if(num > a){
cout << " 您猜測的數字過大,請重新猜測" << endl;
}
else if(num < a){
cout << " 您猜測的數字過小,請重新猜測" << endl;
}
else{
cout << "恭喜您獲得勝利" << endl;
// 注意break,不然會一直循環下去
break;
}
cout << "請輸入您猜測的數字" << endl;
}
return 0;
}
4.2.2 do...while循環語句
作用: 滿足循環條件,執行循環語句
語法: do{ 循環語句 } while(循環條件);
總結:與while循環區別在於,do...while先執行一次循環語句,再判斷循環條件
4.2.3 for 循環語句
作用: 滿足循環條件,執行循環語句
語法: for(起始表達式;條件表達式;末尾循環體) { 循環語句; }
注意:for循環中的表達式,要用分號進行分隔
總結:while , do...while, for都是開發中常用的循環語句,for循環結構比較清晰,比較常用
4.3 跳轉語句
4.3.1 break語句
作用: 用於跳出選擇結構或者循環結構
break使用的時機:
- 出現在switch條件語句中,作用是終止case並跳出switch
- 出現在循環語句中,作用是跳出當前的循環語句
- 出現在嵌套循環中,跳出最近的內層循環語句
4.3.2 continue語句
作用: 在循環語句中,跳過本次循環中余下尚未執行的語句,繼續執行下一次循環
注意:continue並沒有使整個循環終止,而break會跳出循環
4.3.3 goto語句
作用: 可以無條件跳轉語句
語法: goto 標記;
解釋: 如果標記的名稱存在,執行到goto語句時,會跳轉到標記的位置
注意:在程序中不建議使用goto語句,以免造成程序流程混亂
五 數組
5.0 ---------------
5.1 概述
所謂數組,就是一個集合,里面存放了相同類型的數據元素
特點1: 數組中的每個數據元素都是相同的數據類型
特點2: 數組是由 連續的內存 位置組成的
5.2 一維數組
5.2.1 一維數組定義方式
一維數組定義的三種方式:
數據類型 數組名[ 數組長度 ];
數據類型 數組名[ 數組長度 ] = { 值1,值2 ...};
數據類型 數組名[ ] = { 值1,值2 ...};
總結1:數組名的命名規范與變量名命名規范一致,不要和變量重名
總結2:數組中下標是從0開始索引
5.2.2 一維數組數組名
一維數組名稱的用途:
- 可以統計整個數組在內存中的長度
- 可以獲取數組在內存中的首地址
注意:數組名是常量,不可以賦值
總結1:直接打印數組名,可以查看數組所占內存的首地址;查看字符所占內存地址,在字符前加
&
總結2:對數組名進行sizeof,可以獲取整個數組占內存空間的大小
5.3 二維數組
二維數組就是在一維數組上,多加一個維度。
5.3.1 二維數組定義方式
二維數組定義的四種方式:
數據類型 數組名[ 行數 ][ 列數 ];
數據類型 數組名[ 行數 ][ 列數 ] = { {數據1,數據2 } ,{數據3,數據4 } };
數據類型 數組名[ 行數 ][ 列數 ] = { 數據1,數據2,數據3,數據4};
數據類型 數組名[ ][ 列數 ] = { 數據1,數據2,數據3,數據4};
建議:以上4種定義方式,利用第二種更加直觀,提高代碼的可讀性
總結:在定義二維數組時,如果初始化了數據,可以省略行數
5.3.2 二維數組數組名
- 查看二維數組所占內存空間
- 獲取二維數組首地址
總結1:二維數組名就是這個數組的首地址
總結2:對二維數組名進行sizeof時,可以獲取整個二維數組占用的內存空間大小
六 函數
6.0 ---------------
6.1 概述
作用: 將一段經常使用的代碼封裝起來,減少重復代碼
一個較大的程序,一般分為若干個程序塊,每個模塊實現特定的功能。
6.2 函數的定義
函數的定義一般主要有5個步驟:
1、返回值類型
2、函數名
3、參數表列
4、函數體語句
5、return 表達式
語法:
返回值類型 函數名 (參數列表)
{
函數體語句
return表達式
}
- 返回值類型 :一個函數可以返回一個值。如果函數不需要返回值,聲明的時候可以寫
void
- 函數名:給函數起個名稱
- 參數列表:使用該函數時,傳入的數據
- 函數體語句:花括號內的代碼,函數內需要執行的語句
- return表達式: 和返回值類型掛鈎,函數執行完后,返回相應的數據
示例: 定義一個加法函數,實現兩個數相加
//函數定義
int add(int num1, int num2)
{
int sum = num1 + num2;
return sum;
}
6.3 函數的調用
功能: 使用定義好的函數
語法: 函數名(參數)
示例:
//函數定義
int add(int num1, int num2) //定義中的num1,num2稱為形式參數,簡稱形參
{
int sum = num1 + num2;
return sum;
}
int main() {
int a = 10;
int b = 10;
//調用add函數
int sum = add(a, b);//調用時的a,b稱為實際參數,簡稱實參
cout << "sum = " << sum << endl;
a = 100;
b = 100;
sum = add(a, b);
cout << "sum = " << sum << endl;
system("pause");
return 0;
}
總結:函數定義里小括號內稱為形參,函數調用時傳入的參數稱為實參
在實際調用中,a,b首先傳遞給num1,num2(實參傳遞給形參),再經過計算得到sum,返還的結果賦值給c
6.4 值傳遞
- 所謂值傳遞,就是函數調用時實參將數值傳入給形參
- 值傳遞時,如果形參發生,並不會影響實參
總結: 值傳遞時,形參是修飾不了實參的
6.5 函數的常見樣式
常見的函數樣式有4種
- 無參無返
- 有參無返
- 無參有返
- 有參有返
示例:
//函數常見樣式
//1、 無參無返
void test01()
{
//void a = 10; //無類型不可以創建變量,原因無法分配內存
cout << "this is test01" << endl;
//test01(); 函數調用
}
//2、 有參無返
void test02(int a)
{
cout << "this is test02" << endl;
cout << "a = " << a << endl;
}
//3、無參有返
int test03()
{
cout << "this is test03 " << endl;
return 10;
}
//4、有參有返
int test04(int a, int b)
{
cout << "this is test04 " << endl;
int sum = a + b;
return sum;
}
6.6 函數的聲明
作用: 告訴編譯器函數名稱及如何調用函數。函數的實際主體可以單獨定義。
- 函數的聲明可以多次,但是函數的定義只能有一次
- 當函數寫在main函數后的時候,一定要事先聲明
七 指針
7.0 ---------------
7.1 指針的基本概念
指針的作用: 可以通過指針間接訪問內存
-
內存編號是從0開始記錄的,一般用十六進制數字表示
-
可以利用指針變量保存地址
7.2 指針變量的定義和使用
指針變量定義語法: 數據類型 * 變量名;
示例:
int main() {
//1、指針的定義
int a = 10; //定義整型變量a
//指針定義語法: 數據類型 * 變量名 ;
int * p;
//指針變量賦值
p = &a; //指針指向變量a的地址
cout << &a << endl; //打印數據a的地址
cout << p << endl; //打印指針變量p
//2、指針的使用
//通過*操作指針變量指向的內存
cout << "*p = " << *p << endl;
system("pause");
return 0;
}
指針變量和普通變量的區別
- 普通變量存放的是數據,指針變量存放的是地址
- 指針變量可以通過" * "操作符,操作指針變量指向的內存空間,這個過程稱為解引用
總結1: 我們可以通過 & 符號 獲取變量的地址
總結2:利用指針可以記錄地址
總結3:對指針變量解引用,可以操作指針指向的內存
7.3 指針所占內存空間
總結:所有指針類型在32位操作系統下是4個字節,64位操作系統下8個字節
7.4 空指針和野指針
空指針:指針變量指向內存中編號為0的空間
用途:初始化指針變量
注意:空指針指向的內存是不可以訪問的
示例1:空指針
int main() {
//指針變量p指向內存地址編號為0的空間
int * p = NULL;
//訪問空指針報錯
//內存編號0 ~255為系統占用內存,不允許用戶訪問
cout << *p << endl;
system("pause");
return 0;
}
野指針:指針變量指向非法的內存空間
示例2:野指針
int main() {
//指針變量p指向內存地址編號為0x1100的空間
int * p = (int *)0x1100;
//訪問野指針報錯
cout << *p << endl;
system("pause");
return 0;
}
總結:空指針和野指針都不是我們申請的空間,因此不要訪問。
7.5 const修飾指針
const修飾指針有三種情況
- const修飾指針 --- 常量指針
- const修飾常量 --- 指針常量
- const即修飾指針,又修飾常量
示例:
# include <iostream>
using namespace std;
int main(){
int a = 10;
int b = 20;
// 1.const 修飾指針 常量指針,指針指向可以改,值不可以改
// 因為*m代表的是值,int * m (m)代表的是指針
const int * m = &a;
// *m = 30; 會報錯
m = &b;
cout << *m << endl;
cout << "指針所占用的內存是: " << sizeof(int *) << endl;
// 2、const修飾常量 指針常量,指針指向不可以改,值可以改
int * const n = &a;
// n = &b; 會報錯
*n = 100;
cout << "a的值為: " << a << endl;
// 3、const即修飾指針,又修飾常量 啥都不能改
const int * const q = &a;
// q = &b; 報錯
// *q = 300; 報錯
return 0;
}
技巧:看const右側緊跟着的是指針還是常量, 是指針就是常量指針,是常量就是指針常量
7.6 指針和數組
作用: 利用指針訪問數組中元素
示例:
# include <iostream>
using namespace std;
int main(){
int arr[] = {1,2,3,4,5};
int * p = arr; // 相當於指向數組的首地址
// 如果想訪問第二個地址,有兩個方法:1、arr[1] 2、指針偏移P++(因為指針類型也是int)
for(int i=0; i<5; i++){
cout << *p << endl; // *用於解地址,得到對應的變量值
p++;
}
return 0;
}
7.7 指針和函數
作用: 利用指針作函數參數,可以修改實參的值
# include <iostream>
using namespace std;
// 值傳遞 交換函數
void swap01(int a, int b){
int temp = a;
a = b;
b = temp;
}
// 地址傳遞 交換函數
void swap02(int * a, int * b){
int temp = *a;
*a = *b;
*b = temp;
}
int main(){
int num1 = 10;
int num2 = 20;
// 調用值傳遞,num1和num2為實參,實參的值沒變
swap01(num1, num2);
cout << "num1的值為: " << num1 << endl; //10
cout << "num2的值為: " << num2 << endl; //20
// 調用地址傳遞,實參的值變了
swap02(&num1, &num2);
cout << "num1的值為: " << num1 << endl; //20
cout << "num2的值為: " << num2 << endl; //10
return 0;
}
總結:如果不想修改實參,就用值傳遞,如果想修改實參,就用地址傳遞
數組傳入函數中,只能是地址傳遞,不可以是函數傳遞!
八 結構體
8.0 ---------------
8.1 結構體基本概念
結構體屬於用戶自定義的數據類型,允許用戶存儲不同的數據類型
8.2 結構體定義和使用
語法:struct 結構體名 { 結構體成員列表 };
通過結構體創建變量的方式有三種:
- struct 結構體名 變量名
- struct 結構體名 變量名 = { 成員1值 , 成員2值...}
- 定義結構體時順便創建變量
總結1:定義結構體時的關鍵字是struct,不可省略
總結2:創建結構體變量時,關鍵字struct可以省略
總結3:結構體變量利用操作符 ''.'' 訪問成員
8.3 結構體數組
作用: 將自定義的結構體放入到數組中方便維護
語法: struct 結構體名 數組名[元素個數] = { {} , {} , ... {} }
示例:
//結構體定義
struct student
{
//成員列表
string name; //姓名
int age; //年齡
int score; //分數
}
int main() {
//結構體數組
struct student arr[3]=
{
{"張三",18,80 },
{"李四",19,60 },
{"王五",20,70 }
};
for (int i = 0; i < 3; i++)
{
cout << "姓名:" << arr[i].name << " 年齡:" << arr[i].age << " 分數:" << arr[i].score << endl;
}
system("pause");
return 0;
}
8.4 結構體指針
作用:通過指針訪問結構體中的成員
- 利用操作符
->
可以通過結構體指針訪問結構體屬性
示例:
//結構體定義
struct student
{
//成員列表
string name; //姓名
int age; //年齡
int score; //分數
};
int main() {
struct student stu = { "張三",18,100, };
struct student * p = &stu;
p->score = 80; //指針通過 -> 操作符可以訪問成員
cout << "姓名:" << p->name << " 年齡:" << p->age << " 分數:" << p->score << endl;
system("pause");
return 0;
}
總結:結構體指針可以通過 -> 操作符 來訪問結構體中的成員
8.5 結構體嵌套結構體
作用: 結構體中的成員可以是另一個結構體
例如: 每個老師輔導一個學員,一個老師的結構體中,記錄一個學生的結構體
示例:
//學生結構體定義
struct student
{
//成員列表
string name; //姓名
int age; //年齡
int score; //分數
};
//教師結構體定義
struct teacher
{
//成員列表
int id; //職工編號
string name; //教師姓名
int age; //教師年齡
struct student stu; //子結構體 學生
};
8.6 結構體做函數參數
作用: 將結構體作為參數向函數中傳遞
傳遞方式有兩種:
- 值傳遞
- 地址傳遞
示例:
//學生結構體定義
struct student
{
//成員列表
string name; //姓名
int age; //年齡
int score; //分數
};
//值傳遞
void printStudent(student stu )
{
stu.age = 28;
cout << "子函數中 姓名:" << stu.name << " 年齡: " << stu.age << " 分數:" << stu.score << endl;
}
//地址傳遞
void printStudent2(student *stu)
{
stu->age = 28;
cout << "子函數中 姓名:" << stu->name << " 年齡: " << stu->age << " 分數:" << stu->score << endl;
}
總結:如果不想修改主函數中的數據,用值傳遞,反之用地址傳遞
8.7 結構體中 const使用場景
作用: 地址傳遞能大大節約內存,用const來防止地址傳遞誤操作
示例:
//學生結構體定義
struct student
{
//成員列表
string name; //姓名
int age; //年齡
int score; //分數
};
//const使用場景
void printStudent(const student *stu) //加const防止函數體中的誤操作
{
//stu->age = 100; //操作失敗,因為加了const修飾
cout << "姓名:" << stu->name << " 年齡:" << stu->age << " 分數:" << stu->score << endl;
}
int main() {
student stu = { "張三",18,100 };
printStudent(&stu);
system("pause");
return 0;
}
8.8 結構體案例
8.8.1 案例1
案例描述:
學校正在做畢設項目,每名老師帶領5個學生,總共有3名老師,需求如下
設計學生和老師的結構體,其中在老師的結構體中,有老師姓名和一個存放5名學生的數組作為成員
學生的成員有姓名、考試分數,創建數組存放3名老師,通過函數給每個老師及所帶的學生賦值
最終打印出老師數據以及老師所帶的學生數據。
示例:
// 創建學生、老師結構體
//實例15個學生,放入3個數組中
//實例3個老師,放入一個數組中
//通過函數賦值
//通過函數打印
# include <iostream>
# include<string>
// # include<time.h> 這個和下邊的都可以
# include<ctime>
using namespace std;
struct Stu
{
string name;
int score;
};
struct Tea
{
string name;
Stu student[5];
};
// 定義函數給老師學生賦值
void Fuzhi(Tea * p, int len)
{
for (int i=0; i<len; i++)
{
string temp = "ABCDE";
// 給結構體指針賦值 不用* 用->
p->name = "teacher";
p->name += temp[i];
// 給學生賦值
for (int j=0; j<5; j++)
{
p->student[j].name = "student";
p->student[j].name += temp[j];
// srand((unsigned int)time(NULL)); 隨機數種子要在main函數中加
// int randScore = rand() % 101; // 隨機生成0-100之間的數,如果是60-100
int randScore = rand() % 41 + 60;
p->student[j].score = randScore;
}
p++;
}
}
void Print(Tea tArray[])
{
for (int i=0; i<3; i++)
{
cout << "老師的名字是" << tArray[i].name << "他帶的學生信息如下:" << endl ;
for (int j=0; j<5; j++)
{
cout << "\t" << "姓名:" << tArray[i].student[j].name << "\t" << "成績:" << tArray[i].student[j].score << "\t" << endl;
}
}
}
int main(){
Tea teacher[3];
srand((unsigned int)time(NULL));
// 通過函數賦值
Fuzhi(teacher, 3);
// 打印
Print(teacher);
return 0;
}
8.8.2 案例2
案例描述:
設計一個英雄的結構體,包括成員姓名,年齡,性別;創建結構體數組,數組中存放5名英雄。
通過冒泡排序的算法,將數組中的英雄按照年齡進行升序排序,最終打印排序后的結果。
五名英雄信息如下:
{"劉備",23,"男"},
{"關羽",22,"男"},
{"張飛",20,"男"},
{"趙雲",21,"男"},
{"貂蟬",19,"女"},
/*
1、創建結構體
2、寫冒泡排序函數
3、將年齡作為參數傳遞(放到數組中)
*/
# include<iostream>
# include<string>
using namespace std;
struct hero
{
string name;
int age;
string sex;
};
void Sort(hero ageArr[], int len)
// 也可以是
// void Sort(hero *ageArr, int len)
{
// 注意:數組內的是.,此時不是指針,而是結構體
// 如果寫ageArr[i]->age肯定會出錯!!
for(int i=0; i<len; i++){
for(int j=0; j<len-1-i; j++){
if(ageArr[j].age > ageArr[j+1].age){
hero temp = ageArr[j];
ageArr[j] = ageArr[j+1];
ageArr[j+1] = temp;
}
}
}
for(int i=0; i<len; i++){
cout << "{" << ageArr[i].name << "," << ageArr[i].age << "," << ageArr[i].sex << "}" <<endl;
}
}
int main(){
hero arrAge[5] = {
{"劉備",23,"男"},
{"關羽",22,"男"},
{"張飛",20,"男"},
{"趙雲",21,"男"},
{"貂蟬",19,"女"}
};
int len = sizeof(arrAge)/sizeof(arrAge[0]);
cout << "-----排序前打印:" << endl;
for(int i=0; i<len; i++){
cout << "{" << arrAge[i].name << "," << arrAge[i].age << "," << arrAge[i].sex << "}" <<endl;
}
cout << "-----排序后打印:" << endl;
Sort( arrAge,len );
return 0;
}