初識指針
一、什麼是指針?
在了解指針之前先要先弄清楚位址的概念。
如果在程式中定義了一個變量,在對程式進行編譯時,系統就會給這個變量配置設定記憶體單元。編譯系統根據程式中定義的變量類型,配置設定一定長度的空間。
例如:整型變量配置設定4個位元組,字元型配置設定1個位元組,單精度配置設定4個位元組等。記憶體區的每一個位元組有一個編号,這就是“位址編号”,它就相當于旅館中的房間号,每一個房間都可以看作一塊記憶體區域,都可以用來存放東西,我們給每個房間都編一個房間門牌号,用于更好的區分每一個房間,記憶體中也是一樣的,整個記憶體由很多個位元組組成,每個位元組都有其對應的“房間号”,這就是“位址”了。通過這個“房間号”就可以找到其對應的“房間”,然後就可以從房間裡取東西,或者把東西放進房間裡了。
了解了位址的概念之後,那所謂的指針,就是記憶體位址,也就是位址的編号,可以把“指針指向位址”了解成“用小本本把房間号記下來”,那這個小本本就相當于一個用于記房間号的指針了,一個變量的位址稱為此變量的“指針”。
二、指針常量與指針變量
1、指針常量
之前有了解過不同資料類型的變量所占記憶體位元組數的這個概念,那麼系統在編譯時給一個變量配置設定的記憶體位址就稱為此變量的“指針”,這個指針的指向是無法改變的,是以又稱為指針常量,數組的位址也是指針常量(也稱為位址常量)。
int a = 10;
//&a = 10000; //&a取變量a的位址,是一個位址常量,不能夠改變它的位置
scanf("%d",&a); //輸入222
printf("a=%d\t &a=%p/n",a,&a); //輸出位址

