天天看點

C++程式員面試指南第5章

面試題1:什麼是引用?引用有什麼作用?

答案:引用就是一個目标變量的别名,對引用的一切操作和對變量的直接操作是一樣的。主要用作函數的參數、

函數傳回值和常引用。

面試題2:簡述為什麼引入常引用,常引用有什麼作用?

答案:常引用的引入主要是為了避免使用變量的引用時,在不知情的情況下改變變量的值。常引用主要用于定義

一個普通變量的隻讀屬性的别名、作為函數的傳入形參,避免實參在調用函數中被以外地改變。

面試題3:流操作符重載為什麼傳回引用?

答案:在程式中,流操作符<<和>>經常連續使用。是以這兩個操作符的傳回值應該是一個仍舊支援這兩個操

作符的流引用。其他的資料類型都無法做到這一點。

面試題4:說明以下聲明的含義

A: int(**p)[10];

B: char*(*p)[10];

C: float(*p[10])();

D: double*((*p)[10]);

E: short(*p)(char);

F: long(*(*p)(int,int)(int)

答案:

A: p為數組指針的指針,數組有10個元素,元素為int型資料。

B: p為數組的指針,數組有10個元素,元素為char*型資料。

C: p為數組,數組有10個元素,元素為函數指針類型,這個函數沒有參數,傳回值為float型資料。

D: p為數組的指針,數組有10個元素,元素為double*型資料。

E: p為函數指針,它所指向的函數有一個char型的參數,傳回值為short型資料。

F: p為函數指針,它所指向的函數有兩個int型的參數,傳回值為函數指針型資料,這個傳回的函數指針指向

的函數有一個int型的參數,傳回值為long型資料。

面試題5:簡述指針常量與常量指針的差別

什麼是指針常量?什麼是常量指針?兩者有什麼差別?

答案:指針常量是定義了一個指針,這個指針的值隻能在定義時初始化,在其他地方不能改變。常量指針是指定

義了一個指針,這個指針指向一個隻讀的對象,不能通過常量指針來改變這個對象的值。

指針常量強調的是指針的不可改變性,而常量指針強調的是指針對其所指對象的不可改變性。

面試題6:寫出以下代碼的輸出結果:

#include <iostream.h>
void main(void)
{
char str1[] = "abc";
char str2[] = "abc";


const char str3[] = "abc";
const char str4[] = "abc";


const char *str5 = "abc";
const char *str6 = "abc";


char *str7 = "abc";
char *str8 = "abc";


cout<<(str1 == str2)<<endl;
cout<<(str3 == str4)<<endl;
cout<<(str5 == str6)<<endl;
cout<<(str7 == str8)<<endl;
}
           

答案:0 0 1 1

運作結果:

1

1

面試題7:找出代碼的錯誤并改正。

#include <stdio.h>
void swapxy(char *a,char *b)
{
char x = *a, y = *b;
x = x + y;
y = x - y;
x = x - y;


*a = x, *b = y;


return;
}
void main(void)
{
char a = 'a', b = 'b';
char &x = a; &y = b;


printf("a = %c and b = %c before swap.\n",a,b);
swapxy(x,y);
printf("a = %c and b = %c after swap.\n",a,b);


return;
}
           

答案:

#include <stdio.h>
void swapxy(char &a, char &b)
{
char x = a, y = b;
x = x + y;
y = x - y;
x = x - y;
a = x, b = y;
return;
}
void main(void)
{
char a = 'a', b = 'b';
  char &x = a, &y = b;
printf("a = %c and b = %c before swap.\n",a,b);
swapxy(x,y);
printf("a = %c and b = %c after swap.\n",a,b);
return;
}
           

運作結果:

a = a and b = b before swap.

a = b and b = a after swap.

面試題8:寫出代碼的輸出結果

#include <iostream.h>
void main(void)
{
int b = 0;
int a[5] = {0,1,2,3,4};

for(int i = 0, i < 5)
{
i = a[i+1];
cout<<a[i]<<endl;
}
return;
}
           

答案:輸出結果為:1 2 3 4 0 1 2 3 4 0 1 2 3 4……

(注意結果是一個死循環,重複輸出1 2 3 4 0)

面試題9:下面這段程式有問題嗎?如果沒有,請寫出列印結果。

#define MAX 255
# include <stdio.h>
void main(void)
{
unsigned char str[MAX],i;
for( i = 0; i <= MAX; i++)
{
str[i] = i;
printf("%d\n",str[i]);
}
}
           

答案:這個程式是死循環加數組越界通路(C/C++不進行數組越界檢查)。

面試題10:a和&a有什麼差別

請寫出以下代碼的列印結果。

# include <stdio.h>
void main(void)
{
int a[5] = {1,2,3,4,5};
int *ptr = (int*)(&a+1);


printf("%d,%d\n",*(a+1),*(ptr-1));
return;
}
           

答案:2,5

運作結果:

2,5

解析:*(a+1)就是a[1],但是*(ptr-1)并不是a[0],因為&a+1并不是數組a的首位址加1,

系統會認為是數組a的首位址加上一個數組a的偏移,即偏移了一個數組的大小,(本例

中是5個int的位址)。原式int*ptr(int*)(&a+1);的結果是,ptr指向了數組的第六個元

素a[5]。可參考如下程式:

# include <stdio.h>
void main(void)
{
int a[5] = {1,2,3,4,5};
int *ptr = (int*)(&a+1);


printf("&a :%d\nptr:%d\n",&a,ptr);
return;
}
           

運作結果:

&a :1703724

ptr:1703744

從結果可以看出,ptr比數組a的首位址偏移了20個位元組的位址,即偏移了5個int型資料,原因是&a是

數組a的指針,其類型為int(*)[5],而指針加1要根據指針類型加上一定的值,不同類型的指針加1後

的結果不同。可參考如下代碼:

# include <stdio.h>
void main(void)
{
int i = 1;
char c = 2;
double f = 3.0;
char A[3] = {0,1,2};


int *pi = &i;
char *pc = &c;
double *pf = &f;
char (*pA)[3] = &A;


printf("&i:%d pi:%d pi+1:%d\n",&i,pi,pi + 1);
printf("&c:%d pc:%d pc+1:%d\n",&c,pc,pc + 1);
printf("&f:%d pf:%d pf+1:%d\n",&f,pf,pf + 1);
printf("&A:%d pA:%d pA+1:%d\n",&A,pA,pA + 1);
return;
}
           

運作結果:

&i:1703740 pi:1703740 pi+1:1703744

&c:1703736 pc:1703736 pc+1:1703737

&f:1703728 pf:1703728 pf+1:1703736

&A:1703724 pA:1703724 pA+1:1703727

面試題11:以下代碼有什麼問題?

#include <iostream.h>
void main(void)
{
char *p1,*p2;
char ch[12];
char **p;


p1 = ch;
pp = &ch;
p2 = *pp;


cout<<p1<<endl;
cout<<pp<<endl;
cout<<p2<<endl;
return;
}
           

答案:(1)數組ch沒有初始化。

      (2)把數組指針指派給字元的二級指針。

修改方案:

#include <stdio.h>
void main(void)
{
char *p1;
char *p2;
char **pp;
char ch[] = "abcd";
printf("sizeof p1:%d,p2:%d,pp:%d,ch:%d\n",
sizeof(p1),sizeof(p2),sizeof(pp),sizeof(ch));

p1 = ch;
pp = &p1;
p2 = *pp;

if(p1 == p2)
{
printf("p1 equals p2\n");
}
else
{
printf("p1 doesn't equal p2\n");
}
return;
}
           

運作結果:

sizeof p1:4,p2:4,pp:4,ch:5

p1 equals p2

面試題12:數組名和指針的差別  請寫出以下代碼的列印結果:

#include <iostream.h>
#include <string.h>
void main(void)
{
char str[13] = "Hello world!";
char *pStr = "Hello world!";
cout<<sizeof(str)<<endl;
cout<<sizeof(pStr)<<endl;
cout<<strlen(str)<<endl;
cout<<strlen(pStr)<<endl;
return;
}
           

答案:

13

4

12

12

面試題13:請解析(*(void(*)())0)()的含義

請解析下面這條語句:

(*(void(*)())0)();

答案:從頭到尾解析結果如下

(1)void(*0)():是一個傳回值為void,參數為空的函數指針0。

(2)(void(*)())0:把0轉變成一個傳回值為void,參數為空的函數指針。

(3)*(void(*)())0:在上句的基礎上加*表示整個是一個傳回值為void,無參數,并且起始

位址為0的函數的名字。

(4)(*(void(*)()0)(): 這就是上句的函數名所對應的函數的調用。

面試題14:指出程式的錯誤

指出下面這段程式的錯誤并改正:

#include<stdio.h>
void main()
{
int max(x,y);
int *p = max;
int a,b,c,d;
scanf("%d,%d,%d",a,b,c);
d = p(p(a,b),c);
printf("d:%d\n",d);
return;
}
int max(int x,int y)
{
return(x > y ? x:y);
}
           

答案:

(1)int max(x,y); 函數聲明錯誤,改為:int max(int,int);

(2)int *p=max; 指針定義錯誤改為:int(*p)(int,int)=max;

(3)scanf("%d%d%d",a,b,c); 庫函數使用錯誤,改為scanf("%d%d%d",&a,&b,&c);

(4)d=p(p(a,b),c); 函數指針調用函數錯誤,改為d=(*p)((*p)(a,b),c);

修改後:

#include<stdio.h>
void main()
{
int max(int,int);
int (*p)(int,int) = max;
int a,b,c,d;
scanf("%d %d %d",&a,&b,&c);
d = (*p)((*p)(a,b),c);
printf("d:%d\n",d);
return;
}
int max(int x,int y)
{
return(x > y ? x:y);
}
           

運作結果:

45

78

23

d:78

面試題15:如何避免“野指針”

“野指針”是如何産生的?應該如何避免?

答案:“野指針”産生原因及解決辦法如下:

(1)指針變量聲明時沒有被初始化。解決辦法:指針聲明時初始化,可以使具體的位址值,也可以讓它指向NULL。

(2)指針p被free或delete之後,沒有置為NULL。解決辦法:指針指向的記憶體空間被釋放後指針應該指向NULL。

(3)指針操作超越了變量的作用範圍。解決辦法:在變量的作用域結束前釋放掉變量的位址空間,并且讓指針指向NULL。

面試題16:程式是否正确

下面這段程式是否正确?如果正确,請寫出列印結果:

#include <iostream.h>
typedef int* pInt;
void swap(int *p1,int *p2)
{
int *p;
*p = *p1;
*p1 = *p2;
*p2 = *p;
}
void main(void)
{
int a = 1, b = 3;
pInt p1 = &a, p2 = &b;


cout<<"a:"<<*p1<<" b:"<<*p2<<endl;
swap(p1,p2);
cout<<"a:"<<*p1<<" b:"<<*p2<<endl;
return;
}
           

答案:不正确,指針p沒有被初始化就直接使用,其為“野指針”會導緻不可預知的錯誤。

修改後:

#include <iostream.h>
typedef int* pInt;
void swap(int *p1,int *p2)
{
int p;
p = *p1;
*p1 = *p2;
*p2 = p;
}
void main(void)
{
int a = 1, b = 3;
pInt p1 = &a, p2 = &b;


cout<<"a:"<<*p1<<" b:"<<*p2<<endl;
swap(p1,p2);
cout<<"a:"<<*p1<<" b:"<<*p2<<endl;
return;
}
           

運作結果:

a:1 b:3

a:3 b:1

面試題17:指出程式的錯誤

#include <stdio.h>
class A
{
public:
A()
{
number = 0;
};
void Fun1()
{
printf("In Fun1 number is:%d\n",number);
};
void Fun2()
{
printf("In Fun2\n");
}
public:
int number;
};
void f(A *p, int i);


void main(void)
{
A *p;
f(p,5);
if(p != NULL)
{
p->Fun1();
p->Fun2();
}
}
void f(A *p,int i)
{
if(p == NULL)
{
A a;
a.number = i;
p = &a;
}
}
           

答案:在主函數中調用函數f後,p是“野指針”,用p調用函數Fun1時,會出現記憶體錯誤,因為在Fun1

中用到了類A的成員變量number,而類的成員變量屬于類的成員對象,在類成員對象作用域外對其的所

有通路都是非法的。

面試題18:簡述C/C++程式編譯的記憶體配置設定情況

在C/C++中不同性質的資料在編譯時存放在不同的位置,請簡述C/C++程式編譯時的記憶體配置設定情況。

答案:

(1)棧區(stack):由編譯器自動配置設定釋放,存放為運作函數而配置設定的局部變量、函數參數、傳回資料、

傳回位址等。其操作方式類似于資料結構中的棧。

(2)堆區(heap): 一般有程式員配置設定釋放,若程式員不釋放,程式結束時可能由系統回收。配置設定方式

類似于連結清單。

(3)全局區(靜态區)(static): 存放全局變量、靜态資料、常量。程式結束後由系統釋放。

(4)文字常量區: 常量字元串就是放在這裡的。程式結束後由系統釋放。

(5)程式代碼區:存放函數體(類成員函數和全局函數)的二進制代碼。

面試題19:以下四段代碼中哪段沒有錯誤?

請看這四段代碼:

代碼一:

void GetMemory(char *p)
{
p = (char *)malloc(100);
}
void Test(void)
{
char *str = NULL;
GetMemory(str);
strcpy(str,"hello world");
printf(str);
}
           

代碼二:

char* GetMemory(void)
{
char p[] = "hello world";
return p;
}
void Test(void)
{
char *str = NULL;
str = GetMemory()();
printf(str);
}
           

代碼三:

void GetMemory(char **p,int num)
{
*p = (char *)malloc(num);
}
void Test(void);
{
char *str = NULL;
GetMemory(&str,100);
strcpy(str,"hello");
printf(str);
}
           

代碼四:

void Test(void)
{
char **str = (char *)malloc(100);
strcpy(str,"hello");
free(str);
}
           

答案:四段代碼全有錯誤。

*代碼一:GetMemory(char *p)的參數為字元型指針,在這個函數修改參數p的值時并不能

真正修改實參的值。

%代碼二:其中的p[]數組是函數GetMemory中的局部變量,函數傳回後,p就被釋放掉,

str便指向了一段無用的記憶體區域。

*代碼三:沒有判斷動态記憶體申請是否成功而直接使用,沒有釋放動态申請的記憶體,造成

記憶體洩漏。

*代碼四:沒有判斷動态記憶體申請是否成功而直接使用,動态記憶體釋放後沒有将指針置空。

繼續閱讀