面试题累积-指针与引用(二)

面试题积累-指针与引用(二)


面试题1:写出函数指针、函数返回指针、const指针、指向const的指针、指向constconst指针

void (*f)(){}:这里的f就是返回值为空的函数的指针。

int * f(){return}

const int* p = &a:这里pconst指针,意味着不能修改p的值,但能修改p所指向的值,如p++是错的,*p=10是对的。

int* const *p=&a,不修改p所指向的值,但能修改p的值,如p++可以,但是*p=11是错的。

Const int* const p = &a:综合以上。

面试题2:找错

int max(int x, int y){
	return x > y ? x : y;                   //1
}
int _tmain(int argc, _TCHAR* argv[])
{
	int max(x, y);                 //2
	int *p= &max;               //3
	int a = 3, b = 2, c = 4, d;
	d = (*p)((*p)(a, b), c);
	cout << d << endl;	
	return 0;
}

解析:该题存在函数指针使用错误。第2步错,改为int max(int,int),第3步错,改为int *p(int,int)=&max;

扩展知识:函数声明和函数定义

    C语言编译系统是由上往下编译的.一般被调函数放在主调函数后面的话,前面就该有声明.不然C由上往下的编译系统将无法识别。

函数的定义是指对函数功能的确立,包括指定函数名,函数值类型、形参及其类型以及函数体等,它是一个完整的、独立的函数单位。

函数的声明的作用则是把函数的名字,函数类型以及形参的类型、个数和顺序通知编译系统,以便在调用该函数时进行对照检查(例如,函数名是否正确,实参与形参的类型和个数是否一致),它不包括函数体。

函数原型则特指包括说明参数类型的函数声明。

面试题3:程序结果为多少

void arrayPoint(){
	int v[2][3] = { { 1, 2, 3 }, { 4, 5, 6 } };
	int(*a)[3] = v;
	cout << **a << endl;
	cout << **(a + 1) << endl;
	cout << *(*a + 1) << endl;
	cout << *(a[0] + 1) << endl;
	cout << *(a[1]) << endl;
}

解析:答案为14224。该题定义一个指针指向一个3int元素的数组,a+1表明a指针向后移动1*sizeof(数组大小)a+1后共移动12个字节,*a+1仅针对一行向后移动4个字节。

面试题4:一个指向整型数组的指针的定义为

Aint(*ptr)[]   B.int *ptr[] C.int *(ptr[])  D.int ptr[]

解析:int(*ptr)[]是一个指向整型数组的指针;int *ptr[]是指针数组,ptr[]里存放的是地址,它指向位置值为*ptr[0],*ptr[1],*ptr[2],不要存*ptr[0]=5,*ptr[1]=6,因为这里没有相应地址。Int *(ptr[])B相同。

扩展知识:指针数组和数组指针

指针数组:定义为int*p[n][]优先级高,先与p结合成为一个数组,再由int*说明这是一个整型指针数组,它有n个指针类型的数组元素。执行p+1p=a是错误的;*p=a这里*p表示指针数组第一个元素的值。如要将二维数组赋给一指针数组: 

int *p[3];
int a[3][4];
for(i=0;i<3;i++)
p[i]=a[i];
这里int *p[3] 表示一个一维数组内存放着三个指针变量,分别是p[0]、p[1]、p[2]

   数组指针:定义为int (*p)[n]; ()优先级高,首先说明p是一个指针,指向一个整型的一维数组,这个一维数组的长度是n,也可以说是p的步长。也就是说执行p+1时,p要跨过n个整型数据的长度。

int a[3][4];
int (*p)[4]; //该语句是定义一个数组指针,指向含4个元素的一维数组。
p=a;        //将该二维数组的首地址赋给p,也就是a[0]或&a[0][0]
p++;       //该语句执行过后,也就是p=p+1;p跨过行a[0][]指向了行a[1][]

面试题5:用变量a给出下面的定义:

a)一个整型数                                                //int a

b)一个指向整型数的指针                                      //int *a

c)一个指向指针的的指针,它指向的指针是指向一个整型数        //int *(*int) //int **a

d)一个有10个整型数的数组                                   //int a[10]

e)一个有10个指针的数组,该指针是指向一个整型数的         //int *a[10]

f)一个指向有10个整型数数组的指针                         //int (*a)[10]

g)一个指向函数的指针,该函数有一个整型参数并返回一个整型数int (*f)(int)

h)一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数                              //int (*a[10])(int)

面试题6:以下代码哪会有错

void lostPoint(){
	SHO *pin = new SHO;
	*pin = 5;
	cout << "*pin" << *pin << endl;
	delete pin;
	pin = 0;
	long *plong = new long;
	*plong = 1000;
	cout << "*plong" << *plong << endl;
	*pin = 20;
	cout << "*pin" << *pin << endl;
	cout << "*plong" << *plong << endl;
	delete plong;
}

解析:该题考察迷途指针。

迷途指针:当所指向的对象被释放或者收回,但是对该指针没有作任何的修改,以至于该指针仍旧指向已经回收的内存地址,此情况下该指针便称迷途指针。若操作系统将这部分已经释放的内存重新分配给另外一个进程,而原来的程序重新引用现在的迷途指针,则将产生无法预料的后果。因为此时迷途指针所指向的内存现在包含的已经完全是不同的数据。通常来说,若原来的程序继续往迷途指针所指向的内存地址写入数据,这些和原来程序不相关的数据将被损坏,进而导致不可预料的程序错误。在*pin=20步中给迷途指针赋值,报错。

扩展知识:空指针、迷途指针和野指针的区别

空指针:使用ptr=0,可将迷途指针改为空指针;

野指针:还没有初始化的指针。每个指针在初始化前都是野指针。

面试题7C++中有了malloc/free,为什么还需要new/delte?

解析:

相同点:都可用于申请动态内存和释放内存。

不同点:

1)操作对象有所不同

   mallocfreeC++/C语言的标准库函数,new/deleteC++的运算符。对于非内部数据类的对象而言,光用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加malloc/free

即new将调用constructor,而malloc不能;delete将调用destructor,而free不能

2)使用方式不同

     malloc/free使用:

     函数malloc的原型如下:void * malloc(size_t size);malloc申请一块长度为length的整数类型的内存:int *p = (int *) malloc(sizeof(int) * length);涉及“类型转换”和“sizeof”。

     1malloc返回值的类型是void *,所以在调用malloc时要显式地进行类型转换,将void*转换成所需要的指针类型。

     2 malloc函数本身并不识别要申请的内存是什么类型,它只关心内存的总字节数。

     函数free的原型如下:void free( void * memblock );如果pNULL指针,那么freep无论操作多少次都不会出问题。如果p不是NULL指针,那么freep连续操作两次就会导致程序运行错误。 

     New/delete使用:

     int *p2 = new int[length];new内置了sizeof、类型转换和类型安全检查功能。

     在用delete释放对象数组时,留意不要丢了符号‘[]’。例如

     delete []objects; //正确的用法

     delete objects; //错误的用法

     后者相当于delete objects[0],漏掉了另外99个对象。