指標
- 一、指標三連問
- 1.1 什么是指標?
- 1.2 為什么使用指標?
- 1.3 指標怎么用?
- 二、指標和指標的型別
- 2.1 指標型別
- 2.2 指標的解參考
- 三、野指標
- 3.1 概念
- 3.2 野指標成因
- 3.2.1 指標未初始化
- 3.2.2 指標越界訪問
- 3.2.3 指標指向的空間釋放
- 3.3 如何規避野指標
- 四、指標運算
- 4.1 指標加減整數
- 4.2 指標減指標
- 4.3 指標的關系運算
- 五、指標和陣列
- 六、二級指標
一、指標三連問
1.1 什么是指標?
在計算機科學中,指標(Pointer)是編程語言中的一個物件,利用地址,它的值直接指向(points to)存在電腦存盤器中另一個地方的值,由于通過地址能找到所需的變數單元,可以說,地址指向該變數單元,因此,將地址形象化的稱為“指標”,意思是通過它能找到以它為地址的記憶體單元,
1.2 為什么使用指標?
提高查找效率
總結:指標是地址,指標變數是一個變數,用來存放記憶體單元的地址,通過指標能找到以它為地址的記憶體單元,
1.3 指標怎么用?
舉個栗子:
#include <stdio.h>
int main()
{
int a = 10;//在記憶體中開辟一塊空間
int *p = &a;//這里我們對變數a,取出它的地址,可以使用&運算子,
//將a的地址存放在p變數中,p就是一個之指標變數,
return 0;
}
這里需要知道計算機當中是如何編址的?
對于32位的機器,假設有32根地址線,那么假設每根地址線在尋址的是產生一個電信號正電/負電(1或
者0)
那么32根地址線產生的地址就會是:
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000001
…
11111111 11111111 11111111 11111111
這里就有2的32次方個地址,
每個地址標識一個位元組,那我們就可以得出:
2
32
B
y
t
e
=
2
32
/
1024
K
B
=
2
32
/
1024
/
1024
M
B
=
2
32
/
1024
/
1024
/
1024
G
B
=
4
G
B
\begin{aligned} 2^{32}Byte \\ &=2^{32}/1024KB \\ &=2^{32}/1024/1024MB \\ &=2^{32}/1024/1024/1024GB\\ &=4GB \end{aligned}
232Byte?=232/1024KB=232/1024/1024MB=232/1024/1024/1024GB=4GB?
即4G的空閑進行編址,
同樣的方法,64位機器,如果給64根地址線,就可以得出:
2
64
B
y
t
e
=
2
64
/
1024
K
B
=
2
64
/
1024
/
1024
M
B
=
2
64
/
1024
/
1024
/
1024
G
B
=
8
G
B
\begin{aligned} 2^{64}Byte \\ &=2^{64}/1024KB \\ &=2^{64}/1024/1024MB \\ &=2^{64}/1024/1024/1024GB\\ &=8GB \end{aligned}
264Byte?=264/1024KB=264/1024/1024MB=264/1024/1024/1024GB=8GB?
即8G的空閑進行編址,
這里我們就明白:
在32位的機器上,地址是32個0或者1組成二進制序列,那地址就得用4個位元組的空間來存盤,所以一個指標變數的大小就應該是4個位元組,
那如果在64位機器上,如果有64個地址線,那一個指標變數的大小是8個位元組,才能存放一個地址,
總結:
指標是用來存放地址的,地址是唯一標示一塊地址空間的,
指標的大小在32位平臺是4個位元組,在64位平臺是8個位元組,
二、指標和指標的型別
2.1 指標型別
char *pc = NULL;
int *pi = NULL;
short *ps = NULL;
long *pl = NULL;
float *pf = NULL;
double *pd = NULL;
指標的定義方式:type + *
char* 型別的指標是為了存放 char 型別變數的地址, short* 型別的指標是為了存放 short 型別變數的地址, int* 型別的指標是為了存放int 型別變數的地址,
舉個栗子來理解指標型別的定義
#include<stdio.h>
int main()
{
int n = 10;
char *pc = (char *)&n;
int *pi = &n;
printf("%p\n", &n);
printf("%p\n", pc);
printf("%p\n", pc+1);
printf("%p\n", pc-1);
printf("%p\n", pi);
printf("%p\n", pi+1);
printf("%p\n", pi-1);
return 0;
}
結果

可以看到在32位作業系統下指標變數是4個位元組,64位作業系統下指標變數是8個位元組,
總結:對指標加1其實是加上指標所指向型別的大小,指標的型別決定了指標向前或者向后走一步有多大(距離),
2.2 指標的解參考
#include<stdio.h>
int main()
{
//2.2指標解參考
int n = 0x11223344;
char *pc = (char *)&n;
int *pi = &n;
*pc = 0;
*pi = 0;
return 0;
}



