1. 程式人生 > >史上最全的iOS面試題及答案

史上最全的iOS面試題及答案

最近在做iOS面試,總結一些實用的面試題以及參考答案,供博友們交流溝通。
可用一些不明確的技術要點引起話題,如:
Multithreading:什麼時候處理多執行緒,幾種方式,優缺點。
Delegate, Notification,KVO, other 優缺點
SDWebImage的原理。實現機制。如何解決TableView卡的問題
block和代理的,通知的區別。block的用法需要注意些什麼。
剩下,就可以根據實際情況適當的問一些細節的問題,來考察開發者對具體應用場景的理解程度和使用程度,具體見下文。
多執行緒、特別是NSOperation 和 GCD 的內部原理。
執行時機制的原理和運用場景。
SDWebImage的原理。實現機制。如何解決TableView卡的問題。
block和代理的,通知的區別。block的用法需要注意些什麼。
strong,weak,retain,assign,copy nomatic 等的區別。
設計模式,mvc,單利,工廠,代理等的應用場景。
單利的寫法。在單利中建立陣列應該注意些什麼。
NSString 的時候用copy和strong的區別。
響應值鏈。
NSTimer 在子執行緒中應該手動建立NSRunLoop ,否則不能迴圈執行。
UIScrollView和NSTimer組合做迴圈廣告圖輪播的時候有一個屬性可以控制當上下滾動tableview的時候廣告輪播圖依然正常滾動。
Xcode最新的自動佈局。。。這個很多公司都用。儘量自學下。
git ,和svn的用法。。。git的幾個命令簡單的記下。。。
友盟報錯可以查到具體某一行的錯誤,原理是什麼。
Instrument 可以檢測 電池的耗電量、和記憶體的消耗。的用法。
動畫CABaseAnimation CAKeyAni…. CATrans….. CAGoup…. 等熟悉。。
ARC的原理。
自己寫過什麼自定義控制元件就最好了。。

__block和__weak修飾符的區別其實是挺明顯的:
1.__block不管是ARC還是MRC模式下都可以使用,可以修飾物件,還可以修飾基本資料型別。
2.__weak只能在ARC模式下使用,也只能修飾物件(NSString),不能修飾基本資料型別(int)。
3.__block物件可以在block中被重新賦值,__weak不可以。

tableView 滑動卡的問題主要是因為:從快取中或者是從本地讀取圖片給UIImage的時候耗費的時間。需要把下面的兩句話放到子執行緒裡面:

NSData *imgData = [NSData dataWithContentsOfURL:[NSURL
URLWithString:app.icon]]; //得到影象資料 UIImage *image = [UIImage imageWithData:imgData];

把UIImage賦值給圖片的時候在主執行緒。
子執行緒不能更新UI 所有的UI跟新都是主執行緒執行了。手指滑動螢幕了。或者螢幕的某個方法執行了。

子執行緒裡面加入NSTimer 的時候需要 手動新增NSRunloop 否則不能迴圈。

單利裡面新增 NSMutableArray 的時候,防止多個地方對它同時便利和修改的話,需要加原子屬性。並且用strong,,,並且寫一個遍歷和修改的方法。加上鎖。 Lock UnLock

__weak ViewController*  weakSelf = self;

GCD裡面用 __weak 防止記憶體釋放不了,迴圈引用。

二、SDWebImage內部實現過程
入口 setImageWithURL:placeholderImage:options: 會先把 placeholderImage 顯示,然後 SDWebImageManager 根據 URL 開始處理圖片。
進入 SDWebImageManager-downloadWithURL:delegate:options:userInfo:,交給 SDImageCache 從快取查詢圖片是否已經下載 queryDiskCacheForKey:delegate:userInfo:.
先從記憶體圖片快取查詢是否有圖片,如果記憶體中已經有圖片快取,SDImageCacheDelegate 回撥 imageCache:didFindImage:forKey:userInfo: 到 SDWebImageManager。
SDWebImageManagerDelegate 回撥 webImageManager:didFinishWithImage: 到 UIImageView+WebCache 等前端展示圖片。
如果記憶體快取中沒有,生成 NSInvocationOperation 新增到佇列開始從硬碟查詢圖片是否已經快取。
根據 URLKey 在硬碟快取目錄下嘗試讀取圖片檔案。這一步是在 NSOperation 進行的操作,所以回主執行緒進行結果回撥 notifyDelegate:。
如果上一操作從硬碟讀取到了圖片,將圖片新增到記憶體快取中(如果空閒記憶體過小,會先清空記憶體快取)。SDImageCacheDelegate 回撥 imageCache:didFindImage:forKey:userInfo:。進而回調展示圖片。
如果從硬碟快取目錄讀取不到圖片,說明所有快取都不存在該圖片,需要下載圖片,回撥 imageCache:didNotFindImageForKey:userInfo:。
共享或重新生成一個下載器 SDWebImageDownloader 開始下載圖片。
圖片下載由 NSURLConnection 來做,實現相關 delegate 來判斷圖片下載中、下載完成和下載失敗。
connection:didReceiveData: 中利用 ImageIO 做了按圖片下載進度載入效果。
connectionDidFinishLoading: 資料下載完成後交給 SDWebImageDecoder 做圖片解碼處理。
圖片解碼處理在一個 NSOperationQueue 完成,不會拖慢主執行緒 UI。如果有需要對下載的圖片進行二次處理,最好也在這裡完成,效率會好很多。
在主執行緒 notifyDelegateOnMainThreadWithInfo: 宣告解碼完成,imageDecoder:didFinishDecodingImage:userInfo: 回撥給 SDWebImageDownloader。
imageDownloader:didFinishWithImage: 回撥給 SDWebImageManager 告知圖片下載完成。
通知所有的 downloadDelegates 下載完成,回撥給需要的地方展示圖片。
將圖片儲存到 SDImageCache 中,記憶體快取和硬碟快取同時儲存。寫檔案到硬碟也在以單獨 NSInvocationOperation 完成,避免拖慢主執行緒。
SDImageCache 在初始化的時候會註冊一些訊息通知,在記憶體警告或退到後臺的時候清理記憶體圖片快取,應用結束的時候清理過期圖片。
SDWI 也提供了 UIButton+WebCache 和 MKAnnotationView+WebCache,方便使用。
SDWebImagePrefetcher 可以預先下載圖片,方便後續使用。
從上面流程可以看出,當你呼叫setImageWithURL:方法的時候,他會自動去給你幹這麼多事,當你需要在某一具體時刻做事情的時候,你可以覆蓋這些方法。比如在下載某個圖片的過程中要響應一個事件,就覆蓋這個方法:

//覆蓋方法,指哪打哪,這個方法是下載imagePath2的時候響應

    SDWebImageManager *manager = [SDWebImageManager sharedManager];



    [manager downloadImageWithURL:imagePath2 options:SDWebImageRetryFailed progress:^(NSInteger receivedSize, NSInteger expectedSize) {



        NSLog(@"顯示當前進度");



    } completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {



        NSLog(@"下載完成");

    }];

對於初級來說,用sd_setImageWithURL:的若干個方法就可以實現很好的圖片快取。

1、常用的方法dispatch_async
為了避免介面在處理耗時的操作時卡死,比如讀取網路資料,IO,資料庫讀寫等,我們會在另外一個執行緒中處理這些操作,然後通知主執行緒更新介面。

用GCD實現這個流程的操作比前面介紹的NSThread NSOperation的方法都要簡單。程式碼框架結構如下:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{  
    // 耗時的操作  
    dispatch_async(dispatch_get_main_queue(), ^{  
        // 更新介面  
    });  
});  

如果這樣還不清晰的話,那我們還是用下載圖片為例子,程式碼如下:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{  
    NSURL * url = [NSURL URLWithString:@"http://avatar.csdn.net/2/C/D/1_totogo2010.jpg"];  
    NSData * data = [[NSData alloc]initWithContentsOfURL:url];  
    UIImage *image = [[UIImage alloc]initWithData:data];  
    if (data != nil) {  
        dispatch_async(dispatch_get_main_queue(), ^{  
            self.imageView.image = image;  
         });  
    }  

是不是程式碼比NSThread NSOperation簡潔很多,而且GCD會自動根據任務在多核處理器上分配資源,優化程式。
系統給每一個應用程式提供了三個concurrent dispatch queues。這三個併發排程佇列是全域性的,它們只有優先順序的不同。因為是全域性的,我們不需要去建立。我們只需要通過使用函式dispath_get_global_queue去得到佇列,如下:

dispatch_queue_t globalQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 

這裡也用到了系統預設就有一個序列佇列main_queue

dispatch_queue_t mainQ = dispatch_get_main_queue();    

雖然dispatch queue是引用計數的物件,但是以上兩個都是全域性的佇列,不用retain或release。

2、dispatch_group_async的使用
dispatch_group_async可以實現監聽一組任務是否完成,完成後得到通知執行其他的操作。這個方法很有用,比如你執行三個下載任務,當三個任務都下載完成後你才通知介面說完成的了。下面是一段例子程式碼:

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);  
dispatch_group_t group = dispatch_group_create();  
dispatch_group_async(group, queue, ^{  
    [NSThread sleepForTimeInterval:1];  
    NSLog(@"group1");  
});  
dispatch_group_async(group, queue, ^{  
    [NSThread sleepForTimeInterval:2];  
    NSLog(@"group2");  
});  
dispatch_group_async(group, queue, ^{  
    [NSThread sleepForTimeInterval:3];  
    NSLog(@"group3");  
});  
dispatch_group_notify(group, dispatch_get_main_queue(), ^{  
    NSLog(@"updateUi");  
});  

dispatch_group_async是非同步的方法,執行後可以看到列印結果:

2012-09-25 16:04:16.737 gcdTest[43328:11303] group1
2012-09-25 16:04:17.738 gcdTest[43328:12a1b] group2
2012-09-25 16:04:18.738 gcdTest[43328:13003] group3
2012-09-25 16:04:18.739 gcdTest[43328:f803] updateUi

每個一秒列印一個,當第三個任務執行後,upadteUi被列印。

3、dispatch_barrier_async的使用
dispatch_barrier_async是在前面的任務執行結束後它才執行,而且它後面的任務等它執行完成之後才會執行

例子程式碼如下:

dispatch_queue_t queue = dispatch_queue_create("gcdtest.rongfzh.yc", DISPATCH_QUEUE_CONCURRENT);  
dispatch_async(queue, ^{  
    [NSThread sleepForTimeInterval:2];  
    NSLog(@"dispatch_async1");  
});  
dispatch_async(queue, ^{  
    [NSThread sleepForTimeInterval:4];  
    NSLog(@"dispatch_async2");  
});  
dispatch_barrier_async(queue, ^{  
    NSLog(@"dispatch_barrier_async");  
    [NSThread sleepForTimeInterval:4];  

});  
dispatch_async(queue, ^{  
    [NSThread sleepForTimeInterval:1];  
    NSLog(@"dispatch_async3");  
});  

列印結果:

2012-09-25 16:20:33.967 gcdTest[45547:11203] dispatch_async1

2012-09-25 16:20:35.967 gcdTest[45547:11303] dispatch_async2

2012-09-25 16:20:35.967 gcdTest[45547:11303] dispatch_barrier_async

2012-09-25 16:20:40.970 gcdTest[45547:11303] dispatch_async3

請注意執行的時間,可以看到執行的順序如上所述。

4、dispatch_apply
執行某個程式碼片段N次。
dispatch_apply(5, globalQ, ^(size_t index) {
// 執行5次

});

