C語言全方位講解指針的使用
接著上次的函數(shù)的基本知識,今天我們來講一講指針
一、指針的概念
1.1、變量和地址
所謂指針,也就是內(nèi)存的地址;所謂指針變量,也就是保存了內(nèi)存地址的變量。
總結(jié):指針就是變量,用指針存放地址(口語中說的指針通常指的是指針變量)
1.2、指針變量和指針的類型
指針變量就是一個變量,它存儲的內(nèi)容是一個指針。在我們定義一個變量的時候,要確定它的類型。在定義指針變量時也是一樣的,必須確定指針類型。int 變量的指針需要用 int 類型的指針存儲,float 變量的指針需要用 float 類型的指針存儲。
指針類型決定了:指針解引用的權(quán)限有多大與指針走一步走多大字節(jié)(步長)
整型指針+1跳過一個整型。字符指針+1跳過一個字符
二、指針變量
2.1、指針變量的定義及使用
(1)指針變量的定義
指針變量的定義形式如:數(shù)據(jù)類型 *指針名;例如:
int* x;//整型指針變量 float* f;//浮點型指針變量 char* ch;//字符型指針變量
指針的變量名分別是:x;f和ch。而int*;float*與char*分別是他們中存儲的數(shù)據(jù)的類型。
(2)指針變量的使用
取地址運算符&:單目運算符&是用來取操作對象的地址。例:&i 為取變量 i 的地址。對于常量表達式、寄存器變量不能取地址(因為它們存儲在存儲器中,沒有地址)。
指針運算符*(解引用運算符 ):與&為逆運算,作用是通過操作對象的地址,獲取存儲的內(nèi)容。例:x = &i,x 為 i 的地址,*x 則為通過 i 的地址,獲取 i 的內(nèi)容。
//聲明了一個普通變量 a int a; //聲明一個指針變量,指向變量 a 的地址 int *pa; //通過取地址符&,獲取 a 的地址,賦值給指針變量 pa = &a; //通過間接尋址符,獲取指針指向的內(nèi)容 printf("%d", *pa);
2.2、指針運算
(1)指針與整數(shù)的加減運算
指針變量的自增自減運算。指針加 1 或減 1 運算,表示指針向前或向后移動一個單元(不同類型的指針,單元長度不同)。
(2)指針減指針
前提是兩個指針指向同一個空間。
指針減指針得到兩個指針間的元素個數(shù)
例: Arr[9]指向9與10中間部分(下標)
三、野指針
3.1、概念:
野指針就是指針指向的為止是不可知的(隨機的,不正確的,沒有明確限制的)
3.2、野指針的成因
(1)指針未初始化
(2)指針越界
如圖:在第十次 訪問時,可以進入到循環(huán),相當于從第10個點向后訪問4個字節(jié),之后的字節(jié)不屬于原數(shù)組,則越界了,則稱為野指針。(只有在超出范圍后,在會發(fā)生崩潰)
//越界訪問 *int arr[10] ={ 0 }; int* p = arr; int i=0; for (i=0; i <= 10; i++)//共執(zhí)行了11次,而arr數(shù)組總共只有10個元素 { *p = i; p++; }
(3)指針指向的空間釋放
int* test()//局部變量 { int a = 10; return &a; } int main() { int *p=test();//返回值是a的地址,而局部變量在引用之后就會銷毀。 *p = 20; return 0; }
3.3、如何規(guī)避野指針
1.指針初始化
2.小心指針越界。
3.指針指向空間釋放即置NULL
4.指針使用之前檢查有效性。
四、字符指針
4.1、字符指針類型
在指針的類型中我們知道有一種指針類型為字符指針 char* ; 一般使用:
int main() { const char* pstr = "hello ";//這里是把一個字符串放到pstr指針變量里了嗎? printf("%s\n", pstr); return 0; }
本質(zhì)是把字符串 hello首字符的地址放到了pstr中。
4.2、例題
int main() { char str1[] = "hello bit."; char str2[] = "hello bit."; const char *str3 = "hello bit."; const char *str4 = "hello bit."; if(str1 ==str2) printf("str1 and str2 are same\n"); else printf("str1 and str2 are not same\n"); if(str3 ==str4) printf("str3 and str4 are same\n"); else printf("str3 and str4 are not same\n"); return 0; }
最終輸出的結(jié)果是
這里str3和str4指向的是一個同一個常量字符串。C/C++會把常量字符串存儲到單獨的一個內(nèi)存區(qū)域。當幾個指針指向同一個字符串的時候,他們實際會指向同一塊內(nèi)存。 但是用相同的常量字符串去初始化不同的數(shù)組的時候就會開辟出不同的內(nèi)存塊。所以str1和str2不同,str3和str4不同。
五、指針與數(shù)組
之前我們可以通過下標訪問數(shù)組元素,學習了指針之后,我們可以通過指針訪問數(shù)組的元素。在數(shù)組中,數(shù)組名即為該數(shù)組的首地址,結(jié)合上面指針和整數(shù)的加減,我們就可以實現(xiàn)指針訪問數(shù)組元素。
5.1、指針與二維數(shù)組
(1)二維數(shù)組的地址
int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}}; int *p=a[0];//此處的p內(nèi)存放的數(shù)組a第一行的地址。
5.2、多級指針
(1)多級指針(指向指針的指針)
指針變量作為一個變量也有自己的存儲地址,而指向指針變量的存儲地址就被稱為指針的指針,即二級指針。依次疊加,就形成了多級指針。
指針變量也是一種變量,也會占用存儲空間,也可以使用 &獲取它的地址。C語言不限制指針的級數(shù),每增加一級指針,在定義指針變量時就得增加一個星號 *。p1 是一級指針,指向普通類型的數(shù)據(jù),定義時有一個 *;p2 是二級指針,指向一級指針 p1,定義時有兩個*。例:假設有一個 int 類型的變量 a,p1是指向 a 的指針變量,p2 又是指向 p1 的指針變量,它們的關系如下圖所示:
六、指針數(shù)組
1.parr的第一個數(shù)組里放arr1的首元素地址
2.parr每個元素的類型是int*。
3.該數(shù)組里每個元素都是指針,所以它是一個指針數(shù)組
4.Parr[i][j],也可以寫成parr[i]+j,
5.相當于地址+j為向后挨個元素指向
七、數(shù)組指針
7.1、數(shù)組指針的定義
如以下語句:
int (*p)[10]; //解釋:p先和*結(jié)合,說明p是一個指針變量,然后指著指向的是一個大小為10個整型的數(shù)組。 //所以p是一個指針,指向一個數(shù)組,叫數(shù)組指針。 //這里要注意:[]的優(yōu)先級要高于*號的,所以必須加上()來保證p先和*結(jié)合。
7.2、&數(shù)組名與數(shù)組名
讓我們看一段代碼
#include <stdio.h> int main() { int arr[10] = { 0 }; printf("arr = %p\n", arr); printf("&arr= %p\n", &arr); printf("arr+1 = %p\n", arr+1); printf("&arr+1= %p\n", &arr+1); return 0; }
運行結(jié)果如下
根據(jù)上面的代碼我們發(fā)現(xiàn),其實&arr和arr,雖然值是一樣的,但是意義應該不一樣的。
實際上: &arr 表示的是數(shù)組的地址,而不是數(shù)組首元素的地址。(細細體會一下)
本例中 &arr 的類型是: int(*)[10] ,是一種數(shù)組指針類型。
數(shù)組的地址+1,跳過整個數(shù)組的大小。
7.3、數(shù)組指針的使用
#include <stdio.h> void print_arr1(int arr[3][5], int row, int col)//形參用數(shù)組來接受 { int i = 0; for(i=0; i<row; i++) { for(j=0; j<col; j++) { printf("%d ", arr[i][j]); }}} void print_arr2(int (*arr)[5], int row, int col)//形參用數(shù)組指針來接受 { int i = 0; for(i=0; i<row; i++) { for(j=0; j<col; j++) {printf("%d ", arr[i][j]);} printf("\n");}} int main() { int arr[3][5] = {1,2,3,4,5,6,7,8,9,10}; print_arr1(arr, 3, 5); //數(shù)組名arr,表示首元素的地址 //但是二維數(shù)組的首元素是二維數(shù)組的第一行 //所以這里傳遞的arr,其實相當于第一行的地址,是一維數(shù)組的地址 //可以數(shù)組指針來接收 print_arr2(arr, 3, 5); return 0; }
八、指針與函數(shù)
8.1、函數(shù)指針的定義
returnType (*pointerName)(param list);
其中,returnType 為函數(shù)返回值類型,pointerNmae 為指針名稱,param list 為函數(shù)參數(shù)列表。參數(shù)列表中可以同時給出參數(shù)的類型和名稱,也可以只給出參數(shù)的類型,省略參數(shù)的名稱,這一點和函數(shù)原型非常類似。 注意( )的優(yōu)先級高于*,第一個括號不能省略,如果寫作returnType *pointerName(param list);就成了函數(shù)原型,它表明函數(shù)的返回值類型為returnType *。
8.2、指向函數(shù)的指針
int (*pf[4])(int,int)={Add,Sub,Mul,Div};
函數(shù)指針數(shù)組,在函數(shù)指針的基礎上,將指針變?yōu)橹羔様?shù)組
總結(jié)
以上就是初階指針的基本內(nèi)容了?。。。》浅8兄x你能看到這里!
如果你覺得你有些想法和我一樣,想和我一起提升自己可以關注私信我,與我一起進步,一起共同努力?。。。?!
到此這篇關于C語言全方位講解指針的使用的文章就介紹到這了,更多相關C語言 指針內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
C++?RBTree紅黑樹的性質(zhì)與實現(xiàn)
紅黑樹是一種二叉搜索樹,但在每個結(jié)點上增加一個存儲位表示結(jié)點的顏色,可以是Red或Black;通過對任何一條從根到葉子的路徑上各個結(jié)點著色方式的限制,紅黑樹確保沒有一條路徑會比其他路徑長出倆倍,因而是平衡的2023-03-03vscode使用cmake時將命令行參數(shù)傳遞給調(diào)試目標的方法
這篇文章主要介紹了vscode使用cmake時將命令行參數(shù)傳遞給調(diào)試目標,下面介紹了一個示例,將參數(shù)first_arg, second-arg和third arg傳遞給程序(此處需要注意,third arg中間雖然存在空格,但是仍然被視作一個參數(shù)),需要的朋友參考下吧2024-03-03C++教程之a(chǎn)rray數(shù)組使用示例詳解
這篇文章主要為大家介紹了C++教程之a(chǎn)rray數(shù)組使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-03-03