從除錯的結果圖中可以看出,當指標變數型別為char型別時,對指標解參考只能操作一個位元組,而當指標變數型別為int型別時,對指標解參考可以一次操作四個位元組,
總結:
指標的型別決定了對指標解參考的時候有多大的權限,即能操作幾個位元組,
三、野指標
3.1 概念
野指標就是指標指向的位置是不可知的(隨機的、不正確的、沒有明確限制的)
3.2 野指標成因
3.2.1 指標未初始化
#include <stdio.h>
int main()
{
int *p;//區域變數指標未初始化,默認為隨機值
*p = 20;
return 0;
}
3.2.2 指標越界訪問
#include <stdio.h>
int main()
{
int arr[10] = {0};
int *p = arr;
int i = 0;
for(i=0; i<=11; i++)
{
//當指標指向的范圍超出陣列arr的范圍時,p就是野指標
*(p++) = i;
}
return 0;
}
3.2.3 指標指向的空間釋放
可以看以下博客的第三部分
05-C語言進階——動態記憶體管理
3.3 如何規避野指標
- 指標初始化
- 小心指標越界
- 指標指向空間釋放即置NULL
- 指標使用之前檢查有效性
四、指標運算
4.1 指標加減整數
#define N_VALUES 5
float values[N_VALUES];
float *vp;
//指標+-整數;指標的關系運算
for (vp = &values[0]; vp < &values[N_VALUES];)
{
*vp++ = 0;
}
對指標加1其實是加上指標所指向型別的大小,指標的型別決定了指標向前或者向后走一步有多大(距離),
標準規定:
允許指向陣列元素的指標與指向陣列最后一個元素后面的那個記憶體位置的指標比較,但是不允許與指向第一個元素之前的那個記憶體位置的指標進行比較,
4.2 指標減指標
int my_strlen(char *s)
{
char *p = s;
while(*p != '\0' )
p++;
return p-s;
}

總結
兩個指標相減,代表兩個指標經歷的元素個數,
- 元素型別由指標表明
- 兩個指標必須指向同一塊記憶體才有意義(通常是同一陣列、字串)
4.3 指標的關系運算
for(vp = &values[N_VALUES-1]; vp >= &values[0];vp--)
{
*vp = 0;
}
指標可以進行大小比較,通常要教教的指標需要指向同一塊記憶體(同一陣列,字串),
標準規定:
允許指向陣列元素的指標與指向陣列最后一個元素后面的那個記憶體位置的指標比較,但是不允許與指向第一個元素之前的那個記憶體位置的指標進行比較,
實際在絕大部分的編譯器上是可以順利完成任務的,然而我們還是應該避免這樣寫,因為標準并不保證
它可行,
五、指標和陣列
首先明確指標和陣列沒有任何關系,下面舉個栗子
#include <stdio.h>
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,0};
printf("%p\n", arr);
printf("%p\n", &arr[0]);
return 0;
}

由上圖可以看出,陣列名和陣列首元素的地址是一樣的
總結:
陣列名表示的是陣列首元素的地址
我們可以使用指標訪問陣列,舉個栗子
#include<stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };
printf("%p\n", arr);
printf("%p\n", &arr[0]);
int *p = arr; //指標變數p存放的陣列首元素的地址
int arrSize = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < arrSize; i++)
{
printf("%d ", p[i]);
printf("%d ", *(p+i));
printf("%d ", arr[i]);
printf("%d \n", *(arr+i));
}
return 0;
}

由結果可以看出我們p+i其實計算的就是陣列arr下表為i的地址
六、二級指標
指標變數是變數,那么是變數就會有地址,二級指標就是用來存放指標變數地址的,
通過一個圖可以理解

a的地址存放在pa中,pa的地址存放在ppa中
pa是一級指標,ppa是二級指標
對于二級指標運算
int a = 10;
int *pa = &a;
printf("%d\n", *pa);
int **ppa = &pa;
int b = 20;
*ppa = &b; //等價于pa=&b
printf("%d\n", *pa);
**ppa = 30; // 等價于*pa=30 等價于b=30
printf("%d\n", *pa);
printf("%d\n", b);
結果

這里對**ppa的操作有兩步
- 第一個解參考*ppa,找到的是pa的地址,因此將b的地址賦值給pa
- 第二個解參考**ppa,首先通過*ppa找到pa,然后對pa進行解參考操作:*pa,找到的就是b
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/236589.html
標籤:其他
上一篇:菜鳥說有線網路連接故障
下一篇:圖論相關概念及術語總結