copy與retain:
1、copy其實是建立了一個相同的物件,而retain不是;
2、copy是內容拷貝,retain是指標拷貝;
3、copy是內容的拷貝 ,對於像NSString,的確是這樣,但是如果copy的是一個NSArray呢?這時只是copy了指向array中相對應元素的指標.這便是所謂的”淺複製”.
4、copy的情況:NSString *newPt = [pt copy];
此時會在堆上重新開闢一段記憶體存放@”abc” 比如0X1122 內容為@”abc 同時會在棧上為newPt分配空間 比如地址:0Xaacc 內容為0X1122 因此retainCount增加1供newPt來管理0X1122這段記憶體;
assign與retain:
1、assign: 簡單賦值,不更改索引計數;
2、assign的情況:NSString *newPt = [pt assing];
此時newPt和pt完全相同 地址都是0Xaaaa 內容為0X1111 即newPt只是pt的別名,對任何一個操作就等於對另一個操作, 因此retainCount不需要增加;
3、assign就是直接賦值;
4、retain使用了引用計數,retain引起引用計數加1, release引起引用計數減1,當引用計數為0時,dealloc函式被呼叫,記憶體被回收;
5、retain的情況:NSString *newPt = [pt retain];
此時newPt的地址不再為0Xaaaa,可能為0Xaabb 但是內容依然為0X1111。 因此newPt 和 pt 都可以管理”abc”所在的記憶體,因此 retainCount需要增加1 ;
readonly:
1、屬性是隻讀的,預設的標記是讀寫,如果你指定了只讀,在@implementation中只需要一個讀取器。或者如果你使用@synthesize關鍵字,也是有讀取器方法被解析
readwrite:
1、說明屬性會被當成讀寫的,這也是預設屬性。設定器和讀取器都需要在@implementation中實現。如果使用@synthesize關鍵字,讀取器和設定器都會被解析;
nonatomic:
1、非原子性訪問,對屬性賦值的時候不加鎖,多執行緒併發訪問會提高效能。如果不加此屬性,則預設是兩個訪問方法都為原子型事務訪問;
weak and strong property (強引用和弱引用的區別):
1、 weak 和 strong 屬性只有在你開啟ARC時才會被要求使用,這時你是不能使用retain release autorelease 操作的,因為ARC會自動為你做好這些操作,但是你需要在物件屬性上使用weak 和strong,其中strong就相當於retain屬性,而weak相當於assign。
2、只有一種情況你需要使用weak(預設是strong),就是為了避免retain cycles(就是父類中含有子類{父類retain了子類},子類中又呼叫了父類{子類又retain了父類},這樣都無法release)
3、宣告為weak的指標,指標指向的地址一旦被釋放,這些指標都將被賦值為nil。這樣的好處能有效的防止野指標。
ARC(Automatic Reference Counting):
1、就是程式碼中自動加入了retain/release,原先需要手動新增的用來處理記憶體管理的引用計數的程式碼可以自動地由編譯器完成了。
該機能在 iOS 5/ Mac OS X 10.7 開始匯入,利用 Xcode4.2 以後可以使用該特性。
strong,weak,copy 具體用法:
1.具體一點:IBOutlet可以為weak,NSString為copy,Delegate一般為weak,其他的看情況。一般來說,類“內部”的屬性設定為strong,類“外部”的屬性設定為weak。說到底就是一個歸屬權的問題。小心出現迴圈引用導致記憶體無法釋放。
2.不用ARC的話就會看到很多retian。
3.如果你寫了@synthesize abc = _abc;的話,系統自動幫你聲明瞭一個_abc的例項變數。
使用assign: 對基礎資料型別 (NSInteger)和C資料型別(int, float, double, char,等)
使用copy: 對NSString

使用retain: 對其他NSObject和其子類

1.寫一個NSString類的實現
+ (id)initWithCString:(c*****t char *)nullTerminatedCString encoding:(NSStringEncoding)encoding;
+ (id) stringWithCString: (c*****t char*)nullTerminatedCString
encoding: (NSStringEncoding)encoding
{
NSString *obj;
obj = [self allocWithZone: NSDefaultMallocZone()];
obj = [obj initWithCString: nullTerminatedCString encoding: encoding];
return AUTORELEASE(obj);
}
2static 關鍵字的作用:
(1)函式體內 static 變數的作用範圍為該函式體,不同於 auto 變數,該變數的記憶體只被分配一次,
因此其值在下次呼叫時仍維持上次的值;
(2)在模組內的 static 全域性變數可以被模組內所用函式訪問,但不能被模組外其它函式訪問;
(3)在模組內的 static 函式只可被這一模組內的其它函式呼叫,這個函式的使用範圍被限制在宣告
它的模組內;
(4)在類中的 static 成員變數屬於整個類所擁有,對類的所有物件只有一份拷貝;
(5)在類中的 static 成員函式屬於整個類所擁有,這個函式不接收 this 指標,因而只能訪問類的static 成員變數。
3執行緒與程序的區別和聯絡?
程序和執行緒都是由作業系統所體會的程式執行的基本單元,系統利用該基本單元實現系統對應用的併發性。
程和執行緒的主要差別在於它們是不同的作業系統資源管理方式。程序有獨立的地址空間,一個程序崩潰後,在保護模式下不會對其它程序產生影響,而執行緒只是一個程序中的不同執行路徑。執行緒有自己的堆疊和區域性變數,但執行緒之間沒有單獨的地址空間,一個執行緒死掉就等於整個程序死掉,所以多程序的程式要比多執行緒的程式健壯,但在程序切換時,耗費資源較大,效率要差一些。但對於一些要求同時進行並且又要共享某些變數的併發操作,只能用執行緒,不能用程序。
4堆和棧的區別
管理方式:對於棧來講,是由編譯器自動管理,無需我們手工控制;對於堆來說,釋放工作由程式設計師控制,容易產生memory leak。
申請大小:
棧:在Windows下,棧是向低地址擴充套件的資料結構,是一塊連續的記憶體的區域。這句話的意思是棧頂的地址和棧的最大容量是系統預先規定好的,在 WINDOWS下,棧的大小是2M(也有的說是1M,總之是一個編譯時就確定的常數),如果申請的空間超過棧的剩餘空間時,將提示overflow。因此,能從棧獲得的空間較小。
堆:堆是向高地址擴充套件的資料結構,是不連續的記憶體區域。這是由於系統是用連結串列來儲存的空閒記憶體地址的,自然是不連續的,而連結串列的遍歷方向是由低地址向高地址。堆的大小受限於計算機系統中有效的虛擬記憶體。由此可見,堆獲得的空間比較靈活,也比較大。
碎片問題:對於堆來講,頻繁的new/delete勢必會造成記憶體空間的不連續,從而造成大量的碎片,使程式效率降低。對於棧來講,則不會存在這個問題,因為棧是先進後出的佇列,他們是如此的一一對應,以至於永遠都不可能有一個記憶體塊從棧中間彈出
分配方式:堆都是動態分配的,沒有靜態分配的堆。棧有2種分配方式:靜態分配和動態分配。靜態分配是編譯器完成的,比如區域性變數的分配。動態分配由alloca函式進行分配,但是棧的動態分配和堆是不同的,他的動態分配是由編譯器進行釋放,無需我們手工實現。
分配效率:棧是機器系統提供的資料結構,計算機會在底層對棧提供支援:分配專門的暫存器存放棧的地址,壓棧出棧都有專門的指令執行,這就決定了棧的效率比較高。堆則是C/C++函式庫提供的,它的機制是很複雜的。
5什麼是鍵-值,鍵路徑是什麼
模型的性質是通過一個簡單的鍵(通常是個字串)來指定的。檢視和控制器通過鍵來查詢相應的屬性值。在一個給定的實體中,同一個屬性的所有值具有相同的資料型別。鍵-值編碼技術用於進行這樣的查詢—它是一種間接訪問物件屬性的機制。
鍵路徑是一個由用點作分隔符的鍵組成的字串,用於指定一個連線在一起的物件性質序列。第一個鍵的
性質是由先前的性質決定的,接下來每個鍵的值也是相對於其前面的性質。鍵路徑使您可以以獨立於模型
實現的方式指定相關物件的性質。通過鍵路徑,您可以指定物件圖中的一個任意深度的路徑,使其指向相
關物件的特定屬性。
6目標-動作機制

