面试题-指针的概念

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/chen1083376511/article/details/82702694

返回目录:https://blog.csdn.net/chen1083376511/article/details/82723709

问题:

问:什么是指针?

答:指针是用来存储内存地址的变量,它指向单个对象的地址,除了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变量前面的一块未知内存,非法。

猜你喜欢

转载自blog.csdn.net/chen1083376511/article/details/82702694
今日推荐