面试指南:指针

2024-01-10 08:42:14

目录

前言

指针基础

指针实战

数组与指针比较

sizeof、strlen与指针

指针++

函数传递指针的时候是副本

指针要分配给足够的空间

指针定义描述

this指针


前言

在我的博客C++高质量编程-CSDN博客内存管理章节里面讲了一些内存的基础知识,内存管理涉及最多的就是指针,也详细讲解了指针的原理以及平时编程使用指针犯的错误,不太熟悉的可以去看看,现在就对面试问的比较多的关于指针的问题归纳总结一下,希望对看到这篇博客的同学们有所帮助。

指针基础

1.什么是指针?请简述指针的基本概念和用途。

2.指针变量和普通变量有什么区别?如何声明和初始化指针变量?

3.指针的算术运算有哪些?请举例说明

4.什么是野指针?如何避免野指针的产生?

5.指针和引用区别?

6.什么是函数指针?请简述函数指针的概念和用途

7.如何声明和初始化函数指针?如何通过函数指针调用函数?

8.什么是多级指针?请举例说明多级指针的使用场景。

9.指针和数组有何关系?如何通过指针访问数组元素?

10.动态内存分配有哪些方式?请简述它们的区别和用途

11.如何使用new和delete操作符进行动态内存分配和释放?

12.C和C++分别怎么动态分配内存?有什么区别?

13.什么是内存泄漏?如何避免内存泄漏?

14.请解释C++中的const指针和指向cons指针的区别。

15.什么是智能指针?请简述智能指针的概含和用途。

16.如何使用std:unique_ptr、std::shared_ptr和std:weak_ptr智能指针?

指针实战

1.数组与指针比较

