日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

C语言——指针(入门详解)

發(fā)布時(shí)間:2024/1/1 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C语言——指针(入门详解) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

  • 1.什么是指針?
    • 1.1.理解指針的兩個(gè)要點(diǎn):
    • 1.2.指針變量:
    • 1.3.內(nèi)存是如何編址?
  • 2.指針和指針類型
    • 2.1指針的創(chuàng)建與初始化
    • 2.2.指針類型
  • 3.野指針
    • 3.1.什么視野指針?
    • 3.2.野指針成因
    • 3.3.規(guī)避野指針
  • 4.指針運(yùn)算
    • 4.1.指針+-整數(shù)
    • 4.2.指針-指針
    • 4.3指針的關(guān)系運(yùn)算
  • 5.指針與數(shù)組
  • 6.二級(jí)指針
    • 6.1.什么是二級(jí)指針
    • 6.2.二級(jí)指針的運(yùn)算
  • 7.指針數(shù)組
  • 總結(jié)

1.什么是指針?

1.1.理解指針的兩個(gè)要點(diǎn):

1.指針是內(nèi)存中最小單元的編號(hào),也就是地址。
2.平時(shí)口語(yǔ)中的指針,通常指的是指針變量,指針變量是用來(lái)存放內(nèi)存地址的變量。
總結(jié):指針其實(shí)就是地址,口語(yǔ)中的指針通常指的是指針變量。


補(bǔ)充:一個(gè)內(nèi)存單元占一個(gè)字節(jié)。

1.2.指針變量:

通過(guò)&取地址操作符取出變量在內(nèi)存中的起始地址,將取出的地址存放在一個(gè)變量中,這個(gè)存放地址的變量就是指針變量。

下面通過(guò)代碼演示指針變量的創(chuàng)建與使用

