面試題-指標的概念
問題:
問:什麼是指標?
答:指標是用來儲存記憶體地址的變數,它指向單個物件的地址,除了void指標型別之外,指標的資料型別與所指向地址的變數資料型別須保持一致。不論指標指向的資料型別是哪一種,他本身永遠是整型,儲存的是地址。
分析:
int *ip;
const intt *ip2;
ip和ip2都是指標變數名,int表示該指標變數的型別是整型。*表示指標變數。
-------------------------------------------------------------------------------------------------------------------------------------------
問題:
問:如何初始化指標並對其賦值?
答:指標的初始化就是給指標賦初值,&符號可以用來獲取物件的記憶體地址,並且賦值給指標變數。指標變數的初始化和賦值都可以通過運算子”=“來實現。
分析:
指標可以初始化為0(NULL),,沒有初始化的指標指向是隨機的,它可能導致隨機修改了程式的值。
變數的資料型別和指標變數的資料型別要保持一致。所以以下程式碼是錯誤的:
int a=123;
long *p;
p=&a;
--------------------------------------------------------------------------------------------------------------------------------------------------
問題:
問:是否可以確定指標指向一個物件?
答:指標用於指向物件,一個指標只指向一個物件的記憶體地址。
------------------------------------------------------------------------------------------------------------------------------------------------
問題:
問:指標和迭代器主要的區別?
答:指標和迭代器都是提供其所指物件的間接訪問。區別是:指標用於指向單個物件,而迭代器只用於訪問容器內的元素。
----------------------------------------------------------------------------------------------------------------------------------------------------
問題:
問:運用好指標有哪些優點?
答:
1.提高程式的編譯效率和執行速度。
2.通過指標可使用主調函式和被調函式之間共享變數或資料結構,便於實現雙向資料通訊。
3.可以實現動態的儲存分配。
4.便於表示各種資料結構,編寫高質量的程式。
5.使表示式變得緊湊和簡潔。
-----------------------------------------------------------------------------------------------------------------------------------------------------
問題:
問:使用指標不恰當的會出現哪些問題?舉些例子。
答:
1.訪問陣列和其他資料結構時越界。
2.自動變數消失後被引用。
3.堆上分配的記憶體釋放後被引用。
4.記憶體分配之前解引用。
------------------------------------------------------------------------------------------------------------------------------------------------------
問題:
問:指標是一種特殊的變數,只能用來儲存地址。這句話對麼?
答:對的。
------------------------------------------------------------------------------------------------------------------------------------------------------
問題(慧通面試):
問:一個32位的機器,該機器的指標是多少位?
答:4位。指標變數的位數根據機器地址匯流排位數而定,對於32位地址匯流排的機器指標的位數就是4個位元組。
分析:
系統為指標變數分配一定的記憶體空間,無論指標變數指向何種型別的資料,指標變數的長度一般是一個機器的字長。所以,在32位的機器就是4,但是其他位數的機器就不一定是這個結果了。(注意:分配的記憶體與編譯器有重大的相關,比如在win32環境下編譯,在作業系統64位環境下,仍然是4位元組。)
---------------------------------------------------------------------------------------------------------------------------------------------------
問題(慧通面試):
問:字元指標、浮點數指標、函式指標這三種類型的變數哪個佔用的記憶體最大?為什麼?
答:三者佔用的記憶體一樣大,因為所有指標變數所佔的記憶體單元數量都是相同的。在32位平臺下,三個不同型別的指標佔用的記憶體都是4個位元組。
-----------------------------------------------------------------------------------------------------------------------------------------------------
問題:
問:用變數a給出下面的宣告和定義
a.一個整型數。 答:int a;
b.一個指向整型數的指標。 答:int *a;
c.一個指向指標的指標,它指向的指標是指向一個整型數。 答:int **a;
d.一個有10個整型數的陣列。 答:int a[10];
e.一個有10個指標的陣列,該指標是指向一個整型數的。 答:int *a[10];
f.一個指向有10個整型數陣列的指標。 答:int (*a)[10];
g.一個指向函式的指標,該函式有一個整型引數並返回一個整型數。 答:int (*a)(int);
h.一個有10個指標的陣列,該指標指向一個函式,該函式有一個整型引數並返回一個整型數。 答: int (*a[10])(int);
分析:
分析同下一道面試題。
-------------------------------------------------------------------------------------------------------------------------------------------------------
問題:
問:各種複雜指標的宣告,下面的資料宣告都代表什麼意思?
a.float(**fa)[10]
答:fa是一個二級指標,它指向的是一個一維陣列的指標,陣列的元素都是float型別。
b.double *(*sp)[10]
答:sp是一個指標,它指向一個一維陣列,該陣列元素都是double*。
c.double (*arr[10])()
答:arr是一個數組,arr有10個元素,元素都是函式的指標,指向的函式型別是沒有引數且返回double的函式
d.int *((*a)[10])
答:與“int *(a)[10]”一樣的,a是一維陣列的指標。
e.long (*fun)(int)
答:函式指標。
f. int (*(*f)(int,int))(int)
答:f是一個函式的指標,指向的函式的型別是有兩個int 參並且返回一個函式指標的函式,返回的函式指標指向一個int引數且返回int型別的函式。
分析:
筆者對於指標宣告總結了一下技巧,有重要的兩點:
第一點,用優先順序來分析指標宣告語句,優先順序從高到低為:()>[]>*。第二點,從裡到外分析,比如(*a),a先與*結合,再到().
接下來讓筆者為大家分析一下怎麼看懂多種指標的宣告,比如最難的最後面那個指標宣告:int (*(*f)(int,int))(int)
1.找到變數f,由於*在()裡面,f先與*號結合,然後是(),說明f是一個指標變數。即:(*f)
2.f再與右邊的(int,int)結合,並且(int,int)中有兩個引數,說明f指向一個有兩個int引數的函式,即f是一個函式指標,(*f)(int ,int)。
3.如果覺得太長,難理解,筆者在這裡把(*f)(int ,int)當作一個變數名N,N先與*號結合,然後是外面的(),即(*N)是一個指標(確切地說函式指標N返回型別不是指標型別,通過(*N)之後,這個函式指標的返回型別是指標。 )。
4.(*N)與右邊(int)結合,並且(int)有一個引數,說明(*N)指向有一個int引數的函式,即函式指標的返回型別指標指向一個有一個int引數的函式。
5.由於最左邊是int,則函式指標返回型別指標指向的是返回值為int型且有一個int引數的函式。
其實筆者認為在f點當中也可以這麼說:含有返回兩個int引數的函式指標返回型別指標指向一個int引數且返回int型別的函式。
只是這樣說,易於理解。但是標準的說法是,把整個宣告語句都拆分來講的,比如函式指標也要拆開來說明,新手因為複雜理解比較困難而已。但是沒關係,這並不重要,在程式設計時一般是不會使用這麼複雜的定義的,因為這使程式的可讀性變差,在這裡只是為了學會分析即可。
------------------------------------------------------------------------------------------------------------------------------------------------------
問題:
問:指標指向的變數,那麼請說說指標與數值運算的問題。
答:指標可能會指向意想不到的記憶體地址。
using namespace std;
int main()
{
int a = 100;
int b = 200;
int *p = &a;
p = p - 1;//由於整型變數佔4個位元組,指標應該移動1*4
cout << &a << endl;
cout << &b << endl;
cout << p << endl;//此時指標指向了變數b,也有可能不是
printf("%d\n",&a);
printf("%d\n", &b);
printf("%d\n", p);
//注意,指標與數值進行運算適合運用在在陣列,因為陣列的元素是連續排列的。
//而在這裡,由於編譯器處理記憶體不一樣,可能要指向的地址就不會準確(在記憶體管理機制中,變數之間可能會有空隙空間,所以會留出空隙地址)。
return 0;
}
--------------------------------------------------------------------------------------------------------------------------------------------------
問題:
問:指標與變數的型別不一致時,請問怎麼解決這個問題?
答:由於指標與變數的型別不一致,指標會指向不正確的記憶體地址,需要強制轉換成和指向的物件的資料型別保持一致。
分析:
#include<iostream>
using namespace std;
int main()
{
//當p的型別和a不一樣時
char a[15]= "mygirlislovely";
int *p = (int *)&a;
p++;//由於指標p是整型型別的,它移動4個位元組,指向下一個地址會,指向了字元陣列中的“r”元素
cout << (char)*p << endl;//需要強制轉換char型別可以輸出字元
return 0;
}
-----------------------------------------------------------------------------------------------------------------------------------------------
問題:
問:分析一下,下面中定義的指標,說出指標型別、指標所指向的型別、指標的值和指標本身所佔據的記憶體區?
答:
int a= 4;
int *p= &a;
指標型別:int* 指標所指向的型別:int 指標的值:4
----------
char *p;
指標型別:char* 指標所指向的型別:char
-----------
int **p;
指標型別:int** 指標所指向的型別:int
------------
int (*p)[3];
指標型別:int (*)[3] 指標所指向的型別:int ()[3]
------------
指標本身所佔據的記憶體區:以上指標本身所佔的記憶體大小,在32位程式中,為4個位元組。
分析:
指標型別:把指標宣告語句的指標名字去掉,就是指標型別,例如int *p;指標型別為int*。
指標所指向的型別:把指標宣告語句的指標名字和名字左邊的*號都去掉。例如:int *p;指標所指向的型別是int。
指標的值:指標所指向的變數的值。
------------------------------------------------------------------------------------------------------------------------------------------------
問題:
問:什麼是野指標?
答:“野指標”是在定義指標後沒有對其進行初始化,或者指標指向的記憶體被釋放,而指標沒有被設定為NULL。野指標隨機地指向一個地址,使用這個指標進行操作時,就會更改該記憶體的資料,造成程式資料的破壞,嚴重威脅著程式的安全。
----------------------------------------------------------------------------------------------------------------------------------------------------
問題:
問:什麼是懸浮指標?
答:當所指向的物件被釋放或者收回,但是對該指標沒有做任何的修改,以至於該指標仍舊指向已經回收的記憶體地址,是懸浮指標,也稱作是迷途指標,是造成野指標的一部分,屬於野指標。
分析:
假如在程序A中,釋放了指標所指向的記憶體M,然後作業系統把原來一部分已經釋放掉的記憶體M重新分配給程序B。如果通過程序A中的迷途指標修改記憶體M的資料,由於記憶體M後來已經分配給程序B的,這將會產生無法預料的後果。這種錯誤是易被發現的。
----------------------------------------------------------------------------------------------------------------------------------------------
問題:
問:下面程式碼會編譯通過嗎?
char *tabHeader = "Sound";
*tabHeader = 'L';
printf("%s\n", tabHeader);
答:
//字串字面值作為常量,在vs編譯器的環境下不能修改,出錯。
//在gcc環境下可以修改,即改變的是新的一塊記憶體地址(拷貝一份),原來的常量的值並沒有被改變。但是char前面加上const,編譯也不會通過,
char *tabHeader = "Sound";
*tabHeader = 'L';//tabHeader指向的是常量的地址,不能修改
printf("%s\n", tabHeader);
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------問題:
問+答:請根據以下程式碼講述一下“*p,*p(++),(*p)++,*++p”之間的區別以及含義?
void main()
{
int b[5] = {9, 2, 3, 4, 5 };
int *p = b;
for (int j = 0; j <4; j++)
{
cout <<b[j+1]<< "指標指向的內容:" << *++p << endl;//先p++,後*p
}
p = b;//指標指向恢復原來陣列的首地址,因為上一次迴圈會改變p的地址值
cout <<endl;
for (int i=0;i<5;i++)
{
//*p(++)語法錯誤
cout << b[i]<<"指標指向的內容:" << *p++ << endl;//先*p,後p++
}
p = b;
cout << endl;
//分開執行是因為下面迴圈的*p的內容改變
for (int m = 0; m < 5; m++)
{
cout << "值:" << (*p)++ << endl;//指標所指向的內容加1
}
}
-----------------------------------------------------------------------------------------------------------------------------------------------------------
問題:
問:觀察下面程式碼,說說“pp++”編譯之後,為何沒有輸出結果?
char a[6] = "hello";
char *p = a;
char **pp = &p;
printf("%c\n", **pp);
pp++;
printf("%c\n", **pp);
答:因為pp++之後,pp指向的變數不再是p,指向的是p變數前面的一塊未知記憶體,非法。