iOS面试准备 - ios篇
ios面试准备 - objective-c篇
ios面试准备 - 网络篇
IOS面试准备 - C++篇
iOS面试准备 - 其他篇
引用和指针的区别
1.不存在空引用。引用必须连接到一块合法的内存。
2.一旦引用被初始化为一个对象,就不能被指向到另一个对象。指针可以在任何时候指向到另一个对象。
3.引用必须在创建时被初始化。指针可以在任何时间被初始化。
如何引用一个已经定义过的全局变量?
可以用引用头文件的方式,也可以用extern关键字,如果用引用头文件方式来引用某个在头文件中声明的全局变变量,假定你将那个变量写错了,那么在编译期间会报错,如果你用extern方式引用时,假定你犯了同样的错误,那么在编译期间不会报错,而在连接期间报错。
extern关键字的用法
extern修饰变量的声明:在一个文件中使用另一个文件的全局变量
函数的链接性:默认情况下函数可以在文件间共享。可以使用extern来指出这一点,。从本质上来讲,变量和函数没有区别。使用extern和包含头文件来引用函数有什么区别呢?extern的引用方式比包含头文件要简洁得多!extern的使用方法是直接了当的,想引用哪个函数就用extern声明哪个函数。这样做的一个明显的好处是,会加速程序的编译(确切的说是预处理)的过程,节省时间。
语言的链接性:在C语言中函数是不能重载的。可以使用extern “C”来告诉编译器不要按照C++默认的方式翻译,而使用C的方式翻译。
局部变量和全局变量同名
可以同名,局部变量会覆盖全局变量,如果想在块内使用全局变量需要通过作用域解析运算符::引用
const的用法
用来限定特定变量,以通知编译器该变量是不可修改的
用法:
1.const修饰普通类型的变量
2.const 修饰指针变量:
const 修饰指针指向的内容,则内容为不可变量。
const int *p = 8
const 修饰指针,则指针为不可变量。
int* const p = &a;
*p = 9; // 正确
p = &b; // 错误
const 修饰指针和指针指向的内容,则指针和指针指向的内容都为不可变量。
const int * const p = &a;
3.const参数传递和函数返回值
4.const修饰类成员函数:成员函数里面不能修改全局变量,除非变量用mutable修饰
static关键词作用
(1)在修饰变量的时候,static 修饰的静态局部变量只执行初始化一次,而且延长了局部变量的生命周期,直到程序运行结束以后才释放。
(2)static 修饰全局变量的时候,这个全局变量只能在本文件中访问,不能在其它文件中访问,即便是 extern 外部声明也不可以。
(3)static 修饰一个函数,则这个函数的只能在本文件中调用,不能被其他文件调用。static 修饰的变量存放在全局数据区的静态变量区,包括全局静态变量和局部静态变量,都在全局数据区分配内存。初始化的时候自动初始化为 0。
(4)不想被释放的时候,可以使用static修饰。比如修饰函数中存放在栈空间的数组。如果不想让这个数组在函数调用结束释放可以使用 static 修饰。
内联函数
作用:降低调用少语句的函数的开销。函数调用有开销,如果函数里面语句少,那么可能导致调用函数的时间大于执行函数的时间。
所以可以使用内联,在编译时将函数调用处用函数体替换。这样就没有调用函数的时间了。
缺点:内联是以代码膨胀(复制)为代价,仅仅省去了函数调用的开销,从而提高函数的执行效率。 如果执行函数体内代码的时间,相比于函数调用的开销较大,那么效率的收获会很少。另一方面,每一处内联函数的调用都要复制代码,将使程序的总代码量增大,消耗更多的内存空间。
不使用内联的情况:不能包含复杂的结构控制语句例如 while、switch,代码多,是递归函数。
关键字 inline 必须与函数定义体放在一起才能使函数成为内联,仅将 inline 放在函数声明前面不起任何作用。
定义在类中的成员函数默认都是内联的,如果在类定义时就在类内给出函数定义,那当然最好。如果在类中未给出成员函数定义,而又想内联该函数的话,那在类外要加上 inline,否则就认为不是内联的。
inline 函数仅仅是一个对编译器的建议,所以最后能否真正内联,看编译器的意思
内联函数和宏的区别:
内联函数在编译时展开,宏在预编译时展开;
内联函数直接将函数体内容嵌入到目标代码中,宏是简单的做文本替换;
内联函数有类型检测、语法判断等功能,而宏没有;
inline函数是函数,宏不是;
malloc、calloc、realloc
void* malloc(unsigned size);
在堆内存中分配一块长度为size字节的连续区域,参数size为需要内存空间的长度。(不会初始化内存空间)
void* calloc(size_t numElements, size_t sizeOfElement);
与malloc相似,参数sizeOfElement为单位元素长度(例如:sizeof(int)),numElements为元素个数,即在内存中申请numElements * sizeOfElement字节大小的连续内存空间。(会初始化内存空间)
void* realloc(void* ptr, unsigned newsize);
使用realloc函数为ptr重新分配大小为size的一块内存空间。下面是这个函数的工作流程:
(1),对ptr进行判断,如果ptr为NULL,则函数相当于malloc(new_size),试着分配一块大小为new_size的内存,如果成功将地址返回,否则返回NULL。如果ptr不为NULL,则进入(2)。
(2),查看ptr是不是在堆中,如果不是的话会抛出realloc invalid pointer异常。如果ptr在堆中,则查看new_size大小,如果new_size大小为0,则相当于free(ptr),将ptr指向的内存空间释放掉,返回NULL。如果new_size小于原大小,则ptr中的数据可能会丢失,只有new_size大小的数据会保存;如果size等于原大小,等于什么都没有做;如果size大于原大小,则查看ptr指向的位置还有没有足够的连续内存空间,如果有的话,分配更多的空间不会初始化,返回的地址和ptr相同,如果没有的话,在更大的空间内查找,如果找到size大小的空间,将旧的内容拷贝到新的内存中,把旧的内存释放掉,则返回新地址,否则返回NULL。
虚函数和纯虚函数
定义一个函数为虚函数,不代表函数为不被实现的函数。定义他为虚函数是为了允许用基类的指针来调用子类的这个函数。
定义一个函数为纯虚函数,才代表函数没有被实现。定义纯虚函数是为了实现一个接口,起到一个规范的作用,规范继承这个类的程序员必须实现这个函数。
析构函数是否定义为虚函数的区别
(1)析构函数定义为虚函数时:基类指针可以指向派生类的对象(多态性),如果删除该指针delete []p;就会调用该指针指向的派生类析构函数,而派生类的析构函数又自动调用基类的析构函数,这样整个派生类的对象完全被释放。
(2)析构函数不定义为虚函数时:编译器实施静态绑定,在删除基类指针时,只会调用基类的析构函数而不调用派生类析构函数,这样就会造成派生类对象析构不完全。
socket编程
客户端和服务端共有的函数:
socket函数 ,使用给定的协议族、套接字类型、协议编号(默认为0)来创建套接字。
recv函数:负责从缓冲区中读取内容
send函数:将buf中的n bytes字节内容写入socket描述字。成功时返回写的字节数。失败时返回-1,并设置errno变量
服务端函数:
bind函数 将套接字绑定到地址
listen函数 使服务器的这个端口和IP处于监听状态,等待网络中某一客户机的连接请求。如果
accept函数:接受远程计算机的连接请求,建立起与客户机之间的通信连接。服务器处于监听状态时,如果某时刻获得客户机的连接请求,此时并不是立即处理这个请求,而是将这个请求放在等待队列中,当系统空闲时再处理客户机的连接请求。
客户端函数:
connect 函数 用来请求连接远程服务器.