《剑指offer》中涉及C++的基础知识

3 篇文章 0 订阅

【未完待续,持续整理中……】

第一章

1. C++中有哪4个与类型转换相关的关键字?这些关键字各有什么特点,应该在什么场合下使用?

答:
推荐这篇博客:
【C++】的四种强制转换》讲得浅显一些
C++的四种强制转换》这篇有搭配场景,讲得深一点
static_cast:最常用的
const_cast:用来转换const类型的,但是尽量不要用,毕竟const就是为了不改变的
reinterpret_cast:谨慎使用,用来转换指针的。
dynamic_cast:运行时进行的检查。
在这里插入图片描述

2.sizeof的使用

①定义一个空的类,使用sizeof后得到的大小:
答:1。实例必须占有空间,要不然无法访问。具体多少由编译器决定,VS中分配1。
②如果给该空类添加构造函数和析构函数,则sizeof大小为:
答:1。构造函数和析构函数只需要知道类的地址即可,与实例无关,所以对实例的大小没有影响。
③如果把析构函数写成虚函数后,则sizeof大小为:
答:4。如果类里面有虚函数,则会为该类型添加一个虚函数表,并为该类的实例添加一个指向这个虚函数表的指针,32位的指针是4字节,64位的是8字节。
这篇博客讲的很好:C++ sizeof的使用总结

3.c++中不允许复制构造函数传值参数

请评价这段程序是否可以运行

class A{
private:
    int value;
public:
    A(int n){ value = n; }
    A(A other){ value = other.value; }
    void Print() {cout<<value<<endl; }
};
int main(void)
{
    A a = 10;
    A b = a;
    b.Print();
    return 0;
}

详细分析可以参考这篇文章:
名词解释:
复制构造函数:就是构造函数的重载

如果拷贝构造函数是传值而不是传引用,
①当调用ccc.CExample(aaa)时,aaa作为参数传值给ccc.CExample(CExample ex),即CExample ex = aaa,
②因为ex没有被初始化,所以会继续调用拷贝构造函数,接下来是构造ex,也就是ex.CExample(aaa),
③必然又会有aaa传给CExample(CExample ex),即CExample ex = aaa;
那么又会触发拷贝构造函数,这样就无限递归下去了。。。

4.面试题1:c++中char*等操作

第一道题涉及一些字符串的基础知识,所有的都被这篇文章涵盖了:
C++ 字符串与字符数组 详解
我在这篇博客里总结了这四种的相互转换:
Learn C++学习笔记:第六章—数组、指针和字符串(二)
总结一些要点就是:
①字符串的结尾是以’\0’为划分的;
②char[]想转char*、string、const char*,都可以直接当成右值赋值即可;
③string可以作为左值接收其他类型的直接赋值;

5. 数组在做函数参数时候自动退化为指针

无论是整形数组还是字符串数组,在做函数参数时候都会退化为指针。

