2023年iOS程序员面试试题及答案_第1页
2023年iOS程序员面试试题及答案_第2页
2023年iOS程序员面试试题及答案_第3页
2023年iOS程序员面试试题及答案_第4页
2023年iOS程序员面试试题及答案_第5页
已阅读5页,还剩10页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

2023年iOS程序员面试真题及答案一、单项选择题1、如果需要在手动管理内存分配和释放的Xcode项目中引入和编译用ARC风格编写的文件,那么需要在文件的CompilerFlags上添加参数______。

A.-shared

B.-fno-objc-arc

C.-fobjc-arc

D.-dynamic

2、CFSocket使用的是哪种socket?______

A.BSDSocket

B.NSOperationsQueuesocket

C.TCP/IPsocket

D.CFSocket

3、在哪个类中将允许同时使用一个或多个Block?______

A.NSBlock

B.NSConcurrentBlock

C.NSBlockOperation

D.NSConcurrency

4、给定Objective-C字符串:NSString*str=@"Testing123";表达式[strsubstring:5];的结果为______。

A.Testin

B.Test

C.undefined

D.Testi

5、[Foonew]与[[Fooalloc]init]的区别是______。

A.new比alloc+init更快

B.new在Objective-C里不存在

C.new不会初始化一个对象

D.没有区别,是一样的

6、floatx与“零值”比较的if语句为______。

A.if(x==0)

B.if(x<0.00001f)

C.if(fabs(x)<0.00001f)

D.if(x>-0.00001f)

7、函数的局部变量所需存储空间是在______分配的。

A.进程的数据段

B.进程的栈上

C.进程的堆上

D.以上都可以

二、不定项选择题8、在UIViewController类中与模态相关的方法有哪些?______

A.presentViewController:animated:completion

B.dismissViewControllerAnimated:completion

C.addChildViewController

D.removeFromParentViewController

9、Objective-C有哪几种内存管理方法?______

A.MRR(ManualRetainRelease)

B.MRC(ManualReferenceCounting)

C.ARC(AutomaticReferenceCounting)

D.GC(GarbageCollection)

10、在使用浏览器打开一个网页的过程中,浏览器会使用的网络协议包括______。

A.DNS

B.TCP

C.HTTP

D.Telnet

11、下面属于构造散列函数的方法是______。

A.直接定址法

B.数字分析法

C.除留余数法

D.平方取中法

三、简答题12、NSString*obj=[[NSDataalloc]init];,在编译时和运行时分别是什么类型的对象?

13、两个App之间如何互调传值?

14、static关键字的作用是什么?static全局变量与普通全局变量的区别是什么?static局部变量与普通变量的区别是什么?static函数与普通函数的区别是什么?

四、编程题15、给定一个字符串,判断其是否是一个IP地址,例如“”是一个IP地址。

16、实现内存复制函数memcpy。

答案:

一、单项选择题

1、C[解析]

题目需求是MRC和ARC的混合工程,且这里是在非ARC工程中添加指定的ARC文件,具体方法是选中项目中的Targets,然后单击展开BuildPhases下的CompileSources项,可以看到项目中的类文件,双击指定的类文件并在弹出的输入框中输入-fobjc-arc即可单独开启该文件的ARC模式,另外输入-fno-objc-arc指的是单独关闭该文件的ARC模式。

所以,本题的答案为C。2、A[解析]

选项A中的BSDSocket,又称伯克利套接字,是进程间通信的编程接口,位于最底层,在Cocoa框架中位于OS层。一般开发都是在CoreFoundation层以上进行编程的,避免编程过于复杂。

选项B中的NSOperationsQueue是iOS多线程编程中的类,用于定义和添加操作队列,而非网络编程相关。

选项C中的TCP/IP是位于传输层的网络通信协议,建立在socket之上。

选项DCFSocket是使用BSDSocket实现的一个通信通道,是一个网络编程API,用于iOS网络编程中,其中位于Cocoa框架CoreFoundation层的NSNetwork就是基于CFSocket的。使用CFSocket在iOS中进行网络编程时,需要引用以下头文件:

#import<CoreFoundation/CoreFoundation.h>

#include<svs/socket.h>

#include<netinet/in.h>

所以,本题的答案为A。3、C

4、D

5、D

6、C

7、B[解析]

本题考察的是C++内存管理知识。

一个C/C++编译的程序所占用的系统内存一般分为:BBS段、数据段、代码段、堆和栈。如下图所示:

(1)符号启始的区块(BlockStartedbySymbol,BSS)段

BSS段通常指用来存放程序中未初始化的全局数据和静态数据的一块内存区域。BSS段属于静态内存分配,程序结束后静态变量资源由系统自动释放。

(2)数据段(DataSegment)

数据段通常指用来存放程序中已初始化的全局变量的一块内存区域。数据段也属于静态内存分配。因此,BBS段与数据段都属于静态区(全局区)。