int main() {int a = 10;int* pa = &a;//創(chuàng)建指針變量并初始化//打印驗(yàn)證printf("%p\n", &a);printf("%p\n", pa);//使用指針變量需要用*解引用操作符*pa = 20;//此時(shí)*pa等價(jià)與aprintf("%d\n", *pa);printf("%d\n", a);return 0; }


補(bǔ)充:

1、a在內(nèi)存中占4個(gè)字節(jié),&a取出的是整型變量a的第一個(gè)字節(jié)的地址(最小的地址)。
2.當(dāng)需要通過(guò)地址訪問(wèn)來(lái)改變變量的值時(shí),需要使用*解引用操作符對(duì)指針變量進(jìn)行解引用操作。

1.3.內(nèi)存是如何編址?

對(duì)于32位的機(jī)器,假設(shè)有32根地址線,那么假設(shè)每根地址線在尋址的時(shí)候產(chǎn)生高電平(高電壓)和低電平(低電壓)就是(1或者0)。

每個(gè)地址標(biāo)識(shí)1個(gè)字節(jié),操作系統(tǒng)就會(huì)分配2的32次方個(gè)字節(jié),也就是4GB的空間進(jìn)行編址。同理可得64位機(jī)器,每個(gè)地址標(biāo)識(shí)2個(gè)字節(jié),操作系統(tǒng)就會(huì)分配2的64次方個(gè)字節(jié),也就是8GB的空間進(jìn)行編址。

32位的機(jī)器上,地址是32個(gè)0或者1組成二進(jìn)制序列,那地址就得用4個(gè)字節(jié)的空間來(lái)存儲(chǔ),所以一個(gè)指針變量的大小就應(yīng)該是4個(gè)字節(jié)。那如果在64位機(jī)器上,如果有64個(gè)地址線,那一個(gè)指針變量的大小是8個(gè)字節(jié),才能存放一個(gè)地址。

總結(jié):

1、指針變量是用來(lái)存放地址的,地址是唯一標(biāo)識(shí)一個(gè)內(nèi)存單元的。
2、在32位平臺(tái)下,地址的大小是4個(gè)字節(jié),指針變量的大小是4個(gè)字節(jié)。在64位平臺(tái)下,地址的大小是8個(gè)字節(jié),指針變量的大小也是8個(gè)字節(jié)。

2.指針和指針類型

2.1指針的創(chuàng)建與初始化

我們都知道變量是分類型的,如整型、單精度浮點(diǎn)型、字符型等。那指針是否也分類型呢?答案是有的。
下面我通過(guò)代碼舉例

int main() {int a = 10;//創(chuàng)建整型指針變量pa并初始化int* pa = &a;//將變量a的地址存放到指針變量pa中return 0; }

上例中,我將變量a的地址存放到指針變量pa中。pa的類型是int*(整形指針)。由此我們可以得到
指針的定義方式是:

type(類型) + * +prt_name(指針變量名字)

其實(shí):
char* 類型的指針是為了存放 char 類型變量的地址。
short* 類型的指針是為了存放 short 類型變量的地址。
int* 類型的指針是為了存放 int 類型變量的地址。

讓我們來(lái)看看第二個(gè)例子

int main() {int a = 10;char* pc = &a;//char*類型的指針能否得存放int類型變量的地址呢?return 0; }

答案是:能夠存放。因?yàn)橐粋€(gè)指針變量在32位環(huán)境下都是占4個(gè)字節(jié)。這里不要門縫里看char*類型指針,把它給看遍了。這也是我們需要注意的一個(gè)小細(xì)節(jié)。

既然指針變量的大小在32位平臺(tái)下都是4個(gè)字節(jié),那指針變量的類型存在的意義是什么呢?

2.2.指針類型

這里我依舊是通過(guò)兩段代碼進(jìn)行舉例

//例一 #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", pi);printf("%p\n", pi + 1);return 0; }


通過(guò)上面的例子我們可以發(fā)現(xiàn),指針的類型決定了指針+1后訪問(wèn)的步長(zhǎng)。int類型指針+1向后移動(dòng)了4個(gè)字節(jié),char類型指針+1向后移動(dòng)了1個(gè)字節(jié)。同理可得short類型指針+1向后移動(dòng)2個(gè)字節(jié),float類型指針+1向后移動(dòng)4個(gè)字節(jié)。

總結(jié)

指針變量的類型決定了指針的步長(zhǎng)(向前或向后走一步的距離)。

//例二int main() {int a = 0x11223344;//0x表示十六進(jìn)制類型char* pc = (char*)&a; //a是整型,需要對(duì)&a進(jìn)行強(qiáng)制類型轉(zhuǎn)換成char*后編譯器才不會(huì)報(bào)錯(cuò)int* pi = &a;*pc = 0; *pi = 0; return 0; }

先調(diào)試這段代碼

讓我們看看pc = 0的效果

接下來(lái)是pi = 0;這句代碼的效果

通過(guò)調(diào)試的內(nèi)存窗口,可以發(fā)現(xiàn)當(dāng)對(duì)char類型指針變量進(jìn)行解引用操作后,訪問(wèn)的權(quán)限是1個(gè)字節(jié),而對(duì)int類型指針變量進(jìn)行解引用訪問(wèn)操作,訪問(wèn)的權(quán)限是4個(gè)字節(jié)。所以指針變量的類型其實(shí)是由意義的。

總結(jié):

指針變量的類型決定了解引用操作后的指針的訪問(wèn)權(quán)限。int類型指針變量解引用操作訪問(wèn)權(quán)限是4個(gè)字節(jié),char類型指針變量解引用操作訪問(wèn)權(quán)限是1個(gè)字節(jié)。

3.野指針

3.1.什么視野指針?

野指針的概念

野指針指的是指向不可知的指針變量(隨機(jī)的、不正確的、不可控的)。

3.2.野指針成因

1.指針變量未進(jìn)行初始化

int main() {int* pa;*pa = 20;return 0; }

上例中,指針變量pa未進(jìn)行初始化,所以pa是一個(gè)野指針,對(duì)pa進(jìn)行僅引用操作是極其危險(xiǎn)的,因?yàn)閜a的指向是不可知的。

指針越界訪問(wèn)

int main() {int arr[5]={1,2,3,4,5};int *p = arr;int i = 0;for(i = 0; i <= 5; i++){*(p++) = i;}return 0; }

當(dāng)運(yùn)行這段代碼后,編譯器會(huì)進(jìn)行報(bào)錯(cuò)

這里編譯器告訴我們因?yàn)橹羔樤L問(wèn)越界,數(shù)組arr被破壞了。所以當(dāng)p超出數(shù)組的合理范圍后,p就是一個(gè)野指針,對(duì)野指針進(jìn)行解引用操作是很危險(xiǎn)的。

3.3.規(guī)避野指針

