iOS開發 -- C語言基礎8(指標)
iOS開發 -- C語言基礎8(指標)
指標是C語言中非常重要的資料型別,如果你說C語言中除了指標,其他你都學得很好,那你乾脆說沒學過C語言。究竟什麼是指標呢?我們先來看一個概念。
直接引用
1. 回想一下,之前我們是如何更改某個變數的值?
我們之前是通過變數名來直接引用變數,然後進行賦值:
char a;
a = 10;
2. 看上去是很簡單,其實程式內部是怎麼操作的呢?
其實,程式對變數的讀寫操作,實際上是對變數所在的儲存空間進行寫入或取出資料。就上面的程式碼而言,系統會自動將變數名a轉換為變數的儲存地址,根據地址找到變數a的儲存空間,然後再將資料10以2進位制的形式放入變數a的儲存空間中。
3. 通過變數名引用變數,由系統自動完成變數名和其儲存地址之間的轉換,稱為變數的"直接引用"方式
一、什麼是指標?
1.我們已經知道,"直接引用"是直接通過變數名來讀寫變數
2.C語言中還有一種"間接引用"的方式(以變數a為例):首先將變數a的地址存放在另一個變數中,比如存放在變數b中,然後通過變數b來間接引用變數a,間接讀寫變數a的值。這就是"間接引用"。
如果程式通過"間接引用"的方式來修改a的值,可以這樣做:先根據 變數名b 獲取 變數b 的地址ffc2,取出變數b中儲存的內容ffc1,也就是變數a的地址,再根據變數a的地址ffc1找到a的儲存空間,然後修改裡面的資料。
3.總結一句:用來存放變數地址的變數,就稱為"指標變數"。在上面的情況下,變數b就是個"指標變數",我們可以說指標變數b指向變數a。
二、指標的定義
一般形式:類名識別符號 *指標變數名;
int *p;
float *q;
"*"是一個說明符,用來說明這個變數是個指標變數,是不能省略的,但它不屬於變數名的一部分
前面的型別識別符號表示指標變數所指向的變數的型別,而且只能指向這種型別的變數
三、指標的初始化
1.先定義後初始化
// 定義int型別的變數a
int a = 10;
// 定義一個指標變數p
int *p;
// 將變數a的地址賦值給指標變數p,所以指標變數p指向變數a
p = &a;
注意第8行,賦值給p的是變數a的地址&a
2.在定義的同時初始化
// 定義int型別的變數a
int a = 10;
// 定義一個指標變數p
// 並將變數a的地址賦值給指標變數p,所以指標變數p指向變數a
int *p = &a;
3.初始化的注意
指標變數是用來存放變數地址的,不要給它隨意賦值一個常數。下面的寫法是錯誤的
int *p;
p = 200; // 這是錯誤的
四、指標運算子
1.給指標指向的變數賦值
char a = 10;
printf("修改前,a的值:%d\n", a);
// 指標變數p指向變數a
char *p = &a;
// 通過指標變數p間接修改變數a的值
*p = 9;
printf("修改後,a的值:%d", a);
當程式剛執行完第5行程式碼時,記憶體中大概的分佈情況是這樣的
,a值是10,p值就是變數a的地址ffc3。
注意下第5、第8行,都有個"*",它們的含義是不一樣的:
(1) 第5行的"*"只是用來說明p是個指標變數
(2) 第8行的"*"是一個指標運算子,這裡的*p代表根據p值ffc3這個地址訪問對應的儲存空間,也就是變數a的儲存空間,然後將右邊的數值9寫入到這個儲存空間,相當於 a = 9;,於是記憶體中就變成這樣了
輸出結果為:
可以發現,我們通過變數p間接修改了變數a的值。
2.取出指標所指向變數的值
指標運算子除了可以賦值之外,還可以用於取值
char a = 10;
char *p;
p = &a;
char value = *p;
printf("取出a的值:%d", value);
輸出結果:
第6行中的*p的意思是:根據p值(即變數a的地址)訪問對應的儲存空間,並取出儲存的內容(即取出變數a的值),賦值給value。
3.使用注意
在指標變數沒有指向確定地址之前,不要對它所指的內容賦值。下面的寫法是錯誤的
int *p;
*p = 10; //這是錯誤的
應該在指標變數指向一個確定的變數後再進行賦值。下面的寫法才是正確的
// 定義2個int型變數
int a = 6, b;
// 定義一個指向變數b的指標變數p
int *p;
p = &b;
// 將a的值賦值給變數b
*p = a;
五、指標的用途舉例
1.例子1
前面我們通過指標變數p間接訪問了變數a,在有些人看來,覺得指標變數好傻B,直接用變數名a訪問變數a不就好了麼,幹嘛搞這麼麻煩。彆著急,接下來舉個例子,讓大家看看指標還能做什麼事情。
現在有個要求:寫一個函式swap,接收2個整型引數,功能是互換兩個實參的值。
1> 如果沒學過指標,你可能會這樣寫
void swap(char v1, char v2) {
printf("更換前:v1=%d, v2=%d\n", v1, v2);
// 定義一箇中間變數
char temp;
// 交換v1和v2的值
temp = v1;
v1 = v2;
v2 = temp;
printf("更換後:v1=%d, v2=%d\n", v1, v2);
}
int main()
{
char a = 10, b = 9;
printf("更換前:a=%d, b=%d\n", a, b);
swap(a, b);
printf("更換後:a=%d, b=%d", a, b);
return 0;
}
輸出結果:
雖然v1和v2的值被交換了,但是變數a和b的值根本就沒有換過來。因為基本資料型別作為函式實參時,只是純粹地將值傳遞給形參,形參的改變並不影響實參。
我們可以簡要分析一下這個過程:
* 在第20行中,將變數a、b的值分別傳遞給了swap函式的兩個形參v1、v2
* 在第8行中,將v1的值賦值給了temp
* 在第9行中,將v2的值賦值給了v1
* 在第10行中,將temp的值賦值給了v2
就這樣,v1和v2的值被交換了,但是a和b的值一直都沒有改變
2> 如果學了指標,就應該這樣寫
void swap(char *v1, char *v2) {
// 中間變數
char temp;
// 取出v1指向的變數的值
temp = *v1;
// 取出v2指向的變數的值,然後賦值給v1指向的變數
*v1 = *v2;
// 賦值給v2指向的變數
*v2 = temp;
}
int main()
{
char a = 10, b = 9;
printf("更換前:a=%d, b=%d\n", a, b);
swap(&a, &b);
printf("更換後:a=%d, b=%d", a, b);
return 0;
}
先看看輸出結果:
變數a和b的值終於換過來了。
解釋一下:
(在16位編譯器環境下,一個指標變數佔用2個位元組)
* 先注意第20行,傳遞是變數的地址。因此swap函式的形參v1指向了變數a,v2指向了變數b
* 第6行程式碼是取出v1指向的變數的值,也就是變數a的值:10,然後賦值給變數temp
* 第9行程式碼是取出v2指向的變數(變數b)的值,然後賦值給v1指向的變數(變數a)
* 第12行程式碼是將temp變數的值賦值給v2指向的變數(變數b)
相信你已經感受到指標的強大了,如果沒有指標,在一個函式的內部根本改變不了外部的實參。
2.例子2
接下來再舉一個指標的實用例子。預設情況下,一個函式只能有一個返回值,有了指標,我們可以實現函式有"多返回值"。
現在有個要求:寫一個函式sumAndMinus,可以同時計算2個整型的和與差,函式執行完畢後,返回和與差(注意了,這裡要返回2個值)
// 計算2個整型的和與差
int sumAndMinus(int v1, int v2, int *minus) {
// 計算差,並賦值給指標指向的變數
*minus = v1 - v2;
// 計算和,並返回和
return v1 + v2;
}
int main()
{
// 定義2個int型變數
int a = 6, b = 2;
// 定義2個變數來分別接收和與差
int sum, minus;
// 呼叫函式
sum = sumAndMinus(a, b, &minus);
// 列印和
printf("%d+%d=%d\n", a, b, sum);
// 列印差
printf("%d-%d=%d\n", a, b, minus);
return 0;
}
輸出結果:
和與差都由同一個函式計算並返回出來。和是函式的直接返回值,差是通過函式的第3個指標引數間接返回。
因此有了指標,我們可以讓函式有"無限個"返回值。
六、關於指標的疑問
剛學完指標,都可能有一大堆的疑惑,這裡我列出幾個常見的疑惑吧。
1.一個指標變數佔用多少個位元組的記憶體空間?佔用的空間是否會跟隨所指向變數的型別而改變?
在同一種編譯器環境下,一個指標變數所佔用的記憶體空間是固定的。比如,在16位編譯器環境下,任何一個指標變數都只佔用2個位元組,並不會隨所指向變數的型別而改變。
2.既然每個指標變數所佔用的記憶體空間是一樣的,而且儲存的都是地址,為何指標變數還要分型別?而且只能指向一種型別的變數?比如指向int型別的指標、指向char型別的指標。
其實,我覺得這個問題跟"陣列為什麼要分型別"是一樣的。
* 看下面的程式碼,利用指標p讀取變數c的值
int i = 2;
char c = 1;
// 定義一個指向char型別的指標
char *p = &c;
// 取出
printf("%d", *p);
這個輸出結果應該難不倒大家:
,是可以成功讀取的。
* 如果我改一下第5行的程式碼,用一個本應該指向int型別變數的指標p,指向char型別的變數c
int *p = &c;
我們再來看一下輸出:,c的原值是1,現在取出來卻是513,怎麼回事呢?這個要根據記憶體來分析
根據變數的定義順序,這些變數在記憶體中大致如下圖排布:
其中,指標變數p和int型別變數i各佔2個位元組,char型別的c佔一個位元組,p指向c,因此p值就是c的地址
1> 最初的時候,我們用char *p指向變數c。當利用*p來獲取變數c的值時,由於指標p知道變數c是char型別的,所以會從ffc3這個地址開始讀取1個位元組的資料:0000 0001,轉為10進位制就是1
2> 後來,我們用int *p指向變數c。當利用*p獲取變數c的值時,由於指標p認為變數c是int型別的,所以會從ffc3這個地址開始讀取2個位元組的資料:0000 0010 0000 0001,轉為10進位制就是513
可見,給指標分類是多麼重要的一件事,而且一種指標最好只指向一種型別的變數,那是最安全的。
相關文章
- C語言基礎-指標C語言指標
- C語言基礎-1、指標C語言指標
- C語言函式指標基礎C語言函式指標
- C語言指標和陣列基礎C語言指標陣列
- C語言基礎及指標⑧檔案IOC語言指標
- iOS開發系列--C語言之指標iOSC語言指標
- C語言程式設計基礎:指標陣列與陣列指標C語言程式設計指標陣列
- C語言 C語言野指標C語言指標
- C語言(指標)C語言指標
- C語言指標C語言指標
- C語言語法基礎--S2函式和指標C語言函式指標
- C指標原理(15)-C指標基礎指標
- C指標原理(14)-C指標基礎指標
- C語言-指標操作C語言指標
- C語言指標(二) 指標變數 ----by xhxhC語言指標變數
- c語言指標彙總C語言指標
- C語言指標學習C語言指標
- c語言指標詳解C語言指標
- C語言 函式指標C語言函式指標
- C語言指標筆記C語言指標筆記
- C語言指標(三):陣列指標和字串指標C語言指標陣列字串
- iOS開發系列--C語言之基礎知識iOSC語言
- C語言:指標,C的靈魂C語言指標
- C語言指標安全及指標使用問題C語言指標
- plsql開發語言基礎SQL
- C語言知識彙總 | 51-C語言字串指標(指向字串的指標)C語言字串指標
- C語言基礎C語言
- 搞清楚C語言指標C語言指標
- C語言 指標與陣列C語言指標陣列
- C語言指標基本知識C語言指標
- C語言指標詳解(一)C語言指標
- C語言指標詳解(二)C語言指標
- C語言指標用法大全C語言指標
- c語言實現this指標效果C語言指標
- C語言指標細節_1C語言指標
- 指標——C語言的靈魂指標C語言
- C語言知識彙總 | 56-C語言NULL空指標以及void指標C語言Null指標
- 專家審讀第8期——《提速C程式》+《征服C語言指標》C程式C語言指標