目錄
- 一、指標是什么
- 1、記憶體
- 2、記憶體的作用
- 3、記憶體VS外存
- 4、指標
- 5、總結
- 二、指標和指標型別
- 1、指標定義方式和大小
- 2、指標型別的意義
- (1)指標型別決定了對指標解參考能操作幾個位元組
- (2)指標型別決定了指標走一步有多大距離
- 三、野指標
- 1、成因
- (1)指標未初始化
- (2)指標越界訪問
- 四、指標運算
- 1、指標+-整數
- 2、指標-指標
- (1)沒有意義的寫法
- (2)有意義的寫法
- (3)結論
- 3、指標的關系運算
- (1)if (p != NULL)等價于if ( p )
- (2)if (p == NULL)等價于if ( !p )
- 五、指標和陣列
- 1、陣列會隱式轉成指標
- (1)參與運算
- (2)函式呼叫傳參
- 2、指標進行 [ ] 操作
- (1)指標使用[ ]的下標問題
- 六、二級指標
- 七、指標陣列
- 1、區分指標陣列和陣列指標
- (1)指標陣列
- (2)陣列指標
- 八、const 和指標之間的關系
一、指標是什么
想要知道指標是什么?
我們首先要理解一個概念:記憶體 ,
1、記憶體
??可以將記憶體想象成一條長走廊,走廊上有很多房間,每個房間的大小是“一個位元組”(8個位元位),每個房間都有自己的編號,從0開始遞增(通常用16進制表示),這個編號就是記憶體地址,
??記憶體還有一個重要特點:訪問記憶體上任意地址的資料,開銷都很小,

2、記憶體的作用
存盤資料,和CPU進行互動,
3、記憶體VS外存
打開此電腦,右鍵點擊屬性,我們可以看到電腦記憶體的大小,

而平時我們我們看到的1T機械,256G固態……這些都是屬于外存,
1.記憶體存盤空間小,外存存盤空間大,
2.記憶體訪問速度快,外存慢,
3.記憶體價格高,外存價格低,
4.記憶體掉電后沒法保存,外存掉電后還可以保存,
4、指標
了解記憶體之后,我們就可以來理解指標了,
在計算機科學中,指標(Pointer)是編程語言中的一個物件,利用地址,它的值直接指向(points to)存在電腦存盤器中另一個地方的值,由于通過地址能找到所需的變數單元,可以說,地址指向該變數單元,因此,將地址形象化的稱為"指標",意思是通過它能找到以它為地址的記憶體單元,
可以這樣理解:
??我們在長走廊上開了個房間,這時我們會拿到一張房卡,房卡上保存的就是這個房間的地址,通過房卡我們可以找到這個房間,這張房卡也就是指標,其中存放的地址就是指標的內容,
5、總結
指標就是一個變數(變數是分配給你使用的一塊記憶體空間),其中存放的是記憶體單元的地址,
二、指標和指標型別
1、指標定義方式和大小
#include<stdio.h>
int main()
{
char* pc = NULL;
int* pi = NULL;
short* ps = NULL;
long* pl = NULL;
float* pf = NULL;
double* pd = NULL;
}
指標定義的方式是type*+名字,char*,int*,short*……都是不同的型別,統稱為指標,
NULL表示指標的起始地址,
無論是什么型別的指標變數,,它自身所占的空間都是一樣的:
在32位系統是4個位元組,在64位系統是8個位元組,
2、指標型別的意義
(1)指標型別決定了對指標解參考能操作幾個位元組
char a = 'a';
char* pa = &a;

*pa操作:
先根據pa中存放的0x100找到記憶體中對應位置的空間,接下來從這個空間中讀取1個位元組(取決于指標型別char)的資料,
int n = 10;
int* pn = 0x200;

*pn操作:
先根據pn中存放的0x200找到記憶體中對應位置的空間,接下來從0x200開始讀取4個位元組(取決于指標型別int)的資料,
(2)指標型別決定了指標走一步有多大距離
#include<stdio.h>
#include<stdlib.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", pi);
printf("%p\n", pi+1);
system("pause");
return 0;
}
結果:
可以看出char* 型別向前走一步走了1個位元組,int* 型別向前走一步走了4和位元組,
三、野指標
野指標:保存了非法地址的指標,指標指向的位置是不可知的,(空指標也是一種野指標)
1、成因
(1)指標未初始化
#include<stdio.h>
int main()
{
int* p;
*p = 20;
return 0;
}
結果:

(2)指標越界訪問
#include <stdio.h>
int main()
{
int arr[5] = { 9, 5, 2, 7, 10 };
for (int i = 0; i <8 ; i++){
printf("%d ", *(arr + i));
}
system("pause");
return 0;
}
結果:

當指標指向的范圍超過陣列arr的的范圍時,指標就是野指標,
注意:合法地址才能解參考,野指標解參考是未定義行為,
四、指標運算
1、指標±整數
指標±整數:跳過整數個元素,
#include <stdio.h>
int main()
{
int arr[5] = { 9, 5, 2, 7, 10 };
int* pi = &arr[4];
printf("%d ", *(arr + 0));
printf("%d ", *(arr + 1));
printf("%d ", *(pi - 0));
printf("%d ", *(pi - 1));
printf("%d ", *(pi - 2));
system("pause");
return 0;
}
結果:

2、指標-指標
實際上指標相減,大部分情況下沒有意義,
除非兩個指標指向同一個連續的有效記憶體空間才有意義,
(1)沒有意義的寫法
//代碼1
#include <stdio.h>
int main()
{
int arr1[4] = { 1, 2, 3, 4 };
int arr3[1] = { 200 };
int arr2[4] = { 1, 2, 3, 4 };
int* p1 = &arr1[0];
int* p2 = &arr2[2];
printf("%d\n", p2- p1);
system("pause");
return 0;
}
//代碼2:
#include <stdio.h>
int main()
{
int arr3[1] = { 200 };
int arr1[4] = { 1, 2, 3, 4 };
int arr2[4] = { 1, 2, 3, 4 };
int* p1 = &arr1[0];
int* p2 = &arr2[2];
printf("%d\n", p2- p1);
system("pause");
return 0;
}
結果:
代碼1:
代碼2:

此時指標相減的結果是不確定的,取決于變數定義的前后順序,
(2)有意義的寫法
兩個指標指向同一個連續的有效記憶體空間才有意義,
#include <stdio.h>
int main()
{
int arr[4] = { 1, 2, 3, 4 };
int* p1 = &arr[0];
int* p2 = &arr[2];
printf("%d\n", p2- p1);
system("pause");
return 0;
}

(3)結論
指標相減得到的結果是兩個地址之間隔了幾個 “元素” ,
//野指標不能解參考. 以下這倆野指標, 是用來演示運算的
#include <stdio.h>
int main()
{
int* p1 = (int*)0x100;
int* p2 = (int*)0x110;
printf("%d\n", p2- p1);
system("pause");
return 0;
}
結果:

3、指標的關系運算
指標的關系運算有<、>、<=、>=、= =、!=,最常用的是= = 、!=,
指標的比較操作(<、>、<=、>=)要求兩個指標指向同一連續的有效記憶體空間 ,這樣才是有意義的,
(1)if (p != NULL)等價于if ( p )
//代碼1
#include <stdio.h>
int main()
{
int num = 10;
int* p = #
if (p) {
printf("不是空指標\n");
} else {
printf("是空指標!\n");
}
system("pause");
return 0;
}
//代碼2
#include <stdio.h>
int main()
{
int num = 10;
int* p = #
if (p != NULL) {
printf("不是空指標\n");
} else {
printf("是空指標!\n");
}
system("pause");
return 0;
}
結果:
代碼1:
代碼2:

(2)if (p == NULL)等價于if ( !p )
//代碼1
#include <stdio.h>
int main()
{
int num = 10;
int* p = #
if (!p) {
printf("是空指標\n");
} else {
printf("不是空指標!\n");
}
system("pause");
return 0;
}
//代碼2
#include <stdio.h>
int main()
{
int num = 10;
int* p = #
if (p == NULL) {
printf("是空指標\n");
} else {
printf("不是空指標!\n");
}
system("pause");
return 0;
}
結果:
代碼1:
代碼2:

五、指標和陣列
指標和陣列的區別是什么?
當我們看到這個問題的時候,不要上當了, 指標和陣列完全是兩個概念,要說區別那是不合理的 ,
只不過在C語言中,
陣列有時候會隱式轉換成指標,指標可以用[ ]取下標,
1、陣列會隱式轉成指標
(1)參與運算
#include <stdio.h>
int main()
{
int arr[4] = { 0 };
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr + 0));
system("pause");
return 0;
}
結果:

(2)函式呼叫傳參
#include <stdio.h>
void change(int arr){
printf("%d\n", sizeof(arr));
}
int main()
{
int arr[4] = { 0 };
printf("%d\n", sizeof(arr));
change(arr);
system("pause");
return 0;
}
結果:

2、指標進行 [ ] 操作
#include <stdio.h>
int main()
{
int arr[4] = { 1, 2, 3, 4 };
int* p = arr;
for (int i = 0; i < 4; i++) {
printf("%d\n", p[i]);
//p[i]等價于*(p + i)
}
system("pause");
return 0;
}
結果:

(1)指標使用[ ]的下標問題
指標下標可以是負值,
整體的原則就是: 保證解參考操作必須針對有效記憶體進行.,
#include <stdio.h>
int main()
{
int arr[4] = { 1, 2, 3, 4 };
int* p = arr + 1;
//這個操作是允許的,陣列下標一定是 [0, size-1] 范圍
// 但是指標的下標不一定. 取決于指標初始情況下指向誰.
printf("%d\n", p[-1]);
printf("%d\n", *(p - 1));
system("pause");
return 0;
}
結果:

六、二級指標
其實二級指標和套娃類似,
指標也是一個變數,也要占據記憶體,也有地址,
int num =10;
int*p = #
int** pp =&p;

套娃套多了,就會不好理解,所以可以使用一些方法來簡化高級指標,比如typedef,
#include <stdio.h>
int main()
{
int num = 10;
int*p = #
typedef int* IntPtr;
IntPtr* pp = &p;
system("pause");
return 0;
}
七、指標陣列
1、區分指標陣列和陣列指標
(1)指標陣列
陣列,每個元素是一個指標型別的變數,
int* arr[4] = { 0 };
(2)陣列指標
指標,,指向了一個陣列,
int(*p)[4] = &arr;
八、const 和指標之間的關系
1、限制 p 中保存的記憶體地址對應的變數不能被修改
#include <stdio.h>
int main()
{
int num = 0;
int num2 = 10;
const int* p = #
*p = 100;
p = &num2;
system("pause");
return 0;
}

2、限制 p 變數本身保存的地址不能改變
#include <stdio.h>
int main()
{
int num = 0;
int num2 = 10;
int* const p = #
*p = 100;
p = &num2;
system("pause");
return 0;
}

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/208460.html
標籤:其他
上一篇:【秋招總結】渣本Java應屆生如愿以償拿到阿里跟騰訊offer(雙offer面經)
下一篇:飛哥工具---如何實作微信自定義鏈接圖片卡片式分享?微信自定義分享網頁鏈接圖片和文字描述資訊流程(附教程與工具)