目標是動作訊息的接收者。一個控制元件,或者更為常見的是它的單元,以插座變數(參見”插座變數”部分)
的形式保有其動作訊息的目標。
動作是控制元件傳送給目標的訊息,或者從目標的角度看,它是目標為了響應動作而實現的方法。
程式需要某些機制來進行事件和指令的翻譯。這個機制就是目標-動作機制。
7objc的記憶體管理
?? 如果您通過分配和初始化(比如[[MyClass alloc] init])的方式來建立物件,您就擁
有這個物件,需要負責該物件的釋放。這個規則在使用NSObject的便利方法new 時也同樣適用。
?? 如果您拷貝一個物件,您也擁有拷貝得到的物件,需要負責該物件的釋放。
?? 如果您保持一個物件,您就部分擁有這個物件,需要在不再使用時釋放該物件。
反過來,
?? 如果您從其它物件那裡接收到一個物件,則您不擁有該物件,也不應該釋放它(這個規則有少數
的例外,在參考文件中有顯式的說明)。
8 自動釋放池是什麼,如何工作
當您向一個物件傳送一個autorelease訊息時,Cocoa就會將該物件的一個引用放入到最新的自動釋放池。它仍然是個正當的物件,因此自動釋放池定義的作用域內的其它物件可以向它傳送訊息。當程式執行到作用域結束的位置時,自動釋放池就會被釋放,池中的所有物件也就被釋放。
1. ojc-c 是通過一種”referring counting”(引用計數)的方式來管理記憶體的, 物件在開始分配記憶體(alloc)的時候引用計數為一,以後每當碰到有copy,retain的時候引用計數都會加一, 每當碰到release和autorelease的時候引用計數就會減一,如果此物件的計數變為了0, 就會被系統銷燬.
2. NSAutoreleasePool 就是用來做引用計數的管理工作的,這個東西一般不用你管的.
3. autorelease和release沒什麼區別,只是引用計數減一的時機不同而已,autorelease會在物件的使用真正結束的時候才做引用計數減一.
9類工廠方法是什麼
類工廠方法的實現是為了向客戶提供方便,它們將分配和初始化合在一個步驟中,返回被建立的物件,並
進行自動釋放處理。這些方法的形式是+ (type)className…(其中 className不包括任何字首)。
工廠方法可能不僅僅為了方便使用。它們不但可以將分配和初始化合在一起,還可以為初始化過程提供對
象的分配資訊。
類工廠方法的另一個目的是使類(比如NSWorkspace)提供單件例項。雖然init…方法可以確認一
個類在每次程式執行過程只存在一個例項,但它需要首先分配一個“生的”例項,然後還必須釋放該例項。
工廠方法則可以避免為可能沒有用的物件盲目分配記憶體。
10單件例項是什麼
Foundation 和 Application Kit 框架中的一些類只允許建立單件物件,即這些類在當前程序中的唯一例項。舉例來說,NSFileManager 和NSWorkspace 類在使用時都是基於程序進行單件物件的例項化。當向這些類請求例項的時候,它們會向您傳遞單一例項的一個引用,如果該例項還不存在,則首先進行例項的分配和初始化。單件物件充當控制中心的角色,負責指引或協調類的各種服務。如果類在概念上只有一個例項(比如
NSWorkspace),就應該產生一個單件例項,而不是多個例項;如果將來某一天可能有多個例項,您可
以使用單件例項機制,而不是工廠方法或函式。
11動態繫結
—在執行時確定要呼叫的方法

動態繫結將呼叫方法的確定也推遲到執行時。在編譯時,方法的呼叫並不和程式碼繫結在一起,只有在消實發送出來之後,才確定被呼叫的程式碼。通過動態型別和動態繫結技術,您的程式碼每次執行都可以得到不同的結果。執行時因子負責確定訊息的接收者和被呼叫的方法。執行時的訊息分發機制為動態繫結提供支援。當您向一個動態型別確定了的物件傳送訊息時,執行環境系統會通過接收者的isa指標定位物件的類,並以此為起點確定被呼叫的方法,方法和訊息是動態繫結的。而且,您不必在Objective-C 程式碼中做任何工作,就可以自動獲取動態繫結的好處。您在每次傳送訊息時,

