wordpress首页获取文章的图片/网站建设优化的技巧
开心啊,终于有一次电面了,投腾讯,爱奇艺笔试过了面试未去(第一太远,第二感觉实力不够),美团,蘑菇街未收到通知,上午发的消息, 今天晚上面试,比预期提早了半个小时,还好没啥影响,于是复习了一下午c/c++,真的猜对了好多题,但是第一次面试太紧张了,总是没说中关键点。中途由于机房手机信号不好尴尬的5分钟左右。。。。想吐槽这个机房。。。。
简单个人介绍
首先重c开始问
1.全局变量和局部变量的区别
作用域不同,全局变量存放在静态区,不初始化时默认为0,局部变量存放在栈区,不初始化,不确定其值。
局部同时有全局和局部的相同名字的变量,可通过::来使用全局变量
2.const 和 define 的区别
3.const char* 和 const *char 的区别
const char* p =char const *p 指针的值不可修改
char *const p 指针地址不可修改
const定义的值可以修改吗?
可以。
#include <stdio.h>
#include <iostream>
int main()
{
const volatile int a=99; //volatile强制将a存放到内存,也就是内存的读取。如果不加volatile,输出值仍是99,但是实际上*p的值是可以并且已经改变了的,由于编译器的优化,有a的地方全部被常量99替换了。
int *p=(int*)&a;
*p=100;
printf("%d", a);
return 0;
}
- const全局变量存储在全局存储空间,其值只有可读属性,不能修改;
- const局部变量存储在堆栈中,可通过指针修改其值;
- const变量在预处理时处理,编译器只对其值读取一次。
(1)const修饰函数参数1.如果输入的参数采用“指针传递”,那么加上const可以防止意外的改动该指针,起到保护作用例如:void func(char *dest_str, const char *src_str)2.如果输入参数采用“值传递”,由于函数将自动产生临时变量用于复制该参数,该输入参数本来就不需要保护所以不用加const也可以例如:void func(int x)不用写成void func(const int x)3.但是对于非内部的数据类型的参数而言,例如void func( A a)这样声明的函数注定效率低,因为函数体内将自动产生临时对象,用于复制该参数a,而临时变量的构造,拷贝构造,析构都将耗费时间。所以为了提高效率可以写成这样void func(A &a)用“引用传递”就不用产生临时对象,如果不想改变参数a就写成void func(const A &a)(2)const修饰函数返回值 1.以“指针传递”方式的函数返回值加上const修饰,那么该函数的返回值的内容不能被修改例如:const char *get_string(void)2.如果函数返回值采用“值传递方式”,由于函数会把返回值复制到外部的临时存储单元中,所以加上const修饰没有意义,例如:int get_number(void)不用写成const int get_number(void)3.但是返回值不是内部数据类型,例如:A get_string(void),这样会产生一个临时的对象用来存放返回的数据,会调用拷贝构造函数,这样效率会低,所以采用“引用传递”A &get_string(void),如果加上const那么返回值的内容就不会被改变const A &get_string(void)(3)const修饰成员函数 1.任何不会修改成员的函数都应该声明为const类型。例如计数函数不会对成员进行修改所以int get_count(void)const;注意const成员函数的声明将const放到函数的尾部。2.const成员函数不可以修改对象的数据。const对象只能访问const成员函数,非const对象可以任意访问任意的成员函数。3.class A{public:int get_count(int)const;}int get_count(int)const准确的说这个const修饰的是this指向的对象,其实
a.const对象只能访问const成员函数,而非const对象可以访问任意的成员函数,包括const成员函数.
b.const对象的成员是不可修改的,然而const对象通过指针维护的对象却是可以修改的.
c.const成员函数不可以修改对象的数据,不管对象是否具有const性质.它在编译时,以是否修改成员数据为依据,进行检查.
e.然而加上mutable修饰符的数据成员,对于任何情况下通过任何手段都可修改,自然此时的const成员函数是可以修改它的
1、const
const int * :指向const对象的指针
1、不能通过该指针来修改对象的值,但是可以使指针指向不同的对象;
2、非const对象的指针不能指向一个const对象;
3、非const对象的地址可以赋给const对象的指针;
int * const:指向非const对象的const指针:不能使该指针指向新的对象,但是可以改变它指向的值;
const int* const
const参数和非const参数,算函数重载;
dynamic_cast: 通常在基类和派生类之间转换时使用,run-time cast
const_cast: 主要针对const和volatile的转换.
static_cast: 一般的转换,no run-time check.通常,如果你不知道该用哪个,就用这个。
reinterpret_cast: 用于进行没有任何关联之间的转换,比如一个字符指针转换为一个整形数。
强制类型转换
1)static_cast<T*>(a)
编译器在编译期处理
将地址a转换成类型T,T和a必须是指针、引用、算术类型或枚举类型。
表达式static_cast<T*>(a), a的值转换为模板中指定的类型T。在运行时转换过程中,不进行类型检查来确保转换的安全性。
static_cast它能在内置的数据类型间互相转换,对于类只能在有联系的指针类型间进行转换。可以在继承体系中把指针转换来、转换去,但是不能转换成继承体系外的一种类型
class A { ... };
class B { ... };
class D : public B { ... };
void f(B* pb, D* pd)
{
D* pd2 = static_cast<D*>(pb); // 不安全, pb可能只是B的指针
B* pb2 = static_cast<B*>(pd); // 安全的
A* pa2 = static_cast<A*>(pb); //错误A与B没有继承关系
...
}
2)dynamic_cast<T*>(a)
在运行期,会检查这个转换是否可能。
完成类层次结构中的提升。T必须是一个指针、引用或无类型的指针。a必须是决定一个指针或引用的表达式。
dynamic_cast 仅能应用于指针或者引用,不支持内置数据类型
表达式dynamic_cast<T*>(a) 将a值转换为类型为T的对象指针。如果类型T不是a的某个基类型,该操作将返回一个空指针。
它不仅仅像static_cast那样,检查转换前后的两个指针是否属于同一个继承树,它还要检查被指针引用的对象的实际类型,确定转换是否可行。
如果可以,它返回一个新指针,甚至计算出为处理多继承的需要的必要的偏移量。如果这两个指针间不能转换,转换就会失败,此时返回空指针(NULL)。
很明显,为了让dynamic_cast能正常工作,必须让编译器支持运行期类型信息(RTTI)。
3)const_cast<T*>(a)
编译器在编译期处理
去掉类型中的常量,除了const或不稳定的变址数,T和a必须是相同的类型。
表达式const_cast<T*>(a)被用于从一个类中去除以下这些属性:const, volatile, 和 __unaligned。
class A { ... };
void f()
{
const A *pa = new A;//const对象
A *pb;//非const对象
//pb = pa; // 这里将出错,不能将const对象指针赋值给非const对象
pb = const_cast<A*>(pa); // 现在OK了
...
}
对于本身定义时为const的类型,即使你去掉const性,在你操作这片内容时候也要小心,只能r不能w操作,否则还是会出错
const char* p = "123";
char* c = const_cast<char*>(p);
c[0] = 1; //表面上通过编译去掉了const性,但是操作其地址时系统依然不允许这么做。
const_cast操作不能在不同的种类间转换。相反,它仅仅把一个它作用的表达式转换成常量。它可以使一个本来不是const类型的数据转换成const类型的,或者把const属性去掉。
尽量不要使用const_cast,如果发现调用自己的函数,竟然使用了const_cast,那就赶紧打住,重新考虑一下设计吧。
4)reinterpret_cast<T*>(a)
编译器在编译期处理
任何指针都可以转换成其它类型的指针,T必须是一个指针、引用、算术类型、指向函数的指针或指向一个类成员的指针。
表达式reinterpret_cast<T*>(a)能够用于诸如char* 到 int*,或者One_class* 到 Unrelated_class*等类似这样的转换,因此可能是不安全的。
class A { ... };
class B { ... };
void f()
{
A* pa = new A;
void* pv = reinterpret_cast<A*>(pa);
// pv 现在指向了一个类型为B的对象,这可能是不安全的
...
}
使用reinterpret_cast 的场合不多,仅在非常必要的情形下,其他类型的强制转换不能满足要求时才使用。
== ===========================================
== static_cast .vs. reinterpret_cast
== ================================================
reinterpret_cast是为了映射到一个完全不同类型的意思,这个关键词在我们需要把类型映射回原有类型时用到它。我们映射到的类型仅仅是为了故弄玄虚和其他目的,这是所有映射中最危险的。(这句话是C++编程思想中的原话)
static_cast 和 reinterpret_cast 操作符修改了操作数类型。它们不是互逆的;
static_cast 在编译时使用类型信息执行转换,在转换执行必要的检测(诸如指针越界计算, 类型检查). 其操作数相对是安全的。
另一方面;reinterpret_cast是C++里的强制类型转换符,操作符修改了操作数类型,但仅仅是重新解释了给出的对象的比特模型而没有进行二进制转换。
例子如下:
int n=9;
double d=static_cast < double > (n);
上面的例子中, 我们将一个变量从 int 转换到 double。这些类型的二进制表达式是不同的。 要将整数 9 转换到 双精度整数 9,static_cast 需要正确地为双精度整数 d 补足比特位。其结果为 9.0。
而reinterpret_cast 的行为却不同:
int n=9;
double d=reinterpret_cast<double & > (n);
这次, 结果有所不同. 在进行计算以后, d 包含无用值. 这是因为 reinterpret_cast 仅仅是复制 n 的比特位到 d, 没有进行必要的分析.
因此, 你需要谨慎使用 reinterpret_cast.
reinterpret_casts的最普通的用途就是在函数指针类型之间进行转换。
例如,假设你有一个函数指针数组:
typedefvoid(*FuncPtr)();//FuncPtr is一个指向函数的指针,该函数没有参数,返回值类型为void
FuncPtrfuncPtrArray[10];//funcPtrArray是一个能容纳10个FuncPtrs指针的数组
让我们假设你希望(因为某些莫名其妙的原因)把一个指向下面函数的指针存入funcPtrArray数组:
int doSomething();
你不能不经过类型转换而直接去做,因为doSomething函数对于funcPtrArray数组来说有一个错误的类型。在FuncPtrArray数组里的函数返回值是void类型,而doSomething函数返回值是int类型。
funcPtrArray[0] = &doSomething;//错误!类型不匹配
reinterpret_cast可以让你迫使编译器以你的方法去看待它们:
funcPtrArray[0] = reinterpret_cast<FuncPtr>(&doSomething);
转换函数指针的代码是不可移植的(C++不保证所有的函数指针都被用一样的方法表示),在一些情况下这样的转换会产生不正确的结果
4.static
存放在静态区
作用域仅局限于本文件
static 修饰成员函数,修饰成员变量,全局变量,局部变量的区别。
在C++中静态成员只关联于类,而和类的具体对象不关联,类静态成员独立于任何一个对象而存在。
特别的静态成员的类型可以是它所在的类,而非静态成员,而对于非静态成员则不行,
非静态成员必须被声明为类对象的指针或者是引用。
static成员函数没有this指针
静态成员函数只能访问静态成员变量和静态成员函数,生存期大于class instance
class Bar
{
public://....
private:static Bar mem1; //OKBar *mem2; //OKBar mem3; //ERROR
};#include <iostream>using namespace std;class test2
{
public:test2(int num) : y(num){}~test2(){}static void testStaticFun(){cout << "y = " << y << endl; //Error:静态成员函数不能访问非静态成员}void testFun(){cout << "x = " << x << endl; }
private:static int x;//静态成员变量的引用性说明int y;
};int test2::x = 10;//静态成员变量的定义性说明int main(void)
{test2 t(100);t.testFun();return 0;
}
#include <iostream>using namespace std;class Test
{
public:Test() : y(1), r(y), d(3){} //对于常量型成员变量和引用型成员变量,必须通过参数化列表的方式进行初始化。~Test(){}int y; //普通变量成员int &r; //引用成员变量const int d; //常量成员变量static int c; //静态成员变量static const int x = 2; //静态常量整型成员变量static const int xx; //静态常量整型成员变量声明static const double z; //静态常量非整型成员变量声明//const static int zz = 6.0; //静态常量非整型成员变量 error
};
const int Test::xx = 4; //静态常量整型成员变量定义
const double Test::z = 5.1; 静态常量非整型成员变量定义
int Test::c = 2;int main(void)
{cout << Test::x << endl; return 0;
}
5.switch
case 后面可以跟变量吗?答:可以跟const修饰的常量,不可跟变量
default的用途? 答:当前面所有case不满足
然后问c++
1.extern的作用
可用于c/c++混写。在别处声明的变量或者c文件(外链接),相当于拷贝到当前文件
原因:c与c++的链接方式和命名规则不同
2.虚函数的了解
3.基类的析构函数是否需要加virtual
要。
4.class和struct 的区别
5.printf如何输出多个参数(不清楚参数的情况下)
6.c语言如何调用c++的函数
extern
linux
1.i/o模型有几种
https://www.cnblogs.com/findumars/p/6361627.html
(1) 阻塞I/O (Blocking I/O)
(2) 非阻塞I/O (Non-Blocking I/O)
(3) I/O复用(I/O Multiplexing)
(4) 信号驱动的I/O (Signal Driven I/O)
(5) 异步I/O (Asynchrnous I/O)
数据结构
1.排序算法有哪些,复杂度是多少
2.最快的查找
3.list和vector的区别
vector和数组类似,拥有一段连续的内存空间,并且起始地址不变。
因此能高效的进行随机存取,时间复杂度为o(1);
但因为内存空间是连续的,所以在进行插入和删除操作时,会造成内存块的拷贝,时间复杂度为o(n)。
另外,当数组中内存空间不够时,会重新申请一块内存空间并进行内存拷贝。
list是由双向链表实现的,因此内存空间是不连续的。
只能通过指针访问数据,所以list的随机存取非常没有效率,时间复杂度为o(n);
但由于链表的特点,能高效地进行插入和删除。
算法
判断一个链表内是否有环(当时有点蒙,这道题去年学长刚从北京回来,因为我替他跑步然后请我吃饭,和我提到过一下,用两个指针,当时不是特别理解,但是没管,于是口胡了一个和当时学长问我时同样的说法,所以面试官没继续问下去了。。。。当时好想说要是换道题我肯定会啊)
问:你会其他的吗,对虚拟化和云计算有了解吗
答:没,现在有在学网络编程
问:tcp和udp的区别
答案链接
问:简单的服务器实现
问:socket参数
问:tcp,udp传递时用的函数
问:有看过unix环境高级编程