1.創(chuàng)建指針變量同時(shí)初始化指針變量。
2. 小心指針越界。
3. 指針指向空間釋放,及時(shí)置NULL。
4. 避免返回局部變量的地址。
5. 指針使用之前檢查有效性。

4.指針運(yùn)算

4.1.指針±整數(shù)

代碼舉例如下

#include<stdio.h>int main() {int arr[5] = { 0 };int* pa = arr;int i = 0;//將數(shù)組內(nèi)容賦值成1~5for (i = 0; i < 5; i++){*pa = i + 1;pa = pa + 1;//指針加整數(shù)}//打印數(shù)組內(nèi)容for (i = 0; i < 5; i++){printf("%d ", arr[i]);}return 0; }

4.2.指針-指針

指針-指針的前提條件是,兩個(gè)指針變量指向同一塊空間。

int main() {int arr[10] = { 0 };int* pa = &arr[9];int* pb = &arr[0];//此時(shí)pa和pb都是指向數(shù)組arr的內(nèi)容printf("%d\n",pa - pb);return 0; }

指針-指針得到的絕對(duì)值是,兩個(gè)指針之間相同類型的元素的個(gè)數(shù)。

下面我通過(guò)指針-指針的方式模擬實(shí)現(xiàn)庫(kù)函數(shù)strlen

#include<assert.h>size_t MyStrlen(const char* str) {assert(str != NULL);char* start = str;//記錄初始地址while (*str++){;}//通過(guò)指針-指針?lè)祷刈址L(zhǎng)度return str - start - 1;}int main() {char str[] = "abcde";printf("%d\n",MyStrlen(str));return 0; }

4.3指針的關(guān)系運(yùn)算

#define N_VALUES 5 int main() {float values[N_VALUES];float *vp;// 指針的關(guān)系運(yùn)算for(vp = &values[N_VALUES]; vp > &values[0];){*--vp = 0;}return 0; }


將上邊的代碼稍作修改

#define N_VALUES 5 int main() {float values[N_VALUES];float *vp;// 指針的關(guān)系運(yùn)算for(vp = &values[N_VALUES]; vp > &values[0];vp--){*vp = 0;}return 0; }

代碼修改后,看起來(lái)是更易讀了,可是我們應(yīng)該避免這樣寫(xiě)代碼。雖然上面的代碼在市面上絕大部分編譯器都可以正常運(yùn)行,但是C語(yǔ)言標(biāo)準(zhǔn)中并不能保證它是對(duì)的。

C語(yǔ)言標(biāo)準(zhǔn)規(guī)定:
允許指向數(shù)組元素的指針與指向數(shù)組的最后一個(gè)元素后面那個(gè)內(nèi)存空間的指針作比較,但是不允許與第一個(gè)元素前面那個(gè)內(nèi)存空間的指針進(jìn)行比較。

5.指針與數(shù)組

指針和數(shù)組是不同的對(duì)象。指針是一種用來(lái)存放地址的變量,大小是4/8個(gè)字節(jié)。數(shù)組是一組相同類型元素的集合,可以放多個(gè)元素,大小取決于元素個(gè)數(shù)和元素類型的。數(shù)組的數(shù)組名是數(shù)組首元素的地址,地址是可以存放在指針變量中的。可以通過(guò)指針來(lái)訪問(wèn)數(shù)組。

#include<stdio.h> int main() {int arr[10] = {0};printf("%p\n",arr);printf("%p\n",&arr);return 0; }


由上例可知,數(shù)組名本質(zhì)是首元素的地址(排除&數(shù)組名和sizeof(數(shù)組名)這兩種情況)。既然數(shù)組名是數(shù)組首元素的地址,我們不妨將數(shù)組名存入一個(gè)指針變量中,再通過(guò)這個(gè)指針變量來(lái)遍歷整個(gè)數(shù)組。

#include<stdio.h>int main() {int arr[] = { 1,2,3,4,5,6,7,8,9,0 };int* p = arr; //指針存放數(shù)組首元素的地址int sz = sizeof(arr) / sizeof(arr[0]);int i = 0;for (i = 0; i < sz; i++){printf("&arr[%d] = %p <====> p+%d = %p\n", i, &arr[i], i, p + i);}return 0; }


可以發(fā)現(xiàn)其實(shí) p+i 是完全等價(jià)于 arr[ i ]的。接下來(lái)試試通過(guò)指針運(yùn)算來(lái)便利整形數(shù)組并且打印數(shù)組

int main() {int arr[10] = {0};int* pa = arr;int sz = sizeof(arr)/sizeof(arr[0]);int i = 0; //改變數(shù)組內(nèi)容1~10for(i = 0; i < sz; i++){*pa = i + 1;pa++;}pa = arr;//重新指定指針的位置以避免越界 //打印數(shù)組內(nèi)容for(i = 0; i < sz; i++){printf("%d ",*pa);pa++;}return 0; } int main() {int arr[10] = {0};int* pa = arr;int sz = sizeof(arr)/sizeof(arr[0]);int i = 0; //改變數(shù)組內(nèi)容1~10for(i = 0; i < sz; i++){*(pa+i) = i + 1;}//打印數(shù)組內(nèi)容for(i = 0; i < sz; i++){printf("%d ",*(pa+i));}return 0; }

補(bǔ)充:
[ ]下標(biāo)訪問(wèn)操作符兩邊,arr 和 i 是下標(biāo)訪問(wèn)操作符的兩個(gè)操作數(shù)。[ ]下標(biāo)訪問(wèn)操作符是支持交換律的,所以 arr[ i ] 等價(jià)于 i[arr]。

6.二級(jí)指針

6.1.什么是二級(jí)指針

指針變量是用來(lái)存放地址的,那指針變量的地址該存放到哪里呢?這就要引出二級(jí)指針這個(gè)概念了。二級(jí)指針是用來(lái)存放指針變量的地址的。

int main() {int a = 10;int* pa = &a;int** ppa = &pa;return 0; }

6.2.二級(jí)指針的運(yùn)算

通過(guò) * 解引用操作符對(duì)二級(jí)指針進(jìn)行解引用操作。

int main() {int a = 10;int* pa = &a;int** ppa = &pa;**ppa = 20;//*(*ppa) =*(pa) = a; //通過(guò)對(duì)* *ppa進(jìn)行解引用操作得到pa,再通過(guò)對(duì)pa進(jìn)行解引用操作得到a//**ppa等價(jià)于aprintf("%d\n", a); }

7.指針數(shù)組

指針數(shù)組是什么呢?是數(shù)組?還是指針?答案是:指針數(shù)組是用來(lái)存放指針的數(shù)組。通過(guò)前面的學(xué)習(xí),我們了解到的數(shù)組類型有字符數(shù)組、整型數(shù)組、單精度浮點(diǎn)型數(shù)組等。

int arr[] = {1,2,3,4,5}; char ch[] = {'a', 'b', 'c'};

int* arrp[] = {0x0012ff40, 0x0012ff41, 0x0012ff42};

下面我通過(guò)一個(gè)指針數(shù)組加三個(gè)一維數(shù)組來(lái)模擬實(shí)現(xiàn)二維數(shù)組

#include<stdio.h>int main() {int arr1[3] = { 1,2,3 };int arr2[3] = { 4,5,6 };int arr3[3] = { 7,8,9 };int* arrp[3] = { arr1,arr2,arr3 };int i = 0;int j = 0;for (i = 0; i < 3; i++){for (j = 0; j < 3; j++){printf("%d ",arrp[i][j]);//arr[i]相當(dāng)于是arr[列號(hào)]。通過(guò)指針運(yùn)算,就可以遍歷整個(gè)數(shù)組。}printf("\n");}return 0; }


通過(guò)了訪問(wèn)指針數(shù)組arrp中存放的三個(gè)整形數(shù)組的首元素地址,然后再通過(guò)指針運(yùn)算,就可以模擬實(shí)現(xiàn)一個(gè)二維數(shù)組了。

總結(jié)

總有人說(shuō)指針多難多難,在我看來(lái)只要搞清楚指針的概念以及指針的用法,理解指針也不是特別難的。這只需要我們多去思考和總結(jié)。學(xué)習(xí)沒(méi)有捷徑,只有你真的認(rèn)真學(xué)了才能夠真正的掌握知識(shí)。最后,也希望看完本篇文章的你有所收獲,有什么問(wèn)題也歡迎在評(píng)論區(qū)進(jìn)行討論。

總結(jié)

以上是生活随笔為你收集整理的C语言——指针(入门详解)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。