特別是當訊息的接收者是動態型別已經確定的物件時,動態繫結就會例行而透明地發生。
12obj-c的優缺點
objc優點:
1) Cateogies
2) Posing
3) 動態識別
4) 指標計算
5)彈性訊息傳遞
6) 不是一個過度複雜的 C 衍生語言
7) Objective-C 與 C++ 可混合程式設計
缺點:
1) 不支援名稱空間
2) 不支援運算子過載
3)不支援多重繼承
4)使用動態執行時型別,所有的方法都是函式呼叫,所以很多編譯時優化方法都用不到。(如行內函數等),效能低劣。
13sprintf,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格式化的函式的長度不可控,有可能格式化後的字串會超出緩衝區的大小,造成溢位。
14答案是:
a) int a; // An integer
b) int *a; // A pointer to an integer
c) int **a; // A pointer to a pointer to an integer
d) int a[10]; // An array of 10 integers
e) int *a[10]; // An array of 10 pointers to integers
f) int (*a)[10]; // A pointer to an array of 10 integers
g) int (*a)(int); // A pointer to a function a that takes an integer argument and returns an integer
h) int (a[10])(int); // An array of 10 pointers to functi**** that take an integer argument and return an integer
15.readwrite,readonly,assign,retain,copy,nonatomic屬性的作用
@property是一個屬性訪問宣告,擴號內支援以下幾個屬性:
1,getter=getterName,setter=setterName,設定setter與getter的方法名
2,readwrite,readonly,設定可供訪問級別
2,assign,setter方法直接賦值,不進行任何retain操作,為了解決原型別與環循引用問題
3,retain,setter方法對引數進行release舊值再retain新值,所有實現都是這個順序(CC上有相關資料)
4,copy,setter方法進行Copy操作,與retain處理流程一樣,先舊值release,再Copy出新的物件,retainCount為1。這是為了減少對上下文的依賴而引入的機制。
copy是在你不希望a和b共享一塊記憶體時會使用到。a和b各自有自己的記憶體。
5,nonatomic,非原子性訪問,不加同步,多執行緒併發訪問會提高效能。注意,如果不加此屬性,則預設是兩個訪問方法都為原子型事務訪問。鎖被加到所屬物件例項級(我是這麼理解的…)。
atomic和nonatomic用來決定編譯器生成的getter和setter是否為原子操作。在多執行緒環境下,原子操作是必要的,否則有可能引起錯 誤的結果。加了atomic,setter函式會變成下面這樣:
16什麼時候用delegate,什麼時候用Notification?答:delegate針對one-to-one關係,並且reciever可以返回值 給sender,notification 可以針對one-to-one/many/none,reciever無法返回值給sender.所以,delegate用於sender希望接受到 reciever的某個功能反饋值,notification用於通知多個object某個事件。
17什麼是KVC和KVO?答:KVC(Key-Value-Coding)內部的實現:一個物件在呼叫setValue的時候,(1)首先根據方法名找到執行方法的時候所需要的環境引數。(2)他會從自己isa指標結合環境引數,找到具體的方法實現的介面。(3)再直接查詢得來的具體的方法實現。KVO(Key-Value- Observing):當觀察者為一個物件的屬性進行了註冊,被觀察物件的isa指標被修改的時候,isa指標就會指向一箇中間類,而不是真實的類。所以 isa指標其實不需要指向例項物件真實的類。所以我們的程式最好不要依賴於isa指標。在呼叫類的方法的時候,最好要明確物件例項的類名
18ViewController 的 loadView, viewDidLoad, viewDidUnload 分別是在什麼時候呼叫的?在自定義ViewController的時候這幾個函式裡面應該做什麼工作?答:viewDidLoad在view 從nib檔案初始化時呼叫,loadView在controller的view為nil時呼叫。此方法在程式設計實現view時呼叫,view 控制器預設會註冊memory warning notification,當view controller的任何view 沒有用的時候,viewDidUnload會被呼叫,在這裡實現將retain 的view release,如果是retain的IBOutlet view 屬性則不要在這裡release,IBOutlet會負責release 。
19
“NSMutableString *”這個資料型別則是代表”NSMutableString”物件本身,這兩者是有區別的。
而NSString只是物件的指標而已。
面向過程就是分析出解決問題所需要的步驟,然後用函式把這些步驟一步一步實現,使用的時候一個一個依次呼叫就可以了。
面向物件是把構成問題事務分解成各個物件,建立物件的目的不是為了完成一個步驟,而是為了描敘某個事物在整個解決問題的步驟中的行為。;
20類別的作用
類別主要有3個作用:
(1)將類的實現分散到多個不同檔案或多個不同框架中。
(2)建立對私有方法的前向引用。
(3)向物件新增非正式協議。
類別的侷限性
有兩方面侷限性:
(1)無法向類中新增新的例項變數,類別沒有位置容納例項變數。
(2)名稱衝突,即當類別中的方法與原始類方法名稱衝突時,類別具有更高的優先順序。類別方法將完全取代初始方法從而無法再使用初始方法。
無法新增例項變數的侷限可以使用字典物件解決
21關鍵字volatile有什麼含意?並給出三個不同的例子:
一個定義為volatile的變數是說這變數可能會被意想不到地改變,這樣,編譯器就不會去假設這個變數的值了。精確地說就是,優化器在用到
這個變數時必須每次都小心地重新讀取這個變數的值,而不是使用儲存在暫存器裡的備份。下面是volatile變數的幾個例子:
• 並行裝置的硬體暫存器(如:狀態暫存器)
• 一箇中斷服務子程式中會訪問到的非自動變數(Non-automatic variables)
• 多執行緒應用中被幾個任務共享的變數

• 一個引數既可以是const還可以是volatile嗎?解釋為什麼。
• 一個指標可以是volatile 嗎?解釋為什麼。

下面是答案:
• 是的。一個例子是隻讀的狀態暫存器。它是volatile因為它可能被意想不到地改變。它是const因為程式不應該試圖去修改它。
• 是的。儘管這並不很常見。一個例子是當一箇中服務子程式修該一個指向一個buffer的指標時。
[email protected] 是系統自動生成getter和setter屬性宣告
@dynamic 是開發者自已提供相應的屬性宣告
@dynamic 意思是由開發人員提供相應的程式碼:對於只讀屬性需要提供 setter,對於讀寫屬性需要提供 setter 和 getter。@synthesize 意思是,除非開發人員已經做了,否則由編譯器生成相應的程式碼,以滿足屬性宣告。
查閱了一些資料確定@dynamic的意思是告訴編譯器,屬性的獲取與賦值方法由使用者自己實現, 不自動生成。

23Difference between shallow copy and deep copy?
淺複製和深複製的區別?
答案:淺層複製:只複製指向物件的指標,而不復制引用物件本身。
深層複製:複製引用物件本身。
意思就是說我有個A物件,複製一份後得到A_copy物件後,對於淺複製來說,A和A_copy指向的是同一個記憶體資源,複製的只不過是是一個指標,物件本身資源
還是隻有一份,那如果我們對A_copy執行了修改操作,那麼發現A引用的物件同樣被修改,這其實違背了我們複製拷貝的一個思想。深複製就好理解了,記憶體中存在了
兩份獨立物件本身。
用網上一哥們通俗的話將就是:
淺複製好比你和你的影子,你完蛋,你的影子也完蛋
深複製好比你和你的克隆人,你完蛋,你的克隆人還活著。
24What is advantage of categories? What is difference between implementing a category and inheritance?
類別的作用?繼承和類別在實現中有何區別?
答案:category 可以在不獲悉,不改變原來程式碼的情況下往裡面新增新的方法,只能新增,不能刪除修改。
並且如果類別和原來類中的方法產生名稱衝突,則類別將覆蓋原來的方法,因為類別具有更高的優先順序。
類別主要有3個作用:
(1)將類的實現分散到多個不同檔案或多個不同框架中。
(2)建立對私有方法的前向引用。
(3)向物件新增非正式協議。
繼承可以增加,修改或者刪除方法,並且可以增加屬性。
25.Difference between categories and extensions?
類別和類擴充套件的區別。
答案:category和extensions的不同在於 後者可以新增屬性。另外後者新增的方法是必須要實現的。
extensions可以認為是一個私有的Category。
26.Difference between protocol in objective c and interfaces in java?
oc中的協議和java中的介面概念有何不同?
答案:OC中的代理有2層含義,官方定義為 formal和informal protocol。前者和Java介面一樣。
informal protocol中的方法屬於設計模式考慮範疇,不是必須實現的,但是如果有實現,就會改變類的屬性。
其實關於正式協議,類別和非正式協議我很早前學習的時候大致看過,也寫在了學習教程裡
“非正式協議概念其實就是類別的另一種表達方式“這裡有一些你可能希望實現的方法,你可以使用他們更好的完成工作”。
這個意思是,這些是可選的。比如我門要一個更好的方法,我們就會申明一個這樣的類別去實現。然後你在後期可以直接使用這些更好的方法。
這麼看,總覺得類別這玩意兒有點像協議的可選協議。”
現在來看,其實protocal已經開始對兩者都統一和規範起來操作,因為資料中說“非正式協議使用interface修飾“,
現在我們看到協議中兩個修飾詞:“必須實現(@requied)”和“可選實現(@optional)”。
26What are KVO and KVC?
答案:kvc:鍵 - 值編碼是一種間接訪問物件的屬性使用字串來標識屬性,而不是通過呼叫存取方法,直接或通過例項變數訪問的機制。
很多情況下可以簡化程式程式碼。apple文件其實給了一個很好的例子。
kvo:鍵值觀察機制,他提供了觀察某一屬性變化的方法,極大的簡化了程式碼。
具體用看到嗯哼用到過的一個地方是對於按鈕點選變化狀態的的監控。
比如我自定義的一個button
[cpp]
[self addObserver:self forKeyPath:@”highlighted” options:0 context:nil];