2、指針變量
(1)指針變量的概念
如果有一個變量專門用來存放另一個變量的位址,則稱這個變量為“指針變量”,也就是說C語言中有一類變量是專門用來存儲(指向)位址的,我們将它稱為“指針變量”,指針變量的中存儲的位址可以被改變,也就是可以改變指針變量的指向,就好比一張紙或一個小本本,寫着一個房間的房間号,那把這個房間的房間号擦掉,寫上另一個房間的房間号也是可以的,這就是指針變量和指針常量最大的差別所在了,可以改變指針變量的指向。
//定義指針變量格式:資料類型 *變量名;
int* p;
(2)指針變量的定義
定義指針變量的一般格式:
類型名* 指針變量名;
int a= 10;
int* p; //定義了一個整型指針變量p,可以用于指向整型資料的位址(裡面儲存的是整型變量的位址)
p = &a; //将整型變量a的位址指派給整型指針變量p,整型指針p指向了整型變量a的位址。
int*p,*q;
char* p1,*q1;
double *p2,*q2;
/* 注意:左端的int、char等是在定義指針變量時必須指定的“基類型”。指針變量的基類型用來規定此指針變量可以指向的變量的類型。如:上面定義的*p和*q隻能用于指向int整型變量的位址,p2和q2隻能用于指向double雙精度類型變量的位址。 */
char *q;
int *p;
printf("%d %d\n",sizeof(p),sizeof(q)); //都輸出為4,指針變量所占記憶體大小一般是占4個位元組
(3) 指針變量的引用:
int* p; //定義了一個整型指針變量p,這裡的'*'是指針變量定義符
*p; //*p解引用,這裡'*'是解引用符号
int a=10;
int *p;
p = &a;
printf("*&a=%d"); //對a的位址進行解引用,輸出為10,。
printf("&p=%p "); //輸出為指針變量p的位址(p自己的位址,不是存儲其他變量位址的位址)
與指針和位址相關運算符:’*’(指針運算符)和’&’(取位址運算符) //差別對待位運算符&
//例如:int a,*p; p=&a; *p=10;
//在引用指針變量時,有以下幾種情況:
//1、給指針變量指派
如:int a = 10,b=20;
int *p=&a;
//定義一個整型指針變量p,初始化p的值為a的位址,也就是p指向a位址
/*解引用:*/
*p=30; //通過指針變量p引用a變量,改變a的值為30
//這裡的’*’為解引用符号,*p引用指針變量p所指向位址中對應的值
scanf(“%d”,p); //scanf通過指針變量p給變量a指派
printf(“%d\n”,*p); //通過指針變量p輸出變量a的值
*p=b; //将b的值放入指針變量p所指向的記憶體位址中(a的位址單元中)
p=&b; //改變指針p的指向,指針p不再指向a的位址了,而是指向b的位址
printf(“%d\n”,*p); //輸出變量b的值
//輸出記憶體位址編号
printf(“%p\n”,p); //以十六進制的格式輸出指針變量p所指向位址的記憶體位址編号
printf(“%d\n”,&a); //以十進制的格式輸出變量a所在的記憶體位址編号
printf(“%o\n”,&b); //以八進制的格式輸出變量b所在的記憶體位址編号
printf(“%p\n”,&p); //以十六進制的格式輸出指針變量p所在的記憶體位址編号
三、指針變量作為函數參數
函數的參數不僅可以是整型、浮點型、字元型的資料,還可以是指針類型。它的作用是将一個變量的位址傳遞到另一個函數中。
1、函數參數為指針類型的函數:
//1、函數參數為指針類型的函數:
void fun1(int x,int y)
{//這裡定義了一個普通函數fun1
printf(“x=%d\ty=%d\n”,x++,y++);
}
void fun2(int *x,int *y)
{//這裡定義了一個形參為整型指針類型函數fun2,其形參為指針類型的變量
printf(“x=%d\ty=%d\n”,(*x)++,(*y)++); //注意*和++的優先級,++的優先級高
//注意:和printf(“x=%d\ty=%d\n”,x++,y++);的差別,也就是沒有*和有*的差別
//沒有*就是指針的偏移,指針本身移動
}
int main()
{
int a=10,b=20,*p,*q;
fun2(&a,&b); //這裡調用函數fun時,所傳遞的實參必須是位址
printf(“a=%d\tb=%d\n”,a,b); //輸出的a和b的值為11,21
p=&a; //使用整型指針變量p指向整型變量a的位址
q=&b; //使用整型指針變量q指向整型變量b的位址
fun2(p,q); //這裡使用指針變量p和q作為實參傳遞
printf(“*p=%d\t*q=%d\n”,*p,*q);
return 0;
}
2、指針函數
//傳回值為指針類型的函數稱為“指針函數”:
int *fun3(int *x) //這是一個指針函數,傳回值類型為整型int指針類型
{//int* x = &a;
++*x;
return x; //傳回指針變量x所指向的記憶體位址
}
//調用
int a=10;
int* p;
p=fun3(&a);
printf("a=%d\t"); //輸出11;
int *fun4()
{
int a=10; //局部變量:出了作用域,記憶體揮被釋放
//如果加static,出了作用域,其記憶體不會被釋放,但是隻能在作用域範圍内使用
return &a; //傳回a記憶體位址
//注意:不允許傳回局部變量的位址
}
int* p;
p=fun4(); //p=&a;使用了非法空間
四、通過指針引用數組
1、數組元素的指針
數組元素的位址表示:
如:int a[10] = {0,1,2,3,4,5,6,7,8,9},*p;
&a[0]; //引用數組元素a[0]位址的表示方法
2、指針指向數組元素
p=&a[1]; //指針變量p指向數組元素a[1]的位址
3、指針指向的移動(指針的偏移)
int a[10] = {0,1,2,3,4,5,6,7,8,9},*p;
p=&a[0];
++*p; //指針指向位址中的數值加1
printf(“%#p\n”,p); //列印指針變量p所指向的位址編号
p++; //指針移動到數組元素a[1]的位置
printf(“%#X\n”,p); //列印移動後指針變量p所指向的位址編号
//指針變量++(或--)移動一次是移動其基類型大小的記憶體區域
for(int i=0;i<10;i++)
{
printf(“%d”,*(p+i)); //通過指針移動引用數組元素,輸出數組
//指針本身位置不改變
}
for(int i=0;i<10;i++)
{
printf(“%d”,p[i])); //通過指針帶下标的形式引用數組元素
//[]相當于*解引用
}
for(int i=0;i<10;i++)
{
printf(“%d”,*(a+i)); //通過數組首位址帶下标的形式引用數組元素
//這裡不能使用*a++,數組的首位址是一個位址常量,其指向不能被改變
}
for(int i=0;i<10;i++)
{
printf(“%d”,*p++); //指針本身的偏移(指針指向的改變)
//如果使用指針本身偏移後,再使用*(p++)就指向數組外面未知區域去了
}
4、指針指向字元串
char *p = “abcdefg”; //通過字元指針直接引用字元串
//字元串是一個字元數組,其首位址是位址常量
while (*p)
{
printf("%c\t", *(p++));
}
int* p;
char* str = "abcdefg1234567890";
p = (int*)str; //将str強轉成int*類型
for(int i=0;i<strlen(str);i++)
{
printf(“%d”,*(p+i));
}
//輸出ae26 +亂碼,因為p指針一次移動4個位元組,不是一個1位元組