这家公司虽然是外包外派,但是题目的水平啊不亚于大公司。
上题:
问答题
1 static 关键字的作用?
- static关键字修饰全局变量,该全局变量只能被该模块内的函数访问,不能被模块外的其他函数访问;
- static关键字修饰局部变量,该局部变量被分配到静态存储区,内存只被分配一次,所以下次访该变量时,仍保持上次的值。
- static关键字修饰函数,该函数只能被该模块内的函数所调用,对模块外的其他函数是隐藏的。
- static关键字修饰类的成员变量,该变量属于整个类所拥有,对所有类的对象只有一份拷贝;
- static关键字修饰类的成员函数,该成员函数属于整个类所拥有,并且只能访问static关键字修饰的成员变量。
2.OC的优缺点?
OC的理解与特性
- OC作为一门面向对象的语言,自然具有面向对象的语言特性:封装、继承、多态。它既具有静态语言的特性(如C++),又有动态语言的效率(动态绑定、动态加载等)。总体来讲,OC确实是一门不错的编程语言,
- Objective-C具有相当多的动态特性,表现为三方面:动态类型(Dynamic typing)、动态绑定(Dynamic binding)和动态加载(Dynamic loading)。动态——必须到运行时(run time)才会做的一些事情。
-
动态类型
:即运行时再决定对象的类型,这种动态特性在日常的应用中非常常见,简单来说就是id类型。事实上,由于静态类型的固定性和可预知性,从而使用的更加广泛。静态类型是强类型,而动态类型属于弱类型,运行时决定接受者。 -
动态绑定
:基于动态类型,在某个实例对象被确定后,其类型便被确定了,该对象对应的属性和响应消息也被完全确定。 -
动态加载
:根据需求加载所需要的资源,最基本就是不同机型的适配,例如,在Retina设备上加载@2x的图片,而在老一些的普通苹设备上加载原图,让程序在运行时添加代码模块以及其他资源,用户可根据需要加载一些可执行代码和资源,而不是在启动时就加载所有组件,可执行代码可以含有和程序运行时整合的新类。
3 sprintf, strcpy,memcpy使用上有什么要注意的地方?
strcpy是一个字符串拷贝的函数,它的函数原型为strcpy(char *dst, c*****t char *src);
将 src开始的一段字符串拷贝到dst开始的内存中去,结束的标志符号为'\0',由于拷贝的长度不是由我们自己控制的,所以这个字符串拷贝很容易出错。具备字符串拷贝功能的函数有memcpy,这是一个内存拷贝函数,它的函数原型为memcpy(char dst, c*****t char src, unsigned int len);
将长度为len的一段内存,从src拷贝到dst中去,这个函数的长度可控。但是会有内存叠加的问题。
sprintf是格式化函数。将一段数据通过特定的格式,格式化到一个字符串缓冲区中去。sprintf格式化的函数的长度不可控,有可能格式化后的字符串会超出缓冲区的大小,造成溢出。
4 readwrite,readonly,assign,retain,copy,nonatomic属性的作用?
- readwrite 是可读可写特性;需要生成getter方法和setter方法时(补充:默认属性,将生成不带额外参数的getter和setter方法(setter方法只有一个参数))
- readonly 是只读特性 只会生成getter方法 不会生成setter方法 ;不希望属性在类外改变
- assign 是赋值特性,setter方法将传入参数赋值给实例变量;仅设置变量时;
- retain 表示持有特性,setter方法将传入参数先保留,再赋值,传入参数的retaincount会+1;
- copy 表示拷贝特性,setter方法将传入对象复制一份;需要完全一份新的变量时。
- nonatomic 非原子操作,决定编译器生成的setter getter是否是原子操作,atomic表示多线程安全,一般使用nonatomic。
5 什么时候用delegate,什么时候通知?
区别
-NotificationCenter 通知中心
:“一对多”,在APP中,很多控制器都需要知道一个事件,应该用通知;
-delegate 代理委托
:
1.“一对一”,对同一个协议,一个对象只能设置一个代理delegate,所以单例对象就不能用代理;
2.代理更注重过程信息的传输:比如发起一个网络请求,可能想要知道此时请求是否已经开始、是否收到了数据、数据是否已经接受完成、数据接收失败。
6 frame和bounds有什么不同?
- frame指的是:该view在父view坐标系统中的位置和大小。(参照点是父亲的坐标系统)
- bounds指的是:该view在本身坐标系统中的位置和大小。(参照点是本身坐标系统)
7 是否可以在一个视图控制器里嵌入两个tableView控制器?
- 如果是视图的话,一个视图下当然可以有两个tableView。
- 如果是控制器的话,tabBarController下就可以有多个控制器。
8 堆栈溢出一般是什么原因导致的?
堆和栈的区别
- 栈区(stack)由编译器自动分配释放 ,存放方法(函数)的参数值, 局部变量的值等,栈是向低地址扩展的数据结构,是一块连续的内存的区域。即栈顶的地址和栈的最大容量是系统预先规定好的。
- 堆区(heap)一般由程序员分配释放, 若程序员不释放,程序结束时由OS回收,向高地址扩展的数据结构,是不连续的内存区域,从而堆获得的空间比较灵活。
- 碎片问题:对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块从栈中间弹出.
- 分配方式:堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行释放,无需我们手工实现。
- 分配效率:栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的。
- 全局区(静态区)(static),全局变量和静态变量的存储是放在一块 的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后有系统释放。
- 文字常量区—常量字符串就是放在这里的。程序结束后由系统释放。
- 程序代码区—存放函数体的二进制代码
详细知识请移步堆栈的深入个人理解
9 什么函数不能声明虚函数?(C++内容都有)
** 一.首先回顾下什么是虚函数及其作用,以便更好理解什么函数不 能声明或定义为虚函数**:
- 定义:
虚函数必须是基类的非静态成员函数,其访问权限可以是protected或public,在基类的类定义中定义虚函数的一般形式:
virtual 函数返回值类型 虚函数名(形参表) { 函数体 }
- 作用:
虚函数的作用是实现动态联编,也就是在程序的运行阶段动态地选择合适的成员函数,在定义了虚函数后,可以在基类的派生类中对虚函数重新定义,在派生类中重新定义的函数应与虚函数具有相同的形参个数和形参类型,以实现统一的接口,不同定义过程。如果在派生类中没有对虚函数重新定义,则它继承其基类的虚函数。
当程序发现虚函数名前的关键字virtual后,会自动将其作为动态联编处理,即在程序运行时动态地选择合适的成员函数。 - 使用方法:
动态联编规定,只能通过指向基类的指针或基类对象的引用来调用虚函数,其格式:
指向基类的指针变量名->虚函数名(实参表)
或
基类对象的引用名. 虚函数名(实参表)
- 其它说明:
虚函数是C++多态的一种表现:
例如:子类继承了父类的一个函数(方法),而我们把父类的指针指向子类,则必须把父类的该函数(方法)设为virtual(虚函数)。 使用虚函数,我们可以灵活的进行动态绑定,当然是以一定的开销为代价。 如果父类的函数(方法)根本没有必要或者无法实现,完全要依赖子类去实现的话,可以把此函数(方法)设为virtual 函数名=0 我们把这样的函数(方法)称为纯虚函数。 如果一个类包含了纯虚函数,称此类为抽象类 。
二、什么函数不能声明为虚函数:
一个类中将所有的成员函数都尽可能地设置为虚函数总是有益的。
设置虚函数须注意:
1.只有类的成员函数才能说明为虚函数;
2.静态成员函数不能是虚函数;
3.内联函数不能为虚函数;
4.构造函数不能是虚函数;
5.析构函数可以是虚函数,而且通常声明为虚函数。
类里面“定义”的成员函数是内联的,但是仍然可以成为虚函数,那么是不是可以说“内联函数不能成为虚函数”这句话有问题呢,是不是应该改成“显式定义的内联函数不能成为虚函数”。比如下面这个示例程序:
#include <iostream>
using namespace std;
class Base{
public:
virtual void f1(){cout < < "Father " < <endl;}
};
class Drived1:public Base{
public:
void f1(){cout < < "Son1 " < <endl;}
};
class Drived2:public Base{
public:
void f1(){cout < < "Son2 " < <endl;}
};
void myPrint(Base* pBs){
pBs-> f1();
}
int main() {
Base father;
Drived1 son1;
Drived2 son2;
myPrint(&father);
myPrint(&son1);
myPrint(&son2);
system( "PAUSE ");
return 0;
}
输出:
Father
Son1
Son2
10 冒泡排序的时间复杂度是什么?
上代码:
int a[7] = {10,8,5,27,7,11,90};
int z = 0;
for (int i =0; i < 7-1; i++) {
for(int j =0; j < 7 - 1 - i; j++) {
if (a[j] > a[j +1]) {
z = a[j];
a[j] = a[j +1];
a[j +1] = z;
}
}
}
for(inti =0;i <7;i++){
printf("%d ",a[i]);
}
这不就是O(n^2)吗
11 写出float x与“零值”比较的if语句?
const float EPSINON = 0.00001;
if ((x >= - EPSINON) && (x <= EPSINON)
- 不可将浮点变量用“==”或“!=”与数字比较,应该设法转化成“>=”或“<=”此类形式。
- EPSINON应该是一个很小的值吧 因为计算机在处理浮点数的时候是有误差的,所以判断两个浮点数是不是相同,是要判断是不是落在同一个区间的,这个区间就是 [-EPSINON,EPSINON] EPSINON一般很小,10的-6次方以下吧,具体的好像不确定的,和机器有关。
12 全局变量可不可以定义在可被多个.C文件包含的头文件里?为什么?(C++)
有是C++的题目,真是一脸懵啊!
详细请移步[C/C++]在头文件中使用static定义变量意味着什么
13 do......while和while........do有什么区别?
那就写代码才可以看出来:
do...while语句:
while语句:
- 与上面的do语句不同,while语句会在开始的时候判断控制表达式的值(do语句则在执行完一次循环体内再判断控制表达式的值)。do语句一定会执行一次循环体中的语句,而while语句并不一定会执行循环体内的语句。如果控制表达式的第一次判断结果为0,则循环体中的语句一次也不会执行。
所以:
找错题##
试题1:
void test1()
{
char string[10];
char *str1 = "0123456789";
strcpy(string, str1);
}
类型不一样无法拼接
试题2:
void test2()
{
char string[10], str1;
int i;
for (i = 10; i < 10; i++) {
str1 = 'a';
}
strcpy(string, str1);
}
试题3:
void test3(char *str1)
{
char string[10];
if (strlen(str1) < = 10) {
strcpy(string, str1);
}
}
计算题##
以下为window NT下的32位C++程序,请计算sizeof的值
void Func(char str[100])
{
sizeof(str) = ?
}
void *p = malloc(100);
sizeof(p) = ?
填空题##
编写一个函数,作用是把一个char组成的字符串循环右移n个。比如“abcdefghi”,如果n = 2,移动后应该为“hiabcdefgh”####
函数头应该是这样的:
//pStr是指向以‘\0’结尾字符串的指针
//steps是要求移动的n
void LoopMove(char *pStr, int step)
{
//请补充。。。。
}