char szTest1[] = "123";
char szTest2[] = "123";
const char szTest3[] = "123";
const char szTest4[] = "123";
const char *pTest1= "123";
const char *pTest2= "123";
char *pTest3= "123";
char *pTest4= "123";
cout<<(szTest1==szTest2)<<endl;   //1 , 输出: 0
cout<<(szTest3==szTest4)<<endl;   //2 , 输出: 0
cout<<(pTest1==pTest2)<<endl;     //3 ,输出: 1
cout<<(pTest3==pTest4<endl;       //4 ,输出: 1

szTest1、szTest2、szTest3、szTest4都是数组,分配新空间,它们有各自的内存空间,这样写szTest1代表的数组的首地址,因此szTest1、szTest2、szTest3、szTest4都不相同;

pTest1、pTest2、pTest3、pTest4都是指针,指定的地址都相同,所以4个都是相同。

因此输出是:0? 0? 1? 1

2.sizeof、strlen与指针

char szTest1[] = "hello world";
const char* pTest1 = "hello world";
int len1 = sizeof(szTest1);
int len2 = strlen(szTest1);
int len3 = sizeof(pTest1);
int len4 = strlen(pTest1);
cout << len1;//输出 12
cout << len2;//输出 11
cout << len3;//输出 8
cout << len4;//输出 11

szTest1是数组,以'\0'结尾,sizeof计算内存占用空间,所以输出12,strlen计算字符串的长度,字符串以'\0'结尾结束,所以输出11;pTest1是个指向const char的指针,指针在x64下固定是8个字节,所以输出是8,strlen(pTest1)是计算pTest1指向的字符串长度,故输出11。

int calcLen(char str[])
{
    return (int)(sizeof(str)-1);//无论何时都是返回3
}

函数传递的是数组的时候就自动退化为指针了, 而指针的长度为4,减去1就是3

3.指针++

int m[5] = { 4, 12, 241, 33, 545 };  
int *ptr = (int *)(&m + 1);  
printf("%d,%d", *(m + 1), *(ptr - 1)); 

理解指针运算,”+1“就是偏移量的问题:一个类型为T的指针移动,是以sizeof(T)为单位移动的。m+1:在数组首元素地址的基础上,偏移一个sizeof(a[0])单位。因此m+1就代表数组第1个元素,为2;

&m+1:在数组首元素的基础上,偏移一个sizeof(m)单位,&m其实就是一个数组指针,类型为int[5]。因此&m+1实际上是偏移了5个元素的长度,也就是m+5;再看ptr是int类型,因此"ptr-1"就是减去sizeof(int*),即为m[4]=5;

m是数组首地址,也就是m[0]的地址,m+1是数组下一个元素的地址,即m[1];&m是对象的首地址,&m+1是下一个对象的地址,即m[5]

4.函数传递指针的时候是副本

void GetMemory(char *p)
{
    p=new char[100];
    strcpy(p,"hello world");
}
void main(void)
{
    char *str=NULL;
    GetMemory(str);
    cout<<str;
    delete []str;
    str=NULL;
}

初看函数逻辑,一切都是那么理所当然。仔细看下,这里的str是指char*的指针,把str指针拷贝了一份传给函数GetMemory,??GetMemory参数中的p和str不一样了,所以在GetMemory中改变p,不会影响到str,main函数中的str还是NULL,如果在GetMemory要返回new出的地址,那参数p必须为引用或双重指针,双重指针代码如下:

void GetMemory(char **p)
{
    *p=new char[100];
    strcpy(*p,"hello world");
}
void main(void)
{
    char *str=NULL;
    GetMemory(&str);
    cout<<str;
    delete []str;
    str=NULL;
}

也可以用引用,代码如下:

void GetMemory(char*& p)
{
    p=new char[100];
    strcpy(p,"hello world");
}
void main(void)
{
    char *str=NULL;
    GetMemory(str);
    cout<<str;
    delete []str;
    str=NULL;
}

5.指针要分配给足够的空间

void func()
{
    char b;
    char *p = &b;
    strcpy(p, "hello world");
    cout<<p;
}

因为 char类型的a变量只拥有了一字节的空间,但是"hello"拥有6字节的空间(包含最后的'\0'),所以程序出现问题,有可能崩溃,因为strcpy的时候有可能把func的返回地址覆盖了,函数调用返回不到上级函数,出现异常。

6.指针定义描述

int *a[10]; 

? ?由于符号[]的优先级高于*, 所以a优先于[]结合,a是一个数组,数组的每个元素都是指向int的指针

int (*a)[10];

? ?由于符号()的优先级高于[],所以a优先于*结合,a是一个指针,指向int类型的数组

int (*a)(int);

? ? 首先a是一个指针,去掉a的()部分就是 int (int),这不就是一个函数吗,所以a是一个指向int(int)函数的指针,即函数指针。

int (*a[10])(int);

分解:1) int (int)? 2) a[10]? ? 3) *,所以a是一个大小为10的数组,数组的每个元素都是指针,该指针指向一个函数,该函数有一个整型参数并返回一个整型数。

int ((*a)[10])(int);

分解:1) int (int)? 2) [10]? ? 3) *a,所以a是一个指针,指向大小为10的数组,数组的每个元素都是函数,该函数有一个整型参数并返回一个整型数。

7.this指针

下面看一道比较经典的题目:

class MyTest {
public:
	void Test() {
		cout << "Test()" << endl;
	}
private:
	int m_a;
};
 
int main()
{
	MyTest* p = nullptr;
	p->Test();
}

上面的代码运行会出现异常吗?答案是不会。

原因分析:1不管是C语言的函数还是C++得成员函数都有一个准确的地址? ?2 在main函数中p调用Test函数的时候,指针p会通过汇编寄存器ecx传给函数Test的入口参数? ?3 进入函数Test后这个ecx就赋值给this指针,可以通过this指针访问MyTest类中的成员变量和成员函数。

上面代码MyTest类中Test函数中,虽然this指针是空的,但是函数里面也没有访问任何成员函数和成员变量,所以不会报错。如果把题目改为如下:

class MyTest {
public:
	void Test() {
		cout << m_a << endl;
	}
private:
	int m_a;
};
 
int main()
{
	MyTest* p = nullptr;
	p->Test();
}

运行报错,原因是Test函数中的this指针是空的,一旦访问m_a就提示访问内存报错。

如果还有不明白的同学可以去翻翻看<<深入理解C++对象模型>>,这本书把C++对象模型讲的比较深,比较透。

参考

C++高质量编程-CSDN博客

<<深入理解C++对象模型>>

文章来源:https://blog.csdn.net/haokan123456789/article/details/135430978
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。