int Getsize(int data[]){return sizeof(data);}
void main()
{
	int data1[] = {1,2,3,4};
	std::cout << Getsize(data1) << std::endl;

这段代码会返回4,虽然数组大小是4*4,但是对于指针来说,大小在32位机器上是4。

6. 面试题5:字符串的扩容

C++中字符串主要有stringchar[]两种格式。
对于char[]:
由于其实数组名是指针,所以可以直接扩容:

    char x[]="rr";
    x[2]='x';
    x[3]='y';
    x[4]='\0';

输出结果rrxy
但是有两方面需要注意的:
1⃣️字符串的结尾要加上'\0',来表示字符串的结尾;
2⃣️sizeof对数组查看的时候,长度依然是未扩容之前的大小,也就是sizeof不会随着指针扩容而改变,长度包含’\0’字符;
3⃣️这种做法有风险,如果有两个数组的地址空间挨的很近,那么前面的扩容的时候很容易伸进后面那个数组的地址里面,造成后面的数组损坏。
总之,这种方法是不安全的。
对于string:
不可以通过指针的方式直接扩容,扩容只能通过string+“xxx”的方式。

    string x="rr";
    x[2]='x';
    x[3]='y';
    x[4]='\0';

输出结果还是rr
string是一种经过封装后比较安全的类,string.length()的长度不包含'\0',并且无论string里面有多少字符,sizeof(string)的大小一直是24,字符串所占的空间是从堆中动态分配的,与sizeof()无关;

长度的三个函数:

char buf[] = "he\0llo";
std::cout << sizeof(buf) << std::endl;                      
// 实际所占内存空间的大小,与`\0`的位置无关,
// 但会在字符串的末尾自动加上`\0`,也即 he\0llo\0
std::cout << strlen(buf) << std::endl;                      
// 遇第一个\0结束统计

string str = "aa";
str.length();    //不包含\0
sizeof(str);     //长度跟字符串长度没关系

7.链表的添加删除函数中参数为什么是指向指针的指针

就是看上去有点绕,其实很简单:

int x = 5;
listNode *phead;

如果写func(int x),传进函数的其实是5这个值,x并没有改变;
如果写func(listNode *phead),传进函数的其实是这个phead这个指针的值,也就是第一个节点的地址,这个值改变了,改变了其实是第一个节点,对于我们可能需要改变的头节点指向,根本没改。

想改变谁,就传谁的指针进来。如果要改指针,就传指针的指针。

8. vector等容器的基本操作

#include<vector>    //导入vector

vector<int> vector;  //初始化变量
vector< vector<int> > vt;//初始化一个 二维vector
vector<vector<int> > vect(vt);//使用另一个 二维 vector 初始化当前二维vector
vector< vector<int> > vec(row,vector<int>(column));//初始化一个 二维的vector 行row,列column,且值为0
vector<vector<int> > visited(row,vector<int>(column,6));//初始化一个 二维vector 行row,列column ,且 值为data=6 自定义data;

int length = vector.size()   //获取长度
vector.push_back(number)     //末尾添加元素
vector.insert(vector.begin(), number) //从头部开始添加元素number
vector.insert(vector.begin(), other_vec.begin(), other_vec.end()) //将另外一个数组插到数组后面
std::reverse(vector.begin(),vector.end()) //反转向量

vec_copy.assign(vector.begin(), vector.end())
vec_copy.assign(vector.begin(), vector.begin()+1) //拷贝向量拷贝向量的数量是前后的差,这句话就是,只拷贝一个元素

sort(arr.begin(), arr.end());

优先队列priority_queue

#include<queue>
//默认是小元素排前面
priority_queue<int> p;
//top 访问队头元素
//empty 队列是否为空
//size 返回队列内元素个数
//push 插入元素到队尾 (并排序)
//emplace 原地构造一个元素并插入队列
//pop 弹出队头元素
//swap 交换内容

9. 面试题11:二分查找的边界问题

待完善

10.c++中不能对小数比较来判断相等

看示例代码:

int main()
{
    double epsilon=0.001;
    double d1=2.334;
    double d2=2.335;
    
    cout<<"epsilon is: "<< setprecision(20) << epsilon<<endl;
    cout<<"d2-d1   is: "<< setprecision(20) << d2-d1 <<endl;
    
    if ((d2 - d1) == epsilon){ cout << "Equal!" << endl; }
    else{cout << "Not equal!" << endl;}

    return 0;
}

输出是:

epsilon is: 0.0010000000000000000208
d2-d1   is: 0.00099999999999988986588
Not equal!
Program ended with exit code: 0

永远不要尝试去比较两个浮点数是否相等
一般用两个小数的差值是否小于设置的数来决定是否相等

11.c++中数据类型对应的表示范围

在这里插入图片描述

12.面试题17:memset用于较大的对结构体和数组的清零操作

该题中需要初始化字符串数组,如果定义的是指针,那么该函数是比较方便的操作。

函数原型:void *memset(void *s , int ch , size_t n )

memset(结构体/数组名 , "用于替换的字符“ , 前n个字符 );

函数解释:将s中的前n个字节用ch替换并且返回s

函数作用:在一段内存块中填充某一个给定的值,常用于较大的对结构体和数组的清零操作。
在该面试题中的用法如下:

char* number = new char[10]   //建立一个空间
memset(number, '0', 9)        //该数组前9个元素初始为'0'

13.面试题33: 关于容器的使用

  • 这道题的递归解法中需要从初始的向量中截取一段子向量去给递归函数使用,我的初步想法是递归函数里声明一个向量,把父向量需要递归的部分赋值给子向量,把子向量作为实参传给递归函数,但是这样会发现,需要不断申请内存。所以这个时候就是指针的好处,但是答案里使用的是引用,指针和引用的区别还需要后面学习。
  • 还有一个就是对于二叉搜索树的定义理解问题。最初的思路是1⃣️递归子函数中需要有一个最大值和最小值,然后根结点跟他们比大小,2⃣️再然后判断向量能不能被vector[-1]分成两段。其实,根本不需要第一步,第二步判断中已经包含了这种判断,只要向量可以被vector[-1]分成两截,其实就是满足二叉搜索树的left < root < right的定义了。

14.面试题39:快速排序中partition函数

该函数需要两个指针,一个指针循环,一个指针记录小于挑选的那个数左边区域的最右边。
在这里插入图片描述

15.面试题40:vector的排序和初始化

vector容器可以使用sort函数进行排序。

vector<int> vec(k, 0);    //初始化规定大小和数字的方式
sort(arr.begin(), arr.end());

本题中需要使用关键数据结构大顶堆:priority_queue
c++优先队列(priority_queue)用法详解介绍的比较好。

16.面试题45:大数问题和排序函数sort的使用

17.面试题46:再次理解递归

一开始的思路就是,确定循环深度,不同的字符串进行不同次数个嵌套循环,但是怎么实现不定次数的嵌套深度呢,一直没想到办法

18. 面试题50:

哈希表的使用,添加、初始化、查找

19.面试题56:

位运算是有优先级的,比较低

((xorr & tmp) == 0)
(xorr & tmp == 0)      //会先进行==运算

5&4运算是返回那一位的值,并不是1或0,而是4或0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值