1. 程式人生 > >面試題-指標的概念

面試題-指標的概念

問題:

問:什麼是指標?

答:指標是用來儲存記憶體地址的變數,它指向單個物件的地址,除了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變數前面的一塊未知記憶體,非法。