【原創】【基礎】一文搞懂嚴蔚敏資料結構SqList &L和SqList L、ElemType &e和ElemType e

碼頭小漁夫發表於2021-04-27

旁白

最近小漁夫在看嚴蔚敏、李冬梅《資料結構 c語言版》(第2版),學到第二章順序表的實現時,看到函式引數一會是SqList &L、一會又是SqList L、一會ElemType &e、一會又ElemType e,當場大寫的黑人問號加感嘆號。這都什麼玩意,一會有&一會又沒有,都代表什麼意思呢?

於是帶著這些問號去找答案,上網上看了很多,看到的比較零散,於是我整理了一下,理清原因後,心想估計也有同學跟我一樣的黑人問號,於是就有著這篇文章,希望能有點幫助吧。

先說答案

嚴書裡的程式碼是虛擬碼,什麼是虛擬碼?顧名思義不是真的程式碼,拿到電腦上去跑不起來的程式碼,虛擬碼重點是表達思路、表達想法的。

所以,書裡函式引數中有&,想表達的意思是:希望通過函式改變該引數的值。可以看到書裡在新建順序表、插入一個資料、刪除資料等改變順序表的操作時用到了SqList &L,因為這些操作會改變表的內容;在查詢操作時,沒有改變表,順序表前沒有&,用到了SqList L;在取值時用到了ElemType &e,是想把取到的值通過引數返回。

C語言裡只能通過指標實現。書裡寫的是虛擬碼,而不是真正的C程式碼;在C++裡可以通過指標和引用(C語言無引用)實現。

有些同學可能不太理解怎麼通過函式改變傳進來引數的值,下面詳細介紹一個例子就明白了。

詳細介紹

例子是用c語言的指標實現的,說起指標不得不提兩個符號*&,那先來看指標中的*&

C語言指標中的*&

首先,一般看一個變數,看它的3點。變數名稱、資料、地址。如定義一個變數int a = 5,變數名是a,值是5,在記憶體中的地址是0x00001111
image
瞭解了變數,就可以瞭解指標了,指標可以理解成記憶體裡的地址,指標變數就是儲存地址的變數。

&是取地址運算子,用於取變數地址;例如:int a = 5, &a表示變數a的地址0x00001111

*出現在不同的地方含義不同,但就我現在理解的,一般出現在兩個地方:

  • 函式引數中和變數定義中,表示定義一個指標變數。如 int *p ,int *p = &a.
  • 等號右邊,*(地址)表示取值運算。如int a = 5; int *p = &a; *p,中變數啊的值為5,指標變數p的值為0x00001111*p的值為5

例子:交換兩變數的值

瞭解了指標後,來看下這個例子。例子中寫了兩個函式,來交換兩變數的值,第一個函式swap1沒用指標,第二個函式swap2用了指標。結果你猜,哪個函式能改變傳進來引數的值?

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
	int num1 = 1;
	int num2 = 2;
	swap1(num1, num2);
	printf("num1 = %d, num2 = %d\n", num1, num2);
	swap2(&num1, &num2);
	printf("num1 = %d, num2 = %d\n", num1, num2);
	// test();
	return 0;
}

void swap1(int a, int b) {
	int temp;
	temp = a;
	a = b;
	b = temp;
}

void swap2(int *a, int *b) {
	int temp;
	temp = *a;
	*a = *b;
	*b = temp;
}

如圖:執行一下,得到結果。第二個函式起作用了,也就是用了指標的函式能改變傳進來引數的值,實現交換兩變數的效果。這就是通過函式改變傳進來引數的值

執行結果

到這裡,已經得到答案了。

至於,為什麼第一個函式沒有實現交換,有興趣的再往下看看。

單步除錯一下,我發現了其中的奧妙。

除錯開始,如下圖,變數num1值為1,地址為0x62fe1c,變數num2值為2,地址為0x62fe18

為什麼1

往下走,開始呼叫函式,進到函式swap1裡。如圖,變數num1num2沒什麼變化。引數ab已經接收到傳進來的引數了。同時發現num1num2的 地址和ab不一樣,原來函式會把形式引數當作區域性變數,然後在棧中開闢記憶體空間,用於存放由主調函式傳遞進來的實參值,從而形成了實參的一個副本(替身)。

為什麼2

再往下走,走完發現了驚喜,與上圖相比ab互換了。而變數num1num2和還是沒什麼變化。

為什麼3

最後,函式swap1執行結束,輸出結果num1 = 1, num2 = 2。可以發現雖然變數交換了,但是隻是交換了副本(替身)。至於為什麼用了指標就可以交換真身呢?感興趣,動動小手去探索探索吧,哈哈哈。

image

附錄

1. *p和**p的區別

int *p 是一級指標,存放的是一個變數的地址。

int **p是二級指標,存放的是指標變數的地址。

例子:

//定義整形變數
int a = 6;     
//定義一個指標指向這個變數
int *p = &a;   
//定義一個二級指標指向p指標
int **pp = &p; 
// 那麼取出6的方式都有哪些呢?
printf("a=%d", a);
printf("a=%d", *p);
printf("a=%d", **pp);

以上3行輸出的值都是6 。

2. *&p和&*p的區別

根據單目運算子運算的優先順序,*&p 等價於*(&p)&*p 等價於&(*p)

  • 如果p是指標變數,那麼*&p = p&*p = p,都等於p,但還沒定義p指向哪,存的是誰的地址。

  • 如果p是一個int變數,那麼*&p = p;而&*p是非法的,因為*p非法。

比如int p =10;那麼*&p = *(&p) = p = 10(即從p的地址取值),而&*p = &(*p) 則非法,因為p=10,*10是取記憶體地址為10的值,這在c語言中是不合法的。

後續

我在學習中發現,c只能通過指標實現這種方式,而C++不僅能通過指標實現,還能通過引用實現。並且C++還提倡使用引用。本來想繼續寫寫,什麼是C++引用,為什麼C++引進這個概念,這個概念有什麼好處、C++指標引數和引用引數有什麼區別的。但發現跟主題好像離得有點遠,扯到C++去了,作罷。看看後面有機會用C++實現演算法的時候再行補上。

才疏學淺,如有不當,請批評指正。

你的支援也是我的動力,最後筆記對你有用,別忘了點贊支援下哦。

相關文章