1. 程式人生 > 實用技巧 >C/C++指標學習記錄(二)

C/C++指標學習記錄(二)

上一篇: C/C++指標學習記錄(一)

1、指定定義的基本原則。

我們在使用指標的時候,記住下面的準則可以很好的幫助我們節約修改程式的時間。

  • (1):永遠清楚每一個指標指向了哪裡,指標必須指向一塊有意義的記憶體。
  • (2):永遠清楚指標指向的物件的內容是什麼。
  • (3):永遠不要使用未初始化的指標變數。

2、連結串列

建立連結串列是我們學習資料結構的最基礎的能力。連結串列這一塊真的就是聽懂容易,上手難。但是解決方法非常樸實,多敲就好!

  • (1):概念。
    官方定義:單鏈表是一種鏈式存取的資料結構,用一組地址任意的儲存單元存放線性表中的資料元素。連結串列中的資料是以結點來表示的,每個結點的構成:元素(資料元素的映象) + 指標(指示後繼元素儲存位置),元素就是儲存資料的儲存單元,指標就是連線每個結點的地址資料。


    可能看文字比較費力,那我們繼續看一下概述圖。




其實就是,我們建立了一個結構體。這個結構體裡面有兩個部分,其一是 資料區 ,其二就是我們的 指標區 (裡面存放的就是下一個結構體的地址)。
假如我要定義一下關於學生成績資訊的結構體:

typedef struct Student
{
	//資料區
	char id[12];//學生學號
	float Match;//數學成績
	float Chinese;//語文成績

	//地址區
    struct Student *next;//指向下一個學生資訊結構體
}

上面的結構體就是我們連結串列裡面最小的單位。接下來我們就要開始建立單鏈表。這裡呢我們需要介紹一下頭指標,對於整一張連結串列我們只需要知道指向第一個節點的地址,那麼我們就可以通過遍歷來獲取整張表的資訊。所以建立連結串列的時候不要忘記定義一個頭指標。

  • 不用malloc()函式建立連結串列的可行性實驗


    寫連結串列的時候我們都會用到 <stdlib.h> 裡面的 malloc() 動態分配記憶體的函式。但是突然有一天,我想到反正指標都是指向的地址,我可以直接定義一個變數並且初始化它。在把地址賦值給指標變數就可以了。
    插入函式程式碼如下:
int insert(Stu *b)//指向連結串列的最後一個節點。
{
	Stu stu;
	Stu *f;
	scanf("%s %f %f",stu.id,&stu.Chinese,&stu.Match);//初始化
        if(stu.id!="EOF")
	{
		f=&stu;
		f->next=NULL;
		b->next=f;
                //b=f;這一句沒有辦法修改引數b的值。就像傳參裡面的位元組傳值。
		return 0;
	}
	else
	{
		return 1;
	}
}

其實在先前一小會兒,我都覺得我的程式碼沒有問題。可是,現在我知道我錯了。雖然思想沒有問題。但是程式碼是真的有問題。因為每次我插入新節點的時候,新建的節點物件。他在記憶體中的地址都被CPU分到了同一個地方,所以我的連結串列根本沒有辦法延長。並且非常尷尬的是,最後一個節點的地址變數指了自己。唯一的解決辦法只有在每插入一個節點的時候都要重新宣告一個節點變數,這樣可能才能達到目的。但是這樣做的話,我為什麼不用陣列呢?因為這樣建立連結串列我也必須事先知道我需要定義多少個變數。

  • 使用malloc()函式建立連結串列
    主要程式碼:
int insert(Stu *b)//指向連結串列的最後一個節點。
{
	Stu stu;
	Stu *f;
	char ch[]={"EOF"};
	f=(Stu *)malloc(sizeof(Stu));//申請空間

	scanf("%s %f %f",stu.id,&stu.Chinese,&stu.Match);//初始化
       if(stu.id[0]!=ch[0])
	{
		*f=stu;
		f->next=NULL;
		b->next=f;	
                //b=f;這一句沒有辦法修改引數b的值。就像傳參裡面的位元組傳值。
		return 0;
	}
	else
	{
		return 1;
	}
}

現在討論一下為什麼我要註釋掉: b=f 。原因就是傳引數直接傳值的原因。被傳入引數僅僅只是把自己的內容傳了進去,所有的操作都僅僅實在擁有相同內容的另一個變數下進行的。
所以進行值傳遞就OK了。
修改程式碼:

int insert(Stu* &b)//
{
	Stu stu;
	Stu *f;
	char ch[]={"EOF"};
	f=(Stu *)malloc(sizeof(Stu));//申請空間

	scanf("%s %f %f",stu.id,&stu.Chinese,&stu.Match);//初始化
    if(stu.id[0]!=ch[0])
	{
		*f=stu;
		f->next=NULL;
		b->next=f; 
		b=f;
		return 0;
	}
	else
	{
		return 1;
	}
}

好了指標的部分就到此結束!