參考自:《鵝廠實習生客戶端筆試》
1.下列減少內存碎片的方法有哪些是正確的?
增加實際申請和釋放的次數
頻繁調用的子函數儘量使用棧內存
系統申請一大塊內存,自己實現內存分配和釋放,定時清理內存
降低虛擬內存的大小
解答:
答案2,3是正確的。屬於操作系統中內存管理的問題。
C/C++中的malloc/free是從堆中動態申請和釋放內存的,是非常耗時的;
棧內存速度比堆內存快,因爲棧結構簡單,只需要彈出或者入棧就可以移動指針了,而在堆中,需要查找空閒內存,申請內存等操作,所以比較慢;
分配一大塊內存池,然後自己進行管理,有經驗的程序員是可以做到的,比如在nginx中,它就首先分配了很多的內存,然後再重寫malloc/free進行自主管理的;
關於虛擬內存,肯定是越多越好啊,升級64位最顯著的優勢就是可以使用64EB的內存。
考點:Stack與Heap的區別:
考點:虛擬內存(Virtual memory)
在32位Unix下,進程啓動後,可以獲取到4GB的虛擬內存,其中內核佔用1G,用戶佔用3G,虛擬內存是通過物理內存(physical memory)與交換空間(swap)進行分配的,它對於進程是透明的,系統通過地址轉換功能(比如MMU,內存管理單元)進行虛擬內存與實際內存的轉換。
什麼是內存碎片?
內部碎片: 線程佔用內存而不利用或者釋放的內存空間。
外部碎片: 內存空間太小以至於無法分配的內存空間。
2.以下哪些是HTTP協議裏面定義的URL組成部分:
schema
path
port
host
query-string
解答:
這道題答案是除第一個以外。考的是實際中對網絡編程的理解。
URL實際上就是是對資源的一種描述:
<scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]<query-string>
scheme 指協議類型,常見的協議類型有market,http,content,media,file,當然協議類型也可以自定義,比如簡書中使用的就是 jianshu作爲默認URL的。
注意這裏的 scheme 不是 schema
比如HTTP-GET的例子:
http://www.blackswift.com:8080/api/v2/getimagelist?limit=10
很顯然,這個HTTP例子中除了HTTP本身已經有了,其它所有的組成都有體現。
3.已知人臉檢測器的檢出率(人臉圖被檢測爲人臉的概率)爲90%,誤檢率(非人臉被檢測爲人臉的概率)爲1%. 請問當一張被人臉檢測器識別爲人臉時,該圖爲人臉圖的概率是多少?若給定一個圖片集中,其中20%的圖片爲人臉圖,80%的圖爲非人臉圖,當該集合中的某一張圖被人臉檢測器檢測爲人臉時,該圖爲人臉的概率又是多少?
- 無法確定, 45/47
- 90/91, 45/47
- 無法確定,90/91
- 90/91,90/91
解答:
選擇1;
第一問,
A = P(圖片是人臉);
B = P(機器檢測出人臉);
P(B|A) = 90%;
P(B|~A) = 1%;
P(B) = P(B|A)xP(A) + P(B|~A)* P(~A) = 0.9A + 0.01(1-A);
根據貝葉斯公示:
P(A|B) = P(B|A) * P(A)/P(B)
= 0.9 * P(A)/(0.89A + 0.01)
A爲止,所以無法確定。
第二問,
P(A) = 0.2,代入完成。
4.iOS開發中,非ARC下這段代碼執行的結果是什麼?
//類似於Java,用註解定義接口
@interface OCObject : NSObject
-(void)printDescription;
@end
//接口的實現
@implementation OCObject
-(void)printDescription{
NSLog(@”OCObject printDescription!”);
}
@end
//手動分配內存,alloc並init
OCObject *obj = [[OCObject alloc]init];
//執行方法,performSelector
類似於Java中的反射,也是在運行時找的。
[obj performSelector:@selector(printDescription) withObject:nil afterDelay:60];
[obj release];
1. 不會打出任何消息
2. 會輸出OCObject printDescription!
3. 會crash
4. 編譯不通過
解答:
答案是2
ARC是 Automatic Reference Counting,即自動引用計數器,在iOS開發中,蘋果不希望開發者控制內存,所以使用ARC幫助開發者在編譯的時候自動加上內存回收的代碼。
以下爲測試結果:
Xcode6.3/ARC on/iOS8.3下,編譯不通過,要求刪除release,刪除後編譯通過,輸出Log;
Xcode6.3/ARC off/iOS8.3下,編譯通過,輸出Log。
5.以下對C++(C++98標準)語言描述中正確的是
- C++提供了對全局對象初始化順序控制的機制
- C++沒有提供固定大小的整型
- C++支持多維數組
- C++支持類類型的成員常量
解答:
答案是1 3 4
·全局對象如果有依賴的話,就需要對初始化順序進行控制,C++已經有了這個機制;
·C++中有int8_t,int16_t,int32_t, 甚至int64_t,所以是有固定大小的整型;
·多維數組肯定支持,連C語言都支持;
·類類型的成員常量是支持的,用const修飾。
6.請問下列代碼,當x =0x7c和x=0f2時,運行結果分別是什麼?
int main(){
char x = 0xF2;
int nConut = 0;
//這裏的x 就是 x!= 0x00;
for (; x; x>>=1) {
++nConut;
}
printf("nCount = %d ",nConut);
}
解答:
答案分別是7,死循環。
第一個是簡單二進制操作題目,用於判斷它有多少位。至於第二個,是負數。
知識點:
負數右移是補1,最後就是0xffffffff了
11110010
11111001
11111100
11111110
11111111
由於-1始終不爲0,所以會死循環。
無符號右移(unsigned right shift)在iOS中是沒有的,在Java中是有的。
7.下列方法得到的NSString對象與衆不同的是:
NSString *str = @"Hello";
NSString *str2 = [NSString stringWithFormat:@"%s","Hello"];
NSString *str3 = [NSString stringWithFormat:@"%s","Hello"];
NSString *str4 = [[NSString alloc]initWithString:@"Hello"];
解答:
答案是第四個,它調用了malloc,是在堆中(運行時)申請的,需要手動釋放(如果沒有用arc的話),而其它幾個是編譯時(棧中)就已經固定在_DATA段了。
8.在一個路由表中,假設有下面三條路由:192.168.128.0/24, 192,168.130.0/24, 192.168.132.0/24,如果進行路由匯聚,能覆蓋這三條路由的地址是:
192.168.128.0/21
192.168.128.0/22
192.168.130.0/22
192.168.130.0/23
解答:
答案是第一個。
1100 0000.1010 1000.1000 0000.0000 0000
1100 0000.1010 1000.1000 0010.0000 0000
1100 0000.1010 1000.1000 0100.0000 0000
可以看出,公共節點在21位。
9.程序運行的結果是?
#include<stdio.h>
struct A
{
unsigned char x;
unsigned char y;
int z;
};
int main(){
struct A a;
a.x = 10;
a.y = 20;
a.z = 30;
*((int*)&a) = 0x010101ff;
printf("%d,%d,%d,%d",sizeof(a),a.x,a.y,a.z);
return 0;
}
解答:
8,255,1,30
本題有2個重點:
結構體對齊
指針類型轉換
在結構體對齊中,我們要知道,爲了提高內存讀取效率,需要把結構體中的成員按照2^n(Power-of-two)來進行對齊(align)的,對齊準則是
回到題目,我們可以看出,結構體是按照Int,也就是4byte來對齊的
所以sizeof爲8.
接下來,是指針問題,我們先翻譯這句話
((int)&a) = 0x010101ff;
它實際上就是取a的地址,然後把a到(a+4)byte中的內容換成0x010101ff。僞代碼如下
a.x = (0x010101ff)&0xff;
a.y = (0x010101ff>>2)&0xff; //小端CPU的情況
a,z不受影響啦
也就是這樣
10.在SQL語句中,與X BETWWEN 20 AND 30 等價的表達式是:__?
解答;
20<= x <= 30,是包括邊界的,最多可以取出11個數。
11.在iOS開發中,需要實踐一個簡單的http協議通訊,可用的工具/組件有?
BSD Socket API
CFSocket
NSStrem
NSSURLConnection
解答:
答案是NSSTream 與 NSSURLConnection。
前面兩個Socket是屬於傳輸層的,面向底層網絡連接,要是自己重寫一個HTTP那還不得累死。在Android中,有URLConnnection,OkHttp,Volley等組件。
12.下列關於棧的說法哪些是正確的?
- 棧是後進先出的
- 通常棧空間大小在編譯時指定,並在程序運行時由操作系統管理(分配,釋放等)
- 所有定義在函數內部的變量都是從棧上分配內存
- 棧的使用效率比堆高
- 棧內存具有讀,寫屬性
解答:除了3是錯的,別的都是對的。注意函數內部的malloc。
13.二進制0.101001B等於十進制()?
0.640625D
0.620125D
0.820325D
0.804625D
解答:0.640625D。
1/2 + 1/8 + 1/64
= 0.5 + 0.125 + 0.015625
= 0.640624D
14.關於數據類型的取值範圍,在Java中執行語句 byte b = (byte)128,請問b的值是多少?
- -1
- 128
- -128
- 出錯
解答:
答案爲128;
第一,強制轉換實際上就是添加mask,僞代碼如下
b = 0x80;
b_new = 0x80 & 0xff;
第二,char與byte的區別(特指C中)
0x00 ~ 0x7f 0x80 ~ 0xff
byte 0 ~ 127 128 ~ 255
char 0 ~ 127 -128 ~ -1
如果我們把byte改成char,結果就是-128了,因爲java中的char是有符號而且是雙子節的。
15.網絡帶寬擁堵可能導致以下哪些問題?
- UDP丟包變嚴重
- tcp數據被寫亂
- tcp丟包
- tcp傳輸速度驟降
解答:1 3 4
網絡擁塞一般是由三個原因照成:
存儲空間(緩存),比如緩存隊列滿了就會被路由器丟包;
帶寬不足,比如最近的出國帶寬就受到了不明干擾;
處理器不足,特別是在openwrt路由器上,由於MIPS的CPU性能優化不足,導致網速下降。
解決擁塞:
滿足上面三個短板
使用NetSpeeder,ARP等不良工具強制搶網速
16.下列函數的時間複雜度是
int foo(int n){
int i = 1;
while(1 <= n){
i = i*2;
}
return 1;
}
解答:
答案是O(log2N),非常簡單。這裏的 i = i*2 可以用 i <<= 1來優化哦。
17.使用快速排序對{83,123,69,179,118,13,190}進行升序排序,請問如下那個是第一趟快排交換後的結果?
- {13,69,83,179,118,123,190}
- {13,83,69,179,118,123,190}
- {13,69,83,118,179,123,190}
- {13,123,69,179,118,83,190}
解答:答案是 1
原理可以參考 http://me.dt.in.th/page/Quicksort/ 的 Partitioning
18.關於TCP和UDP協議的說法正確的有:
- TCP是面向連接的協議,而UDP是無連接的協議
- TCP建立連接過程中,協議棧需要進行三次握手,而關閉連接則需要進行4次握手;
- UDP協議常常用於容忍丟數據,但需要更高傳送性能的業務場景;
- UDP和TCP協議棧都具備保證數據包時序性的能力,並通過滑動窗口機制進行擁塞控制。
解答:1 2 3
19.假設代碼如下:
#include<stdio.h>
#pragma pack(8)
struct X{
uint8_t a;
uint32_t b;
uint16_t c;
};
#pragma pack()
int main(){
struct X x;
printf("%d\n",sizeof(x));
return 0;
}
解答:
答案是12。同剛剛的那道結構體對齊的題目,公式如下
MIN(MAX(DataType),#pragram pack(8))
= MIN(8,8);
= 8;
所以以8byte爲準則進行對齊,它的內存佈局如下
如果我們現在改一下結構體的佈局
struct X{
uint8_t a;
uint16_t c;
uint32_t b;
};
它的佈局是這樣的
這樣,結構體的佔用就變少了,sizeof由12變成了8。
20.一顆二叉樹有5個節點,樹的形態有多少種?
- 38
- 42
- 46
- 58
解答:42
考的是遞推。以根節點爲開始,按照左一右零,左一右一,左零右一的三個方向進行調用,網上有公式。
大題(60分鐘)
1.請儘可能多的列舉/描述出你所瞭解的個進程間通信機制已經對應的應用場景,各自的優缺點。
我只知道Android中的Binder;還有曾經學的管道,Socket。
2.已知結構體StructA定義如下
#include<stdio.h>
typedef struct _StruckA{
unsigned int val1;
unsigned char bSuccess;
unsigned int val2;
unsigned char bInitialize;
}structA, *pStructA;
int main(){
structA a;
a.val1 = 0x12345678;
a.bSuccess = 0;
a.val2 = 0xABCDEF01;
a.bInitialize = 1;
//請給出變量a在x86,x64下的內存分佈情況
return 0;
}
解答:
!address 0x00 ~ 0x03 0x04 0x05 ~ 0x7 0x08 ~ 0x0b 0x0c 0x0d ~ 0x0f
value val1 bSuccess padding val2 bInitialize padding
還是按照4byte對齊,共16bype,具體原理我在前面的字節對其中已經講了
而且我沒有32位的機子測試啊,全是LP64的….運行以下代碼
printf("%d\n",sizeof(a));
printf("%p\n",&a);
printf("%p\n",&a.val1);
printf("%p\n",&a.bSuccess);
printf("%p\n",&a.val2);
printf("%p\n",&a.bInitialize);
Xcode6.3
16
0x7fff5fbff838
0x7fff5fbff838
0x7fff5fbff83c
0x7fff5fbff840
0x7fff5fbff844
Ubuntu14.10 x64
16
0x7fff652a4880
0x7fff652a4880
0x7fff652a4884
0x7fff652a4888
0x7fff652a488c
3.設計抽卡程序,策劃人員填寫物品出現概率,程序按照概率隨機抽出物品。配置表如下:
<data>
<item id="1">10</item>
<item id="2">50</item>
</data>
4.用C寫一個程序,得出當前系統的整型數字長(16位,32位,64位等),不能使用sizeof()
解答:
使用數組即可
#include<stdio.h>
unsigned int getSize(){
int a[2] = {1,2};
return (char*)(a+1) - (char*)a;
}
或者
unsigned int getSize(){
int *a;
return (char*)(a+1) - (char*)a;
}
5.在傳統的CS網絡模型中,server端需要控制請求量,對超過某個閥值的請求量直接拋棄或者返回錯誤,以保護自己(過載保護)。假設一個Server服務的能力爲1W Qps,設計一個過濾機制,對於超過服務能力的請求直接拋棄。