(3)代码段(CodeSegment/TextSegment)

代码段有时候也叫文本段,通常指用来存放程序执行代码(包括类成员函数和全局函数以及其他函数代码)的一块内存区域,这部分区域的大小在程序运行前就已经确定,并且内存区域通常是只读,某些架构也允许代码段为可写,即允许修改程序。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量。这个段一般是可以被共享的,比如在Linux操作系统中打开了两个Vi来编辑文本,那么一般来说,这两个Vi是共享一个代码段的。

(4)堆(heap)

堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调用malloc或new等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张),当利用free或delete等函数释放内存时,被释放的内存从堆中被删除(堆被缩减)。堆一般由程序员分配释放,如果程序员自己不释放,在程序结束时,该块内存空间可能会由操作系统回收。需要注意的是,它与数据结构中的堆是两回事,分配方式类似于链表。

(5)栈(stack)

栈上存放的是用户临时创建的局部变量,一般包括函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变量)。除此之外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且等到调用结束后,函数的返回值也会被存放回栈中。栈由编译器自动分配释放,存放函数的参数值、局部变量的值等。其操作方式类似于数据结构中的栈。栈内存分配运算内置于处理器的指令集中,一般使用寄存器来存取,效率很高,但是分配的内存容量有限。

通过上述描述可知,选项B正确。

所以,本题的答案为B。二、不定项选择题

8、AB[解析]

本题考察的是对模态视图方法的理解。

模态方法指视图控制器利用模态跳转到另一个视图控制器的方法,可以带有跳转动画。iOS中UIViewController的两个模态相关方法主要就有选项A和B中的这两个。

所以,本题的答案为A、B。9、ABCD[解析]MRC指手动内存管理;ARC指自动内存管理;GC指垃圾回收,只存在于MacOX开发平台上;MRR是MRC的官方名字。

所以,本题的答案为A、B、C、D。10、ABC[解析]

本题考察的是计算机网络与通信知识。

一般在打开网页的时候,需要在浏览器中输入网址,所以,需要通过网址找到访问资源的IP地址,从而可以把请求发送到对应的机器上,在这个过程中需要域名系统(DomainNameSystem,DNS),它是互联网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便地访问互联网,而不用去记住能够被机器直接读取的IP数串。通过主机名,最终得到该主机名对应的IP地址的过程叫作域名解析。HTTP是用于从Web服务器传输超文本到本地浏览器的传输协议。浏览器与服务器通过HTTP协议进行交互。HTTP是应用层协议,在传输层是通过TCP协议来传输HTTP请求的。telnet是Internet远程登录服务的标准协议和主要方式。它为用户提供了在本地计算机上完成远程主机工作的能力。一般使用方法为通过终端登录到远处主机,所以在浏览器打开网页的过程中用不到。

所以,本题的答案为A、B、C。11、ABCD[解析]

本题考察的是常用的哈希函数的知识。

常用的构造哈希函数的方法有:直接定址法、数字分析法、平方取中法、折叠法、除留余数法和随机数法。以下将分别对这几种方法进行介绍。

1)直接定址法:取关键字或关键字的某个线性函数值为哈希地址。例如:H(key)=a*key+b,其中,a和b为常数。

2)数字分析法:假设关键字是以r为基数(例如:以10为基的十进制数),并且哈希表中可能出现的关键字都是事先知道的,则可取关键字的若干数位组成哈希地址。

3)平方取中法:取关键字平方后的中间几位作为哈希地址。

4)折叠法:将关键字分割成位数相同的几部分,然后取这几部分的叠加和作为哈希地址。

5)除留余数法:取关键字被某个小于或等于哈希表长m的数p除后所得的余数作为哈希地址。(f(key)=keymodp(p≤m),m为散列表长)

6)随机数法:选择一个随机函数,取关键字的随机函数值作为它的哈希地址。

所以,本题的答案为A、B、C、D。三、简答题12、编译时是NSString类型对象,运行时是NSData对象。

13、第一步,给两个需要相互调用的App设置URLSchemes。

第二步,为了适配iOS9及以上系统需要在info.plist中注册LSApplicationQueriesSchemes,并在其中指定需要打开的App的URL。

第三步,使用-(void)openURL:(NSURL*)urloptions:

(NSDictionary*)optionscompletionHandler:(void(^__nullable)(BOOLsuccess))completion方法打开你需要跳转的App。

14、static关键字是C/C++语言中都存在的关键字,它具有以下特性:

1)static全局变量的作用域范围是有限制的,即如果一个变量被声明为静态的,那么该变量可以被模块内所有函数访问,但不能被模块外其他函数访问,它是一个本地的全局变量。而普通全局变量能被其他模块访问。

2)在函数体内,静态变量具有“记忆”功能,即一个被声明为静态的变量在这一函数调用结束后,它的值仍然被保存着,当这个函数下一次被调用的时候,这个静态变量的值仍然是上次调用后的结果(需要注意的是,函数中的静态变量只初始化一次),而函数体内的普通变量没有记忆功能。示例代码如下:

#include<stdio.h>

voidfun1(inti)

{

staticintvalue=i;

printf("%d",++value);

}

voidfun2(inti)

{

intvalue=i;

printf("%d

",++value);

}

intmain()

{

printf("fun1:");

fun1(0);

fun1(4);

fun1(7);

printf("\nfun2:");

fun2(0);

fun2(4);

fun2(7);

return0;

}

程序的运行结果为:

fun1:1

2

3

fun2:1

5

8

分析:函数fun1中把value定义为静态变量,它会在第一次调用的时候初始化为0,由于其具有记忆功能,只会被初始化一次。因此,在调用函数fun1(0)的时候,函数fun1内部的value被初始化为0,语句printf("%d",++value);输出结果为1;当调用函数fun1(4)的时候,语句staticintvalue=i;不会再被执行(只能初始化一次),此时value的值为1,打印语句printf("%d

",++value)的输出结果为2。同理,第三次调用函数fun1(7)时,输出的结果为3。而对于普通变量而言,没有记忆功能,每次被调用的时候都需要初始化。调用fun2函数的时候,value每次都会被初始化为传入的参数,因此每次输出++value的值就是实参+1。

3)如果一个函数被声明为静态的,那么该函数与普通函数的作用域不同,静态函数的作用域仅在本文件中,它只能被这一模块内的其他函数调用,不能被模块外的其他函数调用。也就是说,这个函数被限制在声明它的模块的本地范围内使用。而普通函数可以被其他模块使用。四、编程题15、根据IP地址的特点,题目也就是判断以点号分开的4个数字是否在0~255之间,当然也可以直接使用正则表达式来进行匹配。简单的办法:输入一个字符串,Objective-C中字符串NSString有一个函数可以将字符串分隔开,这里以点号将字符串分成几个数字的字符串,然后转化成整型数字依次判断即可。利用如下知识点可以轻易解决本问题:

NSString*string=@"";

/*以"."分割字符串,得到的数组有"192","168","0"和"2"4个字符串元素*/

NSArray<NSString*>*substringArray=[stringcomponentsSeparatedByString:@"."];

/*字符串转整型对象*/

NSIntegernum=[substringArray[0]integerValue];

16、memcpy函数的功能是从源src所指的内存地址的起始位置开始复制n个字节到目标dest所指的内存地址的起始位置中。

它的函数原型为void*memcpy(void*dest,constvoid*src,size_tn);

这个函数的参数与返回值的类型都是void*,在实现的时候,需要把void*转换成可操作的数据类型来处理。下面首先给出一个简单的实现方式,示例代码如下:

#include<iostream>

usingnamespacestd;

void*mymemcpy1(void*dst,constvoid*src,size_tnum)

{

if(dst==NULL||src==NULL)

returnNULL;

constchar*psrc=(char*)src;

char*pdst=(char*)dst;

while(num-->0)

*pdst++=*psrc++;

returndst;

}

intmain()

{

charsrc[]="abc";

char*dest=newchar[4];

dest=(char*)mymemcpy1(dest,src,4);

printf("%s\n",dest);

delete[]dest;

return0;

}

程序的运行结果为:

Abc

以上这种实现方式显然没有考虑内存重叠的问题,如果源字符串src与目标字符串dst有重叠,那么上述程序将会有意想不到的结果。例如,把main函数换成如下的写法:

intmain()

{

charsrc[]="abc";

char*dest=src+1;

dest=(char*)mymemcpy1(dest,src,4);

printf("%s\n",dest);

return0;

}

此时,程序会有意想不到的结果。

如下图所示:

在上图中,源字符串src与目标字符串dest存在重叠,当复制第一个字符“a”的时候,源字符串src的第二个字符也被修改了(“b”被修改成了“a”),因此,当复制第二个字符的时候已经出错了(本来应该复制的是字符“b”,但实际上复制了字符“a”)。更严重的问题是,在复制第三个字符的时候把源字符串的结束符“\0”也给替换掉了,所以导致在复制第四个字符的时候,应该是复制一个结束符“\0”,但实际上复制了一个字符“a”,这就导致复制后,dest字符是无法确定的,因为无法确定下一个字符“\0”出现的位置。

但是,在调用系统函数memcpy的时候,程序的输出结果依然是abc,说明上面这个程序还不完整,主要是没有考虑内存重叠的问题。处理内存重叠的主要思路为:

1)当源内存的首地址大于目标内存的首地址时,从源内存的首地址开始复制。

2)当源内存的首地址小于目标内存的首地址时,从源内存的首地址加待复制字节的长度的地址开始逆序复制。

下面给出第二种情况的实现示意图。

从图中可以看出,在这种情况下,如果从字符串的结尾开始倒着复制,那么就能得到正确的结果。实现代码如下

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论