初識指標

宣哲發表於2021-11-24

初識指標

一、什麼是指標?

在瞭解指標之前先要先弄清楚地址的概念。

如果在程式中定義了一個變數,在對程式進行編譯時,系統就會給這個變數分配記憶體單元。編譯系統根據程式中定義的變數型別,分配一定長度的空間。

例如:整型變數分配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位元組

相關文章