首頁 > 軟體

C/C++指標介紹與使用詳解

2022-08-26 18:04:04

什麼是指標

C/C++語言擁有在程式執行時獲得變數的地址和操作地址的能力,這種用來操作地址的特殊型別變數被稱作指標。

翻譯翻譯什麼tmd叫tmd指標!

變數或常數的指標儲存的資料是 :對應的變數或常數在記憶體中的地址。

圖解:

此時 我們定義三個指標 p1, p2, p3 分別指向a, b, c ,那麼p1中儲存的資料是變數a所佔用記憶體的首地址:0x00;

b和c中儲存的資料是什麼呢? 沒錯,就是0x02和0x04。

顯然。若要知道變數a的值,首先讀取指標p1中的資料0x00,然後讀取記憶體0x00和0x01中的資料就可以了。這個時候,會出現一個問題:怎麼才能確定究竟要讀取幾個單位記憶體中的資料呢?畢竟p1中只儲存了0x00呀。這個時候 ,指標的型別就發揮了作用。舉個例子:如果定義的指標是int型別的,那麼讀取的時候自動從指標中儲存的初值向後讀取4個位元組;float型別的指標就是讀取8個位元組。這樣就可以既完整又不多餘的取出所需要的資料了。

總結一下一個指標的兩個要素:指標型別和指標所指變數的初地址。

定義指標變數

指標在定義的時候最好直接初始化,否則可能出現意想不到的結果。

@定義一個指向變數的指標。

/*定義一個指向int型別變數a的指標p*/
int a = 3;
int * p;	
p = &a;	//把a的地址賦值給p;
/*下面的語句最好不要用!!!!*/
p = &28;	//這也是可以的,p指向的地址中儲存的資料是28.
/*可以用下面的語句代替上面的語句*/
*p = 28;

間接參照指標

間接參照操作符也是 *

*p 取出p指向的記憶體空間中的值。

所以區分定義或是參照指標可能有些麻煩。

只有同型別的指標和變數才能通過 * 和 & 互相建立關係。

int a = 0;
int temp;
int * p = &a;
/*指標的間接參照*/
cout<< *p;	//輸出結果是0
/*以下兩種表達等價*/
*p = 3;	//把3賦值給a
a = 3;
/*以下兩種表達效果相同。都是把變數a賦值給temp*/
temp = a;
temp = *p;	//temp被賦值為0
/* 以下表達是錯誤的*/
float f = 3.1;
int * p = &f;	//error,指標型別與變數型別不匹配 

常or常常

這個部分本來應該在定義指標變數裡,但是因為需要指標的間接參照作為鋪墊,所以把它單獨拿出來了

我們先區分一組概念:常數、指向常數的指標、常指標以及指向常數的常指標。

1.常數:顧名思義不發生改變的量,想必大家是熟悉的。

2.指向常數的指標:只限制間接存取操作,不限制指標指向的值本身的操作規範。

3.常指標:指標中儲存的地址一經初始化就不能改變了,也就是說常指標只能指向一個固定的地址,但是地址中儲存的資料是可以改變的哦~

4.指向常數的常指標:根據上面三個概念大家應該可以理解了,就是指標中儲存的地址和該地址中的資料皆不可更改。

例如:

int b = 4;
const int a = 5;	//定義一個常數a。
/*注意觀察以下三個定義中const的位置*/
const int *p = &a;	//定義一個指向常數的指標p,指向常數a。
p = &b;	//這個也是沒問題的哦
*p = 6;	//error,這個間接存取操作是不可以。 
int * const p2 = &b;//定義一個常指標p2
*p2 = 6;	//這個是可以的,注意區分和上面的區別
const int * const p3 = &a;	//指向常數的常指標p3
/* emm我也不知道該註釋點什麼,自行體會吧~*/
*p = 11;	//error,因為p指向的是常數,常數的值不可更改
*p2 = 2;	//true,p2是常指標,指向的地址不變,但地址中的值可以更改
*p3 = 4;	//error
p3 = &b;	//error

指向指標的指標

指標本質上也是一個變數或常數,那麼指標也是有地址的,而指向這些地址的指標被稱為指向指標的指標。

int a = 25;
int * p  = &a;
int pp = &p;	//true,pp指向的地址中儲存的是指標p的地址。 

指標與陣列

一個陣列的陣列名就是一個常指標。

int arr[] = {5,4,6,9,8,3};

arr就是一個指標,而且指向陣列的第一個元素arr[0]。

指標陣列:

char * arr[] ={"this is", "a", "C++ !"}; 

在此提及一下字串常數:

char * a 
/*
雙引號的作用:
	在字串結尾加一個,並分配記憶體空間,返回首地址。
*/
a = "dshfw";	

指標的運算

指標只能支援 + 和 - 的運算,但這已經足夠滿足大多數指標操作的需求了。

/*接下來以陣列為例,只介紹加法 ,減法同理*/
int arr[] = {5,4,6,9,8,3};
cout<< *p;	//輸出結果為5
cout<< *(p+1);	//輸出結果為4
/*列印整個陣列*/
for(int *p = arr; p < arr+5; ++p)
{
	cout<< *p<<' ';
}
cout<<endl;

堆記憶體分配

C語言

/*函數原型*/
void * malloc(size_t size);
/*使用:開闢5個int型別變數的儲存空間,返回首地址*/
/**/
int *arr;
if(arr = (int *) malloc(5 *sizeof(int)) == NULL)
{
	exit(1);
}
/*釋放堆記憶體*/
free(arr);

C++語言

注意釋放陣列記憶體空間時,delete後有[] !!!

/*申請一個5個元素的陣列空間*/
int * arr = new int[5];
delete[] arr;
/*申請一個變數的空間*/
int * arr = new int;
delete arr;

指標與函數

函數名和陣列名一樣都是一個指標,有時我們需要把函數名作為引數傳入其他函數中。

陣列名作為函數的入口引數

arr[] = {4,6,9,8,5,3,2,7,5};
/*兩種不同的寫法均可以*/
void Sort_Shell(int arr[], int n)
{
/*code*/
}
void Sort_Shell(int * arr, int n)
{
/*code*/
}
/*下面這種是不可以的!!!*/
void Sort_Shell(int * arr[], int n)
{
/*code*/
}

舉個小小的例子

/*來個小小的希爾排序演演算法*/
void Sort_Shell(int arr[], int n)
{
	int gap = n / 2;
	for(; gap > 0; gap /= 2)
	{
		for(int i = gap; i <n; ++i)
		{
			int temp = a[i];
			int j = i;
			while(j >= gap&& temp < arr[j -  gap])
			{
				a[j] = a[j - gap];
				j -=gap;
			}
			a[j] = temp;
		}
	}
}

開了個小差,接下來回歸正題,我們的指標。

函數名作為引數傳入其他函數

static bool cmp(int a, int b)
{
	return a < b;
}
void show(bool * b)
{
	if( &b)
	{
		cout<< true;
	}
	else
	{
		cout<<false;
	}
}

使用指標修改函數引數

首先來看個例子:

void swip(int a, int b)
{
	int c = a;
	a = b;
	b = c;	
}
int main()
{
	int a = 5, b = 6;
	swip(a, b);
	cout<<a<<' '<<b;
}

輸出結果:5 6

並未達到交換的效果,因為函數內部對形參的修改並不能反映到上層的main函數中。

此時我們可以通過指標作為函數的入口引數來實現預期的功能。

void swip(int * a, int* b)
{
	int c = *a;
	*a = *b;
	*b = c;	
}
int main()
{
	int a = 5, b = 6;
	swip(&a, &b);
	cout<<a<<' '<<b;
}

輸出結果:6 5

傳遞函數的指標雖然能達到預期效果,但是確實以破壞函數的黑盒為代價,可讀性差,偵錯困難。

有沒有什麼更好的辦法呢?接下來 參照登場了。

變數的參照作為函數的引數

void swip(int &a, int &b)
{
	int c = a;
	a = b;
	b = c;	
}
int main()
{
	int a = 5, b = 6;
	swip(a, b);
	cout<<a<<' '<<b;
}

輸出結果:6 5

克服了指標作為引數的弊端。話又有點多了,哈哈,這和指標有什麼關係呢······

兩個常用的字串函數

  • strcmp() :用於比較字串的大小。
  • strcpy() :複製字串。
//函數原型
int strcmp(const char * arr1, const char * arr2);
//使用舉例:
char arr1[] = "dfetf";
char arr2[] = "cfefef";
int b = strcmp(arr1, arr2);

輸出b的值是大於0 的。

總結

指標強大而又危險,卻也是C和C++的靈魂,由於其可以直接操作記憶體地址的特殊性,使得理解指標是如何工作的在C和C++中必不可少,若想成為一名優秀的C++工作者,必須要掌握指標。

到此這篇關於C/C++指標介紹與使用詳解的文章就介紹到這了,更多相關C++指標內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com