pragma mark KVO

  • (void)observeValueForKeyPath:(NSString )keyPath ofObject:(id)object change:(NSDictionary )change context:(void *)context
    {
    if ([keyPath isEqualToString:@”highlighted”] ) {
    [self setNeedsDisplay];
    }
    }
    對於系統是根據keypath去取的到相應的值發生改變,理論上來說是和kvc機制的道理是一樣的。
    對於kvc機制如何通過key尋找到value:
    “當通過KVC呼叫物件時,比如:[self valueForKey:@”someKey”]時,程式會自動試圖通過幾種不同的方式解析這個呼叫。首先查詢物件是否帶有 someKey 這個方法,如果沒找到,會繼續查詢物件是否帶有someKey這個例項變數(iVar),如果還沒有找到,程式會繼續試圖呼叫 -(id) valueForUndefinedKey:這個方法。如果這個方法還是沒有被實現的話,程式會丟擲一個NSUndefinedKeyException異常錯誤。
    (cocoachina.com注:Key-Value Coding查詢方法的時候,不僅僅會查詢someKey這個方法,還會查詢getsomeKey這個方法,前面加一個get,或者_someKey以及_getsomeKey這幾種形式。同時,查詢例項變數的時候也會不僅僅查詢someKey這個變數,也會查詢_someKey這個變數是否存在。)
    設計valueForUndefinedKey:方法的主要目的是當你使用-(id)valueForKey方法從物件中請求值時,物件能夠在錯誤發生前,有最後的機會響應這個請求。這樣做有很多好處,下面的兩個例子說明了這樣做的好處。“
    來至cocoa,這個說法應該挺有道理。
    因為我們知道button卻是存在一個highlighted例項變數.因此為何上面我們只是add一個相關的keypath就行了,

27What is purpose of delegates?
代理的作用?
答案:代理的目的是改變或傳遞控制鏈。允許一個類在某些特定時刻通知到其他類,而不需要獲取到那些類的指標。可以減少框架複雜度。
另外一點,代理可以理解為java中的回撥監聽機制的一種類似。

28What are mutable and immutable types in Objective C?
oc中可修改和不可以修改型別。
答案:可修改不可修改的集合類。這個我個人簡單理解就是可動態新增修改和不可動態新增修改一樣。
比如NSArray和NSMutableArray。前者在初始化後的記憶體控制元件就是固定不可變的,後者可以新增等,可以動態申請新的記憶體空間

29When we call objective c is runtime language what does it mean?
我們說的oc是動態執行時語言是什麼意思?
答案:多型。主要是將資料型別的確定由編譯時,推遲到了執行時。
這個問題其實淺涉及到兩個概念,執行時和多型。
簡單來說,執行時機制使我們直到執行時才去決定一個物件的類別,以及呼叫該類別物件指定方法。
多型:不同物件以自己的方式響應相同的訊息的能力叫做多型。意思就是假設生物類(life)都用有一個相同的方法-eat;
那人類屬於生物,豬也屬於生物,都繼承了life後,實現各自的eat,但是呼叫是我們只需呼叫各自的eat方法。
也就是不同的物件以自己的方式響應了相同的訊息(響應了eat這個選擇器)。
因此也可以說,執行時機制是多型的基礎?~~~

