課程位址: https://www.coursera.org/learn/cpp-chengxu-sheji
文章目錄
-
- 1.1 函數指針
-
- 基本概念
- 從qsort庫函數看函數指針的作用
- 練習題
- 1.2 指令行參數
-
- 練習
- 2.1 位運算
- 2.2 引用
-
- 練習
- 3.1 const關鍵字
-
- const定義常量
- const定義指針
- 3.2 動态記憶體配置設定
-
- 練習
- 3.3 内聯函數,函數重載,參數預設
-
- 函數重載
- 參數預設
- 4.1 面向對象的設計方法
1.1 函數指針
基本概念
程式在運作期間,每一個函數都會占用一片連續的記憶體空間。每一個函數都會有一個起始位址。 那在C語言和C++語言裡面,我們可以把一個函數的起始位址指派給一個指針, 那這樣的一個指針就稱為函數指針。
- 函數指針定義
例:類型名 (* 指針變量名)(參數類型1,參數類型2)
note:* 指針變量名一定要加括号int (*pf)(int char)
-
函數指針使用
可以用一個原型比對的函數名字為一個函數指針指派。
通過函數指針調用指向函數:
note:原型比對值傳回值類型,參數類型和個數都要相同函數指針名(實參表)
從qsort庫函數看函數指針的作用
-
qsort函數聲明
qsort函數是能對任意類型的數組進行排序的c庫函數
void qsort(void *base, int nelem, unsigned int width,
int (* pfCompare)(const void *,const void *));
/*****/
base: 數組的首元素位址
nelem:數組元素的個數
width:每個元素的大小(位元組)
pfCompare: 排序規則
-
排序規則編寫
格式:
int 比較函數名(const void * elem1,const void * elem2);
如果認為elem1應該排在elem2的前面,函數的傳回值就應該是一個負的整數。
如果認為elem1和elem2哪個排在前面都行,那麼比較函數的傳回值就應該是0。
如果認為elem1應該排在elem2的後面, 比較函數的傳回值就應該是一個正整數。
簡而言之:
不交換傳回負數,交換傳回正數,随意傳回0
#include <stdio.h>
#include <stdlib.h>
//讓數組元素按照個位數大小排序,(從小到大)
int MyCompare(const void * elem1,const void *elem2)
{
unsigned int *p1,*p2;
p1 = (unsigned int *)elem1;
p2 = (unsigned int *)elem2;
return (*p1 % 10)-(*p2 % 10);
}
int main()
{
unsigned int an[5] = {12,34,4,51,3};
qsort(an,5,sizeof(unsigned int),MyCompare);
for(int i=0;i<5;i++)
printf("%d ", an[i]);
}
//運作結果
51 12 3 4 34
總結:函數指針作為參數,可以傳遞更多的資訊。
練習題
答案 B

