C語言自學攻略-指標

更新於 發佈於 閱讀時間約 8 分鐘

認識指標

指標,用來儲存變數的記憶體位址,宣告方式如下:

資料型別 *變數名稱 or 資料型別* 變數名稱

假設今天有一個整數變數x,內容為38,那我們如何利用指標接收變數x的記憶體位址呢? 方法如下:

int *p = &x;

現在指標(64位元電腦下通常為8bytes)和變數在記憶體中的樣子如下圖所示:

raw-image
  • 我們假設指標記憶體位址為0x7ffd8d3f7f46 - 0x7ffd8d3f7f52

接著我們試著用指標輸出內容: 以下示範:

#include<stdio.h>

int main()
{
int *p, x=38;
p = &x;
printf("%p",p); //輸出變數x的記憶體位址,以16進制表示
return 0;
}

接著我們想要利用指標輸出變數x的內容,如何實現? 方法如下:

#include<stdio.h>

int main()
{
int *p, x=38;
p = &x;
printf("%d",*p); //輸出變數x的內容
return 0;
}

上面程式碼中,我們藉由在p前面添加*(我們稱這樣為解參考)。

好,今天我又想宣告一個指標儲存p的記憶體位址,如何實現? 方法如下:

#include<stdio.h>

int main()
{
int *p, x=38;
p = &x;

int **ptr = &p;
printf("%p\n",p); //輸出變數x的記憶體位址,以16進制表示
printf("%p\n",ptr); //輸出p的記憶體位址,以16進制表示
printf("%p\n",*ptr); //輸出變數x的記憶體位址,以16進制表示
printf("%d",**ptr); //輸出變數x的內容
return 0;
}

陣列名稱可以當作指標?!

#include <stdio.h>

int main() {
int test[5]={60,70,80,90,100};
printf("%p\n",&test[0]);
printf("%p",test);
return 0;
}
/* 輸出
0x7ffffdcab4f0
0x7ffffdcab4f0
*/
  • 從上面程式碼我們發現,一維陣列名稱test&a[0]的輸出相同,表示了test其實也可以做為一個指標(隱式轉換),指向a[0]的記憶體位址。

接著我們再做一些變化並測試:

#include <stdio.h>

int main() {
int test[5]={60,70,80,90,100};
printf("%p\n",&test[0]+1);
printf("%p",test+1);
return 0;
}
/* 輸出
0x7ffffdcab4f4
0x7ffffdcab4f4
*/
  • 從上面程式碼,我們發現,當test+1(等同&test[0]+1)時,輸出的記憶體位址增加了4,其實不難理解,意思就是他指向了一維陣列下一個儲存空間的記憶體位址,即a[1]的記憶體位址。我們一樣可以透過解參考輸出陣列內容。如下示範:
#include <stdio.h>

int main() {
int test[5]={60,70,80,90,100};
printf("%d\n",*test);
printf("%d",*(test+1));
//printf("%d",*test+1); 這樣寫會變為60+1等於61
return 0;
}
/* 輸出
60
70
*/

好,現在如果我想要再宣告一個指標指向這個陣列,只要把名字test丟給指標就行,如下示範:

#include <stdio.h>

int main() {
int a[5]={60,70,80,90,100};
int *p = a;
printf("%p\n",a);
printf("%d\n",*a);
printf("%p\n",a+1);
printf("%d\n",*(a+1));

printf("%p\n",p);
printf("%d\n",*p);
printf("%p\n",p+1);
printf("%d\n",*(p+1));

printf("%p\n",&p[0]);
printf("%d\n",p[0]);
printf("%p\n",&p[1]);
printf("%d\n",p[1]);

return 0;
}
/* 輸出
0x7fffb32eb0e0
60
0x7fffb32eb0e4
70
0x7fffb32eb0e0
60
0x7fffb32eb0e4
70
0x7fffb32eb0e0
60
0x7fffb32eb0e4
70
*/
  • 上面程式碼值得一提的是,p也可以使用索引的方式存取陣列,使用上就像是a

接著,我還有一些觀念想講:

觀念釐清

  1. 在 C 語言中,陣列名會被隱式地轉換為指向其第一個元素的指標。然而,當使用取位址運算符(&)時,情況有所不同。
  • a 在表達式中,a 會被視為指向陣列第一個元素的指標,型別為 int*(假設 aint 型別的陣列)。
  • &a 這裡,&a 取得的是整個陣列 a 的位址,其型別為 int (*)[N],其中 N 是陣列的大小。

  1. 型別區別
  • int* 指向 int 型別的指標。
  • int (*)[N] 指向大小為 Nint 陣列的指標。

  1. 指標算術中的位址計算

指標算術中的位址計算取決於指標的型別和指標運算。當對指標進行加法(如 ptr + 1)時,實際的位址增加量為 1 * sizeof(指標所指向的型別)

  • 對於 int* ptr + 1 將位址增加 1 * sizeof(int)
  • 對於 int (*)[N]ptr + 1 將位址增加 1 * sizeof(int[N]),也就是 N * sizeof(int)

假設我們有一個陣列:

int a[4] = {1, 2, 3, 4};
  • &a 的型別: int (*)[4],即指向包含 4 個整數的陣列的指標。
  • &a + 1 由於 &a 的型別是 int (*)[4],因此加1時,實際增加的位址為 1 * sizeof(int[4]),也就是 1 * (4 * sizeof(int))

示例 1:使用 &a(指向整個陣列的指標)

int a[4] = {1, 2, 3, 4};
int (*p)[4] = &a; // p 的型別是 int (*)[4]

printf("%p\n", p); // 輸出陣列 a[0] 的位址
printf("%p\n", p + 1); // 輸出位址增加 4 * sizeof(int) 後的位址
  • p + 1 將位址增加 4 * sizeof(int)

示例 2:使用 a(指向第一個元素的指標)

c
int a[4] = {1, 2, 3, 4};
int *p = a; // p 的型別是 int*

printf("%p\n", p); // 輸出 a[0] 的位址
printf("%p\n", p + 1); // 輸出位址增加 sizeof(int) 後的位址
  • p + 1 將位址增加 sizeof(int)

在當今數位時代,電資領域人才需求爆發式成長,不論是前端網頁設計、嵌入式開發、人工智慧、物聯網還是軟硬體整合,這些技術都在改變世界。而掌握 C/C++、Python、數位邏輯、電路學與嵌入式開發等大學電資領域的課程,正是進入這個高薪、高需求產業的關鍵!
留言
avatar-img
留言分享你的想法!

































































本章將介紹 C 語言的函式 (Functions),這是將程式碼模組化、提高可讀性與重用性 的關鍵技術。透過函式,我們可以 拆分程式邏輯、減少重複代碼,本章亦透過實作讓讀者學習 參數傳遞、回傳值、遞迴等重要觀念。
本章將介紹 C 語言的陣列 (Arrays),這是一種 連續儲存多個相同類型變數 的數據結構。透過陣列,我們可以有效管理與操作大量數據,並應用在 數據處理、排序、搜尋與多維數據存取 等情境中。
本章將介紹 C 語言的條件控制與迴圈控制,這是讓程式具備 邏輯判斷能力與重複執行能力 的關鍵技術。透過 if 判斷式、switch 多重選擇、for 迴圈、while 迴圈 等控制結構,我們可以有效管理程式流程,提升代碼的 效率與可讀性。
本章將介紹 C 語言的運算子 (Operators),這是程式語言的基礎,負責執行數值計算、條件判斷與邏輯運算。我們將最先學習變數在記憶體中的樣子,這是非常重要的觀念,接著漸入到算術運算、關係運算、邏輯運算、位元運算與三元運算子等,並透過 運算子優先順序 來確保正確的運算執行順序。
本文章介紹了 C 語言putchar, getchar, puts, fgets函數及其使用方法與常見問題解決方案。包含程式碼範例、問題分析及解決方法,幫助讀者理解並避免輸入錯誤。
在C語言中,scanf()可能並沒有我們所想的那麼簡單且單調,本章節會列出4點補充的使用方式。這些都是容易忽視的小知識。
本章將介紹 C 語言的函式 (Functions),這是將程式碼模組化、提高可讀性與重用性 的關鍵技術。透過函式,我們可以 拆分程式邏輯、減少重複代碼,本章亦透過實作讓讀者學習 參數傳遞、回傳值、遞迴等重要觀念。
本章將介紹 C 語言的陣列 (Arrays),這是一種 連續儲存多個相同類型變數 的數據結構。透過陣列,我們可以有效管理與操作大量數據,並應用在 數據處理、排序、搜尋與多維數據存取 等情境中。
本章將介紹 C 語言的條件控制與迴圈控制,這是讓程式具備 邏輯判斷能力與重複執行能力 的關鍵技術。透過 if 判斷式、switch 多重選擇、for 迴圈、while 迴圈 等控制結構,我們可以有效管理程式流程,提升代碼的 效率與可讀性。
本章將介紹 C 語言的運算子 (Operators),這是程式語言的基礎,負責執行數值計算、條件判斷與邏輯運算。我們將最先學習變數在記憶體中的樣子,這是非常重要的觀念,接著漸入到算術運算、關係運算、邏輯運算、位元運算與三元運算子等,並透過 運算子優先順序 來確保正確的運算執行順序。
本文章介紹了 C 語言putchar, getchar, puts, fgets函數及其使用方法與常見問題解決方案。包含程式碼範例、問題分析及解決方法,幫助讀者理解並避免輸入錯誤。
在C語言中,scanf()可能並沒有我們所想的那麼簡單且單調,本章節會列出4點補充的使用方式。這些都是容易忽視的小知識。
你可能也想看
Google News 追蹤
Thumbnail
了解這些運算子及其優先等級有助於更好地理解和編寫 JavaScript 代碼
Thumbnail
在本章節中,我們將學習JavaScript的基本語法,包括如何註解代碼和如何聲明變數。瞭解這些基礎知識對於進一步學習和使用JavaScript來編寫代碼是非常重要的。
Thumbnail
C 語言的函式庫定義了許多好用的函式,在寫 C++ 的時候可以拿來用。這是因為 C++ 當初在設計的時候,就有刻意把 C 涵蓋進來。 基本用法 首先要導入 C 語言的標準函式庫: #include <cstdlib> 以 c 作為開頭表示它是 C 語言的函式庫,只是被我們拿來 C++ 的程式
Thumbnail
在為「質數」此純數學範疇搜索相關的教學資源時,我發現到一個很好用的教具,那就是「Anchor Chart(錨點圖)」,類似於「海報展示」,對於純數學抽象概念的引導、闡明非常有幫助。
Thumbnail
解決電腦上遇到的問題、證明正確性、探討效率 並且很著重溝通,說服別人你做的事是正確且有效率的。 內容: 計算模型、資料結構介紹、演算法介紹、時間複雜度介紹。
Thumbnail
編輯的基本功,是對文字的敏感度。
Thumbnail
了解這些運算子及其優先等級有助於更好地理解和編寫 JavaScript 代碼
Thumbnail
在本章節中,我們將學習JavaScript的基本語法,包括如何註解代碼和如何聲明變數。瞭解這些基礎知識對於進一步學習和使用JavaScript來編寫代碼是非常重要的。
Thumbnail
C 語言的函式庫定義了許多好用的函式,在寫 C++ 的時候可以拿來用。這是因為 C++ 當初在設計的時候,就有刻意把 C 涵蓋進來。 基本用法 首先要導入 C 語言的標準函式庫: #include <cstdlib> 以 c 作為開頭表示它是 C 語言的函式庫,只是被我們拿來 C++ 的程式
Thumbnail
在為「質數」此純數學範疇搜索相關的教學資源時,我發現到一個很好用的教具,那就是「Anchor Chart(錨點圖)」,類似於「海報展示」,對於純數學抽象概念的引導、闡明非常有幫助。
Thumbnail
解決電腦上遇到的問題、證明正確性、探討效率 並且很著重溝通,說服別人你做的事是正確且有效率的。 內容: 計算模型、資料結構介紹、演算法介紹、時間複雜度介紹。
Thumbnail
編輯的基本功,是對文字的敏感度。