指標介紹

指標的宣告與其他任何變數一樣,除了在變數的型別和名稱之間放置星號(*)以表示它是一個指標。

int *pointer; /* inside a function, pointer is uninitialized and doesn't point to any valid object yet */

要宣告兩個相同型別的指標變數,請在同一宣告中使用每個識別符號前面的星號。例如,

int *iptr1, *iptr2;
int *iptr3,  iptr4;  /* iptr3 is a pointer variable, whereas iptr4 is misnamed and is an int */

由&符號(&)表示的地址或引用運算子給出了給定變數的地址,該變數可以放在適當型別的指標中。

int value = 1;
pointer = &value;

由星號(*)表示的間接或解除引用運算子獲取指標指向的物件的內容。

printf("Value of pointed to integer: %d\n", *pointer);
/* Value of pointed to integer: 1 */

如果指標指向結構或聯合型別,那麼你可以取消引用它並使用 -> 運算子直接訪問其成員:

SomeStruct *s = &someObject;
s->someMember = 5; /* Equivalent to (*s).someMember = 5 */

在 C 中,指標是一種不同的值型別,可以重新分配,否則將被視為一個變數。例如,以下示例列印指標(變數)本身的值。

printf("Value of the pointer itself: %p\n", (void *)pointer);
/* Value of the pointer itself: 0x7ffcd41b06e4 */
/* This address will be different each time the program is executed */

因為指標是一個可變變數,所以它可能無法通過設定為 null 來指向有效物件

pointer = 0;     /* or alternatively */
pointer = NULL;

或者只是包含一個不是有效地址的任意位模式。後者是一個非常糟糕的情況,因為在指標被取消引用之前無法測試,只有對指標為空的情況進行測試:

if (!pointer) exit(EXIT_FAILURE);

如果指標指向有效物件,則只能取消引用指標,否則行為未定義。許多現代實現可能會通過引發某種錯誤(如分段錯誤和終止執行) 來幫助你,但其他實現可能只會使你的程式處於無效狀態。

解引用運算子返回的值是原始變數的可變別名,因此可以更改它,修改原始變數。

*pointer += 1;
printf("Value of pointed to variable after change: %d\n", *pointer);
/* Value of pointed to variable after change: 2 */

指標也可以重新分配。這意味著指向物件的指標稍後可用於指向同一型別的另一個物件。

int value2 = 10;
pointer = &value2;
printf("Value from pointer: %d\n", *pointer);
/* Value from pointer: 10 */

與任何其他變數一樣,指標具有特定型別。例如,你不能將 short int 的地址分配給指向 long int 的指標。這種行為被稱為型別懲罰,並且在 C 中是被禁止的,儘管有一些例外。

儘管指標必須是特定型別,但為每種型別的指標分配的記憶體等於環境用於儲存地址的記憶體,而不是指向的型別的大小。

#include <stdio.h>

int main(void) {
    printf("Size of int pointer: %zu\n", sizeof (int*));      /* size 4 bytes */
    printf("Size of int variable: %zu\n", sizeof (int));      /* size 4 bytes */
    printf("Size of char pointer: %zu\n", sizeof (char*));    /* size 4 bytes */
    printf("Size of char variable: %zu\n", sizeof (char));    /* size 1 bytes */
    printf("Size of short pointer: %zu\n", sizeof (short*));  /* size 4 bytes */
    printf("Size of short variable: %zu\n", sizeof (short));  /* size 2 bytes */
    return 0;
}

(注意:如果你使用的是不支援 C99 或 C11 標準的 Microsoft Visual Studio,則必須在上面的示例中使用 %Iu 1 而不是%zu。)

請注意,上面的結果可能因環境而異,但所有環境對於不同型別的指標都會顯示相同的大小。

根據卡迪夫大學 C 指標介紹的資訊提取

指標和陣列

指標和陣列在 C 中緊密相連 .C 中的陣列總是儲存在記憶體中的連續位置。指標算術始終按指向的專案大小進行縮放。因此,如果我們有一個三個雙打的陣列,以及指向基數的指標,則*ptr 指的是第一個雙重,*(ptr + 1) 指向第二個,*(ptr + 2) 指向第三個。更方便的表示法是使用陣列符號 []

double point[3] = {0.0, 1.0, 2.0};
double *ptr = point;

/* prints x 0.0, y 1.0 z 2.0 */ 
printf("x %f y %f z %f\n", ptr[0], ptr[1], ptr[2]);

所以基本上 ptr 和陣列名稱是可以互換的。此規則還意味著陣列在傳遞給子例程時會衰減到指標。

double point[3] = {0.0, 1.0, 2.0};

printf("length of point is %s\n", length(point));

/* get the distance of a 3D point from the origin */ 
double length(double *pt)
{
   return sqrt(pt[0] * pt[0] + pt[1] * pt[1] + pt[2] * pt[2])
}

指標可以指向陣列中的任何元素,也可以指向最後一個元素之外的元素。但是,將指標設定為任何其他值(包括陣列之前的元素)是錯誤的。 (原因是在分段體系結構上,第一個元素之前的地址可能跨越段邊界,編譯器確保最後一個元素加上一個元素不會發生)。

腳註 1:可以通過 printf()格式規範語法找到 Microsoft 格式資訊。