答案:C
1.2 指令行參數
我們在指令行執行程式的時候是可以帶參數的,那麼我們的程式怎麼接收參數呢?
-
傳參數
直接在可執行程式後面輸入參數就行,兩個參數之間用空格隔開
例:a.exe程式輸入help和in、out三個參數
note:如果要輸入帶有空格的參數,則需要加雙引号a.exe help in out
a.exe "hello world"
- 接受參數
int main(int argc, char * argv[])
argc: 代表程式啟動的時,指令行參數的個數。c/c++規定,可執行程式本身也是一個參數。是以,argc的值至少是1。
argv: 指針數組,其中的每一個元素都指向一個參數(字元串)。
#include <stdio.h>
int main(int argc, char * argv[])
{
printf("the numbers of param: %d \n",argc);
for(int i=0; i<argc; i++)
printf(" %s ",argv[i]);
}
執行:
a.exe help in out
輸出:
the numbers of param: 4
a.exe help in out
note: 在程式啟動的時候,作業系統就已經把使用者在指令行敲進去的參數,存在了某個地方了。作業系統在調用程式的時候再把指令行參數傳進去。
練習
答案:A
2.1 位運算
嵌入式裡面需要對寄存器進行操作時,用的比較多
c/c++提供了六種位運算符
TYPE | 描述 |
---|---|
& | 按位與(雙目) |
| | 按位或(雙目) |
^ | 按位異或(雙目) |
~ | 按位非(單目) |
<< | 左移(雙目) |
>> | 右移(雙目) |
-
按位與&
功能:
1.将變量中的某一位清0,同時其他位保持不變;
2.擷取變量中的某一位;
例:将int型變量n的低八位全部清零,其他位不變:
例:判斷int型變量的第3位(從右往左,從0開始數)是否為1?n = n & 0xffffff00;
if (n & 0x08 == 0x08)
因為0與任何數與都是0,1與任何數與都是任何數。是以我們要将特定數取出就用1去與就行。
當然如果要将具體位取出還要依賴于移位操作
-
按位或 |
功能:
用來将變量中的某些位置1
-
按位異或 ^
兩位相異,結果為1
兩位相同,結果為0
1 ^ (任何數) =》 取反
0 ^ (任何數) =》 不變
功能:
1.可以将變量中的某些位取反,而保留其他位不變
2.可以實作最簡單的加密和解密
特點:
如果 a^b=c,則 c^b=a 及 a^c=b
, 用此特點可以實作最簡單的加密和解密
例:a是要加密的資料,b是密鑰。c是加密後的資料。
3.不通過臨時變量,交換兩個變量的值
這是利用了功能2,以及任何數異或自己等于0,0異或任何數不變,
int a=5,b=8;
a = a^b;
b = a^b;
a = a^b;
printf("%d, %d \n",a,b);
-
左移運算符 <<
左移1位,就是乘以2,左移n位,就是乘以2^n
-
右移運算符 >>
note: 對于有符号的數,右移時候,符号位也會跟着一起移動。在大多數C和C++編譯器中處理右移:如果原來的那個符号位為1,那右移的時候左邊補充進來的那個高位就都是1, 如果被右移的數符号位是0, 那右移的時候,左邊補充出來的那些位就都是0. 大多數編譯器都是這麼規定的。
右移1位,就是除以2,右移n位,就是除以2^n。
并且最後結果是往小裡取整(規律,不是規定)
-25 >> 4 = -2
2.2 引用
類型名 & 引用名 = 某變量名
某個變量的引用,等價與這個變量,相當于這個變量的别名。
note:
1.定義引用時一定要将其初始化成引用某個變量
2.初始化之後,它就一直引用該變量,不會再引用别的變量了。
3.引用隻能引用變量,不能引用常量和表達式
- 引用作為函數傳回值
int n=4;
int & SetValue() {return n;}
int main()
{
SetValue() = 40;
cout << n;
}
-
常引用
不能通過常引用去修改其引用的内容
int n=100;
const int &i=n;
r = 200; //編譯出錯
n = 200; //編譯正确
-
常引用和非常引用的轉換
設T是變量類型,
const T & 和 T & 是不同的類型 !!!
T & 類型的引用或T類型的變量可以用來初始化const T&類型的引用。
const T類型的常變量和const T&類型的引用則不能用來初始化T &類型的引用,除非進行強制類型轉換
練習
答案 C
3.1 const關鍵字
const定義常量
const double pi = 3.1415926;
double const pi = 3.1415926;
這兩種定義方式都是一樣的含義
在c++裡面盡量用const替代#define,const有類型檢查。
const定義指針
- 指針本身是不可改變的
指針本身不可以改變char a = 'a'; char *const pContent = &a;
char b = 'b';pContent = &b;
錯
但是指向的内容是可以改變的
對*pContent = 'b';
- 指向的内容不可改變 (常量指針)
指向的内容不可通過指針改變const char * pContent; pContent = &a;
*pContent = 'b';
錯
但是可以通過變量自身改變
a = 'b';
對
note:不能把常量指針指派給非常量指針 (可以強制類型轉換)
-
const char * const pContent
3.2 動态記憶體配置設定
按需配置設定記憶體
new的兩種用法
note:用new定義出來的數組編譯時候不會有越界警告
用delete釋放new出來的數組的時候加[]
char *p = new char[10];
delete[] p;
練習
答案B
答案C
3.3 内聯函數,函數重載,參數預設
一般子函數在編譯的時候都隻會将調用指令編譯進去,随之而來的就是參數入棧,壓棧,彈棧等工作。inline關鍵字的作用就是将整個子函數的内容都編譯進去。
inline在傳回值類型前面
函數重載
一個函數,函數名字相同,參數類型和參數個數不一樣就行
note:不能按照傳回值類型區分函數重載,
因為就算有傳回值的函數在調用的時候也可以不接收傳回值
答案D
參數預設
c++中,在定義函數的時候,可以讓最右邊的連續多個參數有預設值。那麼在調用函數的時候,若相應的位置不寫參數,則對應的參數就是預設值。
函數參數可預設的目的在于提高程式的可擴充性。
如:在增加某項功能的時候,需要給函數新增參數,那麼原來調用這個函數的代碼也要增加參數,這樣就就會帶來不相容。有了函數預設就能将這兩種需求結合起來。
答案C
4.1 面向對象的設計方法
結構化程式設計的四大問題:
- 了解難
- 修改難
- 查錯難
- 重用難