C語言中的指針變量
C 語言中,指針變量也是變量,只不過跟 char、int 型等基本類型變量不同,指針變量中保存的是其他變量的地址和類型。
通過這個地址,並根據類型來讀取指定長度的字節,就可以把這個變量解析出來。
int a = 3;
int *p = &a; // & 是取地址符號,返回變量 a 的地址
printf("%d\n", *p);
C 語言中本身不支持字符串,但是通過 char *
類型的指針可以實現字符串效果:
char *s = "hello world";
printf("%s\n", s);
上面代碼中,創建指針變量 s,指向字符類型的變量。然後把變量 s 的值當做字符串類型來解析,直到碰到字符串結束標誌 \0
就結束讀取。
字符串數組
char *arr[] = {"hello world", "test"};
printf("%s\n", arr[0]);
上面代碼中,先創建數組 arr,數組中的每個元素都是 char *
類型,即指向字符的指針。然後把 arr[0]
數組第一個元素當做字符串解析。
char (*p)[10] = "hello";
printf("%s\n", *p);
二級指針
二級指針跟普通指針變量的區別在於:指針變量直接報錯目標變量的地址,而二級指針變量保存的是另一個指針變量的地址,另一個指針變量才真正保存目標變量的地址。
二級指針的主要用途:
- 字符串數組
- main 函數的入參 argv
字符串數組
上面示例用數組的形式實現了字符串數組,在聲明數組的同時初始化。其實還可以用二級指針實現字符串數組。
例如 char **p
,聲明的變量 p 就是一個二級指針。p 指向的變量類型是 char *
,即字符指針,然後這個字符指針才真正指向一個字符變量。
下面代碼是錯誤的示例,會報錯:segmentation fault。
#include <stdio.h>
#include <malloc.h>
int main () {
char **p;
*p = "helo"; // 未分配內存空間就直接使用,報錯
p[1] = "wold";
printf("%s\n", *p);
return 0;
}
出現段錯誤的原因是:編譯器會自動爲創建的 char **
類型的變量 p 分配內存空間。但是,*p
指向的 char *
類型的變量則並沒有分配內存空間,就直接使用了。
只要讓 p 變量指向一塊經過初始化的內存,即可消除錯誤:
#include <stdio.h>
#include <malloc.h>
int main () {
// 分配內存空間,並將首地址返回給二級指針變量 p
// 然後用這塊連續內存保存中間指針變量
char **p = malloc(sizeof(char *) * 2);
*p = "helo";
p[1] = "wold";
printf("%s\n", *p);
return 0;
}
指向數組的指針
一維數組
int a[10];
int *p = a;
二維數組
二維數組不能像一維數組那樣簡單的傳遞指針變量。
二維數組本質上仍是內存中的一塊連續地址空間,只不過人爲的將這塊空間分隔爲固定長度的子空間。
只要確保指針每次加一時,可以跳到下一塊子空間,就可以用指針完美的表示二維數組。char (*p)[n]
就可以實現這個目的,其中 n 是子空間大小。
char (*p)[10]
這裏的括號不能省略,否則 char *p[10]
,編譯器會從右到左解析,變量 p 解析爲數組,存放 10 個 char *
類型的變量。
#include <stdio.h>
int main () {
char arr[2][10] = {{"hello"}, {'w'}};
// 定義指針變量 p,指向有 10 個元素的 char 類型的數組
char (*p)[10] = arr;
printf("%s\n", *p);
printf("%s\n", *(p+1));
(*p)[0] = 'a';
printf("%s\n", *p);
(*(p + 1))[0] = 'a';
printf("%s\n", *(p+1));
return 0;
}