30what is difference between NSNotification and protocol?
通知和協議的不同之處?
答案:協議有控制鏈(has-a)的關係,通知沒有。
首先我一開始也不太明白,什麼叫控制鏈(專業術語了~)。但是簡單分析下通知和代理的行為模式,我們大致可以有自己的理解
簡單來說,通知的話,它可以一對多,一條訊息可以傳送給多個訊息接受者。
代理按我們的理解,到不是直接說不能一對多,比如我們知道的明星經濟代理人,很多時候一個經濟人負責好幾個明星的事務。
只是對於不同明星間,代理的事物物件都是不一樣的,一一對應,不可能說明天要處理A明星要一個釋出會,代理人發出處理髮佈會的訊息後,別稱B的
釋出會了。但是通知就不一樣,他只關心發出通知,而不關心多少接收到感興趣要處理。
因此控制鏈(has-a從英語單詞大致可以看出,單一擁有和可控制的對應關係。

31What is push notification?
什麼是推送訊息?
答案:太簡單,不作答~~~~~~
這是cocoa上的答案。
其實到不是說太簡單,只是太泛泛的一個概念的東西。就好比說,什麼是人。
推送通知更是一種技術。
簡單點就是客戶端獲取資源的一種手段。
普通情況下,都是客戶端主動的pull。
推送則是伺服器端主動push。

32.Polymorphism?
關於多型性
答案:多型,子類指標可以賦值給父類。
這個題目其實可以出到一切面向物件語言中,
因此關於多型,繼承和封裝基本最好都有個自我意識的理解,也並非一定要把書上資料上寫的能背出來。
最重要的是轉化成自我理解。

33

What is responder chain?
說說響應鏈
答案:事件響應鏈。包括點選事件,畫面重新整理事件等。在檢視棧內從上至下,或者從下之上傳播。
可以說點事件的分發,傳遞以及處理。具體可以去看下touch事件這塊。因為問的太抽象化了
嚴重懷疑題目出到越後面就越籠統。

34Difference between frame and bounds?
frame和bounds有什麼不同?
答案:frame指的是:該view在父view座標系統中的位置和大小。(參照點是父親的座標系統)
bounds指的是:該view在本身座標系統中 的位置和大小。(參照點是本身座標系統)

35

.Difference between method and selector?
方法和選擇器有何不同?
答案:selector是一個方法的名字,method是一個組合體,包含了名字和實現.

36NSOperation queue?
答案:存放NSOperation的集合類。
操作和操作佇列,基本可以看成java中的執行緒和執行緒池的概念。用於處理ios多執行緒開發的問題。
網上部分資料提到一點是,雖然是queue,但是卻並不是帶有佇列的概念,放入的操作並非是按照嚴格的先進現出。
這邊又有個疑點是,對於佇列來說,先進先出的概念是Afunc新增進佇列,Bfunc緊跟著也進入佇列,Afunc先執行這個是必然的,
但是Bfunc是等Afunc完全操作完以後,B才開始啟動並且執行,因此佇列的概念離亂上有點違背了多執行緒處理這個概念。
但是轉念一想其實可以參考銀行的取票和叫號系統。
因此對於A比B先排隊取票但是B率先執行完操作,我們亦然可以感性認為這還是一個佇列。
但是後來看到一票關於這操作佇列話題的文章,其中有一句提到
“因為兩個操作提交的時間間隔很近,執行緒池中的執行緒,誰先啟動是不定的。”
瞬間覺得這個queue名字有點忽悠人了,還不如pool~
綜合一點,我們知道他可以比較大的用處在於可以幫組多執行緒程式設計就好了。

37What is lazy loading?
答案:懶漢模式,只在用到的時候才去初始化。
也可以理解成延時載入。
我覺得最好也最簡單的一個列子就是tableView中圖片的載入顯示了。
一個延時載,避免記憶體過高,一個非同步載入,避免執行緒堵塞。

38Can we use two tableview controllers on one viewcontroller?
是否在一個檢視控制器中嵌入兩個tableview控制器?
答案:一個檢視控制只提供了一個View檢視,理論上一個tableViewController也不能放吧,
只能說可以嵌入一個tableview檢視。當然,題目本身也有歧義,如果不是我們定性思維認為的UIViewController,
而是巨集觀的表示檢視控制者,那我們倒是可以把其看成一個檢視控制者,它可以控制多個檢視控制器,比如TabbarController
那樣的感覺。

39Can we use one tableview with two different datasources? How you will achieve this?
一個tableView是否可以關聯兩個不同的資料來源?你會怎麼處理?
答案:首先我們從程式碼來看,資料來源如何關聯上的,其實是在資料來源關聯的代理方法裡實現的。
因此我們並不關心如何去關聯他,他怎麼關聯上,方法只是讓我返回根據自己的需要去設定如相關的資料來源。
因此,我覺得可以設定多個數據源啊,但是有個問題是,你這是想幹嘛呢?想讓列表如何顯示,不同的資料來源分割槽塊顯示?

40id、nil代表什麼?

id和void *並非完全一樣。在上面的程式碼中,id是指向struct objc_object的一個指標,這個意思基本上是說,id是一個指向任何一個繼承了Object(或者NSObject)類的物件。需要注意的是id是一個指標,所以你在使用id的時候不需要加星號。比如id foo=nil定義了一個nil指標,這個指標指向NSObject的一個任意子類。而id *foo=nil則定義了一個指標,這個指標指向另一個指標,被指向的這個指標指向NSObject的一個子類。

nil和C語言的NULL相同,在objc/objc.h中定義。nil表示一個Objctive-C物件,這個物件的指標指向空(沒有東西就是空)。

首字母大寫的Nil和nil有一點不一樣,Nil定義一個指向空的類(是Class,而不是物件)。

SEL是“selector”的一個型別,表示一個方法的名字

Method(我們常說的方法)表示一種型別,這種型別與selector和實現(implementation)相關

IMP定義為 id (*IMP) (id, SEL, …)。這樣說來, IMP是一個指向函式的指標,這個被指向的函式包括id(“self”指標),呼叫的SEL(方法名),再加上一些其他引數.說白了IMP就是實現方法。

41層和UIView的區別是什麼?

答:兩者最大的區別是,圖層不會直接渲染到螢幕上,UIView是iOS系統中介面元素的基礎,所有的介面元素都是繼承自它。它本身完全是由CoreAnimation來實現的。它真正的繪圖部分,是由一個CALayer類來管理。UIView本身更像是一個CALayer的管理器。一個UIView上可以有n個CALayer,每個layer顯示一種東西,增強UIView的展現能力。
42GCD為Grand Central Dispatch的縮寫。  Grand Central Dispatch (GCD)是Apple開發的一個多核程式設計的較新的解決方法。在Mac OS X 10.6雪豹中首次推出,並在最近引入到了iOS4.0。  GCD是一個替代諸如NSThread等技術的很高效和強大的技術。GCD完全可以處理諸如資料鎖定和資源洩漏等複雜的非同步程式設計問題。 

 GCD可以完成很多事情,但是這裡僅關注在iOS應用中實現多執行緒所需的一些基礎知識。  在開始之前,需要理解是要提供給GCD佇列的是程式碼塊,用於在系統或者使用者建立的的佇列上排程執行。  宣告一個佇列  
如下會返回一個使用者建立的佇列:
  dispatch_queue_t myQueue = dispatch_queue_create(“com.iphonedevblog.post”, NULL);其中,第一個引數是標識佇列的,第二個引數是用來定義佇列的引數(目前不支援,因此傳入NULL)。 
執行一個佇列 
 如下會非同步執行傳入的程式碼: 
 dispatch_async(myQueue, ^{ [self doSomething]; });其中,首先傳入之前建立的佇列,然後提供由佇列執行的程式碼塊。  
宣告並執行一個佇列  
如果不需要保留要執行的佇列的引用,可以通過如下程式碼實現之前的功能:  dispatch_async(dispatch_queue_create (“com.iphonedevblog.post”, NULL), ^{ [self doSomething]; });  如果需要暫停一個佇列,可以呼叫如下程式碼。暫停一個佇列會阻止和該佇列相關的所有程式碼執行。  dispatch_suspend(myQueue);暫停一個佇列  
如果暫停一個佇列不要忘記恢復。暫停和恢復的操作和記憶體管理中的retain和release類似。呼叫dispatch_suspend會增加暫停計數,而dispatch_resume則會減少。佇列只有在暫停計數變成零的情況下才開始執行。dispatch_resume(myQueue);恢復一個佇列   從佇列中在主執行緒執行程式碼  有些操作無法在非同步佇列執行,因此必須在主執行緒(每個應用都有一個)上執行。UI繪圖以及任何對NSNotificationCenter的呼叫必須在主執行緒長進行。在另一個佇列中訪問主執行緒並執行程式碼的示例如下:  dispatch_sync(dispatch_get_main_queue(), ^{ [self dismissLoginWindow]; });注意,dispatch_suspend (以及dispatch_resume)在主執行緒上不起作用。
使用GCD,可以讓你的程式不會失去響應. 多執行緒不容易使用,用了GCD,會讓它變得簡單。你無需專門進行執行緒管理, 很棒!
dispatch_queue_t t1=dispatch_queue_create(“1”, NULL);
dispatch_queue_t t2=dispatch_queue_create(“2”, NULL);
dispatch_async(t1, ^{
[self print1];
});
dispatch_async(t2, ^{
[self print2];
});
43Provider是指某個iPhone軟體的Push伺服器,這篇文章我將使用.net作為Provider。
APNS 是Apple Push Notification Service(Apple Push伺服器)的縮寫,是蘋果的伺服器。

上圖可以分為三個階段。
第一階段:.net應用程式把要傳送的訊息、目的iPhone的標識打包,發給APNS。
第二階段:APNS在自身的已註冊Push服務的iPhone列表中,查詢有相應標識的iPhone,並把訊息發到iPhone。
第三階段:iPhone把發來的訊息傳遞給相應的應用程式,並且按照設定彈出Push通知。
http://blog.csdn.net/zhuqilin0/article/details/6527113 //訊息推送機制
看記憶體洩露時候:在搜尋中搜索run 找到Run Static Snalyzer .
44.可擴充套件標記語言extensible markup language;XML

2.用於標記電子檔案使其具有結構性的標記語言,可以用來標記資料、定義資料型別,是一種允許使用者對自己的標記語言進行定義的源語言。
3,資料庫提供了更強有力的資料儲存和分析能力,例如:資料索引、排序、查詢、相關一致性等,XML僅僅是儲存資料。
4.XML與HTML的設計區別是:XML的核心是資料,其重點是資料的內容。而HTML 被設計用來顯示資料,其重點是資料的顯示。
5.XML和HTML語法區別:HTML的標記不是所有的都需要成對出現,XML則要求所有的標記必須成對出現;HTML標記不區分大小寫,XML則大小敏感,即區分大小寫。

結合
  XML的簡單使其易於在任何應用程式中讀寫資料,這使XML很快成為資料交換的唯一公共語言,雖然不同的應用軟體也支援其它的資料交換格式,但不久之後他們都將支援XML,那就意味著程式可以更容易的與Windows,Mac OS,Linux以及其他平臺下產生的資訊結合,然後可以很容易載入XML資料到程式中並分析他,並以XML格式輸出結果。
  XML去掉了之前令許多開發人員頭疼的SGML(標準通用標記語言)的隨意語法。在XML中,採用瞭如下的語法:
  1 任何的起始標籤都必須有一個結束標籤。
  2 可以採用另一種簡化語法,可以在一個標籤中同時表示起始和結束標籤。這種語法是在大於符號之前緊跟一個斜線(/),例如。XML解析器會將其翻譯成。
  3 標籤必須按合適的順序進行巢狀,所以結束標籤必須按映象順序匹配起始標籤,例如this is a samplestring。這好比是將起始和結束標籤看作是數學中的左右括號:在沒有關閉所有的內部括號之前,是不能關閉外面的括號的。
  4 所有的特性都必須有值。
  5 所有的特性都必須在值的周圍加上雙引號。
45union u

{
 double a;
 int b;
};

union u2
{
 char a[13];
 int b;
};

union u3
{
 char a[13];
 char b;
};

cout<

define MIN(A,B) ((A) <= (B) ? (A) : (B))

  MIN(*p++, b)會產生巨集的副作用

  剖析:

  這個面試題主要考查面試者對巨集定義的使用,巨集定義可以實現類似於函式的功能,但是它終歸不是函式,而巨集定義中括弧中的“引數”也不是真的引數,在巨集展開的時候對“引數”進行的是一對一的替換。

  程式設計師對巨集定義的使用要非常小心,特別要注意兩個問題:

  (1)謹慎地將巨集定義中的“引數”和整個巨集用用括弧括起來。所以,嚴格地講,下述解答:

define MIN(A,B) (A) <= (B) ? (A) : (B)

define MIN(A,B) (A <= B ? A : B )

  都應判0分;

  (2)防止巨集的副作用。

  巨集定義#define MIN(A,B) ((A) <= (B) ? (A) : (B))對MIN(*p++, b)的作用結果是:

((*p++) <= (b) ? (*p++) : (*p++))

  這個表示式會產生副作用,指標p會作三次++自增操作。

  除此之外,另一個應該判0分的解答是:

define MIN(A,B) ((A) <= (B) ? (A) : (B));

  這個解答在巨集定義的後面加“;”,顯示編寫者對巨集的概念模糊不清,只能被無情地判0分並被面試官淘汰。

  試題4:為什麼標準標頭檔案都有類似以下的結構?

ifndef __INCvxWorksh

define __INCvxWorksh

ifdef __cplusplus

extern “C” {

endif

//

ifdef __cplusplus

}

endif

endif /* __INCvxWorksh */

  解答:

  標頭檔案中的編譯巨集

ifndef __INCvxWorksh

define __INCvxWorksh

endif

  的作用是防止被重複引用。

  作為一種面向物件的語言,C++支援函式過載,而過程式語言C則不支援。函式被C++編譯後在symbol庫中的名字與C語言的不同。例如,假設某個函式的原型為:

void foo(int x, int y);
  該函式被C編譯器編譯後在symbol庫中的名字為_foo,而C++編譯器則會產生像_foo_int_int之類的名字。_foo_int_int這樣的名字包含了函式名和函式引數數量及型別資訊,C++就是考這種機制來實現函式過載的。

  為了實現C和C++的混合程式設計,C++提供了C連線交換指定符號extern “C”來解決名字匹配問題,函式宣告前加上extern “C”後,則編譯器就會按照C語言的方式將該函式編譯為_foo,這樣C語言中就可以呼叫C++的函數了。 [img=12,12]file:///D:/魚魚軟體/魚魚多媒體日記本/temp/{C74A38C4-432E-4799-B54D-73E2CD3C5206}_arc_d[1].gif[/img]
試題5:編寫一個函式,作用是把一個char組成的字串迴圈右移n個。比如原來是“abcdefghi”如果n=2,移位後應該是“hiabcdefgh”

  函式頭是這樣的:

//pStr是指向以’\0’結尾的字串的指標
//steps是要求移動的n

void LoopMove ( char * pStr, int steps )
{
 //請填充…
}
  解答:

  正確解答1:

void LoopMove ( char *pStr, int steps )
{
 int n = strlen( pStr ) - steps;
 char tmp[MAX_LEN];
 strcpy ( tmp, pStr + n );
 strcpy ( tmp + steps, pStr);
 *( tmp + strlen ( pStr ) ) = ‘\0’;
 strcpy( pStr, tmp );
}
  正確解答2:

void LoopMove ( char *pStr, int steps )
{
 int n = strlen( pStr ) - steps;
 char tmp[MAX_LEN];
 memcpy( tmp, pStr + n, steps );
 memcpy(pStr + steps, pStr, n );
 memcpy(pStr, tmp, steps );
}
  剖析:

  這個試題主要考查面試者對標準庫函式的熟練程度,在需要的時候引用庫函式可以很大程度上簡化程式編寫的工作量。

  最頻繁被使用的庫函式包括:

  (1) strcpy

  (2) memcpy

  (3) memset