【原創】一文搞懂嚴蔚敏數據結構迷人的SqList &L和SqList L、ElemType &e和ElemType e


旁白

最近小漁夫在看嚴蔚敏、李冬梅《數據結構 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++實現算法的時候再行補上。

以上個人拙作,希望能給路上同仁帶去點光。

若不小心對你有啟發,評論留下你的故事,點贊分享讓更多人為你受益。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM