C語言指針相關面試題

在分析指針的代碼時,腦子裏必定要有一張內存的分配圖,用於分析各個變量的存儲狀況。數組

 

一、用變量a給出下面的定義
a) 一個整型數(An integer)
b)一個指向整型數的指針( A pointer to an integer)
c)一個指向指針的的指針,它指向的指針是指向一個整型數( A pointer to a pointer to an intege)r
d)一個有10個整型數的數組( An array of 10 integers)
e) 一個有10個指針的數組,該指針是指向一個整型數的。(An array of 10 pointers to integers)
f) 一個指向有10個整型數數組的指針( A pointer to an array of 10 integers)
g) 一個指向函數的指針,該函數有一個整型參數並返回一個整型數(A pointer to a function that takes an integer as an argument and returns an integer)
h)  一個有10個指針的數組,該指針指向一個函數,該函數有一個整型參數並返回一個整型數 ( An array of ten pointers to functions that take an integer argument and return an integer )

答案是:
a) int a; // An integer
b) int *a; // A pointer to an integer
c) int **a; // A pointer to a pointer to an integer
d) int a[10]; // An array of 10 integers
e) int *a[10]; // An array of 10 pointers to integers
f) int (*a)[10]; // A pointer to an array of 10 integers
g) int (*a)(int); // A pointer to a function a that takes an integer argument and returns an integer
h) int (*a[10])(int); // An array of 10 pointers to functions that take an integer argument and return an integer函數

備註:spa

「&」和「*」兩個運算符的優先級別相同,但按自右而左方向結合設計

在定義時,*號表示後面的變量的類型是指針變量,例如「int *a;」代表a是指針變量,「int * a[10];」代表a[10]裏面成員爲指針(變量),「int (*a)[10]」代表a爲指針變量(該指針類型爲int ()[10])3d

 

C語言函數返回類型爲指針時的一些問題指針

1.code

#include<stdio.h>
char  *returnStr()
{
           char  *p = 「tigerjibo」;
           return  p;
}
int  main()
{
           char*str;
           str =returnStr();
           //str[0]=’T’;             則會引發錯誤,不能修改只讀數據段中的內容
           printf(「%s\n」,str);
           return0;
}

來分析下該程序。blog

(1)char  *p = 「tigerjibo」。系統在棧上分配四個字節的空間存放p的數值。「tigerjibo」是字符常量,存放在只讀數據段內。指向完後,系統把」tigerjibo」的地址賦值給p。內存

(2)函數用return 把p的數值返回。該數值指向只讀數據段(該數據段內的數據是靜態的不會改變)。退出子函數後,系統把p的數值銷燬。可是p的數值已經經過return 返回。且只讀數據段中的內容不會被修改和回收(其輸於靜態區域)字符串

(3)在主程序中把該地址又給了str。所以str指向了「tigerjbo」。

(4)該程序雖然能運行,擔又一個缺點,就是在程序中不能修改字符經常量中的數值。若是修改會引發段錯誤。

 

2.

#include<stdio.h>
char *returnStr()
{
           char  p[]=」tigerjibo」;
           return  p;
}
int  main()
{
           char  *str;
           str =returStr();
           printf(「%s\n」,str);
}

編譯該程序後,系統會提示以下警告:

function returns  address of local variable

(函數返回一個可變地址)

分析該錯誤:

1>」tigerjibo」是一個字符常量,存放在只讀數據段中,是不能被修改的。

2>char p[],是一個局部變量,當函數被調用時,在棧上開闢一個空間來存放數組P的內容。

3>char p[]=」tigerjibo」,該語句是把」tigerjibo」的值賦值給數值P,存放在數組p地址處。而不是把」tigerjibo」的地址賦值給數組p。所以,「tigerjibo」此時在系統中有一處備份,一個在只讀數據段中(不能修改,內容也不會被回收),一個在棧上存儲(能夠修改起內容,但函數退出後,其棧上存儲的內容也會被回收)。

4>所以,當return p,返回了數組的首地址,可是當函數退出後,其棧上的內容也將被丟棄,局部變量的內存也被清空了,所以該數組首地址處的內容是一個可變的值。

 

3.

#include<stdio.h>
char *returnStr()
{
           static  char p[]=」tigerjibo」;
           return  p;
}
int  main()
{
           char  *str;
           str =returnStr();
           str[0]=’T’;
           printf(「%s\n」,str);
}

此程序運行正確。

分析以下:

1>」tigerjibo」是一個字符常量,存放在只讀數據段中,是不能被修改的。

2>static char p[],是一個靜態局部變量,在讀寫數據段中開闢一個空間給p用來存放其數值。

3>static char p[]=」tigerjibo」,該語句是把」tigerjibo」的值賦值給數值P,存放在數組p地址處。而不是把」tigerjibo」的地址賦值給數組p。所以,「tigerjibo」此時在系統中有一處備份,一個在只讀數據段中(不能修改,內容也不會被回收),一個在讀寫數據段中存儲(能夠修改其內容,當函數退出後,因其在讀寫數據段中存儲,起內容不會被丟棄)。

4>所以,當return p,返回了數組的首地址,可是當函數退出後,雖然棧上的內容都清除了,可是p地址是讀寫數據段中的地址,其上的內容不會被回收。

 

這裏先補充如下知識:

             char day[15] = "abcdefghijklmn"; 這個語句執行的時候,系統就分配了一段長15的內存,並把這段內存起名爲day,裏面的值爲"abcdefghijklmn",以下圖所示:

    

            對於char* strTmp = "opqrstuvwxyz";,這句語句執行後,字符串指針strTmp的內存的圖示以下:

    

4.

#include<stdio.h>
#include<string.h>
#include<strdlib.h>
void getmemory(char *p)
{
        p = (char *)malloc(100);
}
int  main()
{
      char  *str=NULL;
      getmemory(str);
      strcpy(str,」helloworld」);
      printf(「%s\n」,str);
}

編譯後錯誤:段錯誤

分析:在主程序中,str地址爲空。在函數傳遞中將str的地址傳給了子函數中的指針p(是拷貝了一份),而後在字函數中給p在堆上申請了一個100字節的空間,並把首地址賦值給p。可是函數傳遞中,p值改變不會影響到主函數中str的值。所以,str的地址仍爲空。在strcpy中引用空指針會出現段錯誤。

假如str不是初始化爲NULL,而是一個char字符串,在調用p = (char *)malloc(100);以前p的值以下:

 

在調用p = (char *)malloc(100);以後p的值以下:

 

可見,str依舊指向原來的地址

 

5.

void GetMemory2(char **p, int num) {
     *p = (char *)malloc(sizeof(char) * num); 
}   
void Test2(void){
     char *str = NULL;
     GetMemory2(&str, 100);  // 注意參數是 &str,而不是str
     strcpy(str, "hello"); 
     cout<< str << endl;
     free(str);   
} 

----------------------------------&str是指針的地址,將指針的地址傳給形參p,則p也指向str,

因此*p = (char *)malloc(sizeof(char) * num);也就是給p所指向的str分配了內存,因此正確。(在堆中分配的空間具備全局性)

假如str不是初始化爲NULL,而是一個char字符串,在調用p = (char *)malloc(100);以前p的值以下:

 

在調用p = (char *)malloc(100);以後p的值以下:

 

6.

char *GetMemory3(int num) {
     char *p = (char *)malloc(sizeof(char) * num);
     return p; 
}   

void Test3(void) {
     char *str = NULL;
     str = GetMemory3(100);
     strcpy(str, "hello");
     cout<< str << endl;
     free(str);   
} 

----------------------------正確

在「return p」以前:

 

在調用GetMemory以後:

 

 

7.

char *GetString(void) {
     char p[] = "hello world";
     return p;   // 編譯器將提出警告 
}   

void Test4(void) { 
    char *str = NULL; 
    str = GetString();  // str 的內容是垃圾 
    cout<< str << endl; 
} 

不要用return語句返回指向「棧內存」的指針,由於該內存在函數結束時自動消亡;

在「return p」以前:

 

在「return p」以後,棧已經被跟隨子函數的中止而銷燬,因此:

8.

char *GetString2(void) {
     char *p = "hello world";
     return p; 
}   

void Test5(void) {
     char *str = NULL;
     str = GetString2();
     cout<< str << endl; 
} 

函 數Test5運行雖然不會出錯,可是函數GetString2的設計概念倒是錯誤的。由於GetString2內的「hello world」是常量字符串,位於靜態存儲區,它在程序生命期內恆定不變。不管何時調用GetString2,它返回的始終是同一個「只讀」的內存塊。

在「return p」以前:

 

在「return p」以後:

 

9.

void test(void) {  
    char *p = (char *) malloc(100);     
    strcpy(p, 「hello」);    
     free(p);        // p 所指的內存被釋放,可是p所指的地址仍然不變    
if(p != NULL)   // 沒有起到防錯做用     
    {        
        strcpy(p, 「world」);  // 出錯     
    } 
}

在「free(p);」以前:

 

在「free(p);」以後:

 

即雖然「hello」所在的堆的100個空間已經被消除了,可是p的值仍是0x10006000,是個野指針,不能使用。因此建議在free以後,添加如下代碼:

p=NULL;

 

10.

#include <stdio.h>

int main(void)
{
    char *p = "helloworld";

    *p = 'T';

    printf("p=%s\n", p);
    return 0;
}

編譯經過,但運行時「Segmentation fault (core dumped)」

Segmentation fault (core dumped)通常是對內存操做不當形成的,常見的有:

(1)數組超出範圍。

(2)修改了只讀內存。

這裏由於p指向"helloworld",是字符常量,存放在只讀數據段內,不能被修改。若將p指針改成數組,即正確。

相關文章
相關標籤/搜索