2017年4月13日 星期四

面試心得: 奕力科技 interview of Ilitek - 韌體工程師 firmware engineer


  • Overview

面試流程:
智力測驗(15min) -> C語言測驗(30min) -> 性向測驗(20min) -> 向主管present ppt (10~15min) -> 主管提問時間 (1hr up) -> HR提問時間 (less than 15min)


  • 智力測驗內容:

part1:國文邏輯能力 (古文,文言文克漏字、除錯字)
part2:數學邏輯能力(奇怪的數列填空、排列組合、邏輯分析)
part3:圖形理解能力 (各種圖案的序列、立體圖形2D, 3D 互轉)

心得:像是在玩遊戲一樣的題目,玩玩就好!不會就跳過,回頭再來想,時間一定夠。

  • C語言測驗內容

語言宣告動靜態差異解釋
Big, Small Endian(有考多個計算機組織題目,這些我都不太會,以前考資工所的時候都有背過)
不同的C語言function實踐,如字串比較、Dec. to Bin. return、特定限制的swap function、記憶體分配跟指派的方式列舉

心得:先挑會的寫就好,一定寫不完!


  • 性向測驗
個性判別的題目,最後的數據會化為能力分布圖,主管會先過目。我一邊寫一邊吃三明治,因為我沒吃午餐,過程比較chill。

  • 向主管present & 主管提問
我報告了我大學期間所參與過的課程、自己做的project(嵌入式系統開發、智能機器人開發、軟體開發、專利申請)、自學的歷程、創業經驗、個人優勢等等。

但三位主管對於90%的內容都沒有什麼感到興趣,似乎也不太在乎我的個性以及參與過的活動,他們都專攻我開發嵌入式的幾個案子(FPGA, DSP, ARM)他們會問得十分細,其中一位最年輕的主管問太細,還被比他大的主管唸了一下(「喂,你問這麼深幹嘛?人家剛畢業你講這些他也不會懂,別問這麼細」)

我的應答邏輯是,我會把問題一一記錄在筆記本,大概寫下,然後思考15秒左右,如果真的不會就說「這個我不會」,如果還可以推演,就會講出自己腦中的思路以及自己的解法。主管們在聽完答案後,不論是否會不會,在問題之後會緊接著更深更細的問題,一直往下鑽,一直往下問個3,4 round,且過程說了許多蠻專業的名字其實我聽不懂,已經是業界的術語了。我寫下了幾個要回來自己wiki的詞彙,當下是覺得有被電(輕微)

結束後主管有給我一些個人的意見,其中一位主管有跟我提到,過去我開發專案時,都是目的導向的去解決問題,比方說我想開發一款Cortex 開發版的電動,我的目的就只是做出來,我就覺得成功了,過程中我所使用的IDE跟API會幫我處理很多底層的事情,我如果要走韌體工程師這一塊,底層所經歷過的所有最細最小的流程,我都要懂,從電力到如果把每個程序由電腦到板子上的每一個電路,都要懂他在幹麻,才是未來我該有的眼光與角度。

每位主管都非常有耐心的聽我解釋題目以及問題,並不會強制打岔或是給予壓力,就算質疑我的答案,也是在非常專業的角度去詢問我的方式或是邏輯是否有錯誤的地方,也因為許多課程跟project都是幾年前所做的,都忘了八成,也影響蠻大的,有些時候真的忘記的part會需要稍微掰出個大方向,而且這些一字一句都會成會連續提問的下一個切入口,所以真的不要講出錯的答案只為了有個答案,不會就說不會,會比較明智。最後個人提問時間,我問了幾個公司發展方向的問題、個人能力有哪裡可以加強來符合職業需求等等,大中小主管都非常有耐心的跟我講說我可以怎麼做,非常感謝他們,氣氛不錯的一個環境,人資們也都很nice。

ps. 偷觀察一下下班狀況,面試到了5:30pm,我那一個樓層超多人下班,燈關了一半,不知道是好還是壞,但還有另外兩個樓層,所以其實這觀察也可以說是無鑑別度




2017年4月9日 星期日

C++: Call by value/address/reference


  • Call by Value

int main() { 
    int x = 5; 
    foo(x); 
void foo(int x) { 
    x++; 
}
這時候main裡的變數x的值被複製到foo裡的x,這兩個x基本上是位於不同的記憶體空間的,也是就foo裡的x在加一後,並不會影響到main裡的x(依然是5)。


  • Call by address (pointer)
int main() { 
    int x = 5; 
    foo(&x); 
void foo(int *x) { 
    (*x)++; // 指向,並加1  }






main呼叫foo時,將x的address(&x)傳遞給foo的x pointer,所以x pointer指向回main的x,應此可以修改其數值。(*x)為指向其實體數值,因此(*x)++就是把main的x加1。
  • Call by reference
int main() { 
    int x = 5; 
    foo(x); // 不用加&  
void foo(int &x) { 
    x++; // 修改此x就是修改main的x  }










如果寫成call by pointer的方式,麻煩的地方是每次傳address都要加個 & ,而在副程式裡還要加個 * 來指向原本的實體。因此,C++新增了Call by reference的方式,讓在丟變數到副程式時,不用加&,而在副程式參做此變數也不用加*號就可以直接修改其變數。唯一要寫的是:在副程式裡的參數裡加上&,代表是Call by reference。
特別要注意的是,Call by reference的方式,一定要在初始化時就有指向的實體,而且不能改變。如上例中,foo(int &x)裡的x在副程式被呼叫時,就固定指向main的x,不能改變。


credit: 藏經閣

2017年4月8日 星期六

LeetCode : 344 - Reverse String

對於leetcode的練習模式尚未掌控最有效率的學習方法,主要先找到了網路上推薦的方式:依照難度,由簡單開始,均勻的做不同tag的考題方向。

344. Reverse String
class Solution {
public:
    string reverseString(string s) {
        string reversedString = "";
        for(int i = s.length() - 1; i >= 0; i--){
            reversedString += s.at(i);
        }
        return reversedString;
    }
};
有看到另一個用swap將最前跟最後逐一對調的方式,不過我個人偏好保留原始data的回傳方式。
新學到的用法是 array.at(i),很方便。



Swift: Closure



定義:Closures are self-contained blocks of functionality that can be passed around and used in your code. 

在撰寫一個struct時,內部原本需要呼叫一個global func 功能,如:換號、乘法,此時直接用closure的方式即可在local宣告方法,不必再額外global寫新的func。

  • 原本必須在global建立以下兩個func來進行struct內的功能:


  • 現在,結合enum以及dictionary的做法,可以在dictionary內部藉由clousure來把簡單的方法implement出來,就不需要每一個項目都去額外寫下一個global的func:
這邊所使用的closure比正式的完整寫法簡化很多,應該是屬於高級的應用,直接用$0, $1這種類似register形式的判別寫下。

這邊是比較清楚的closure 介紹:closure 完整寫法

2017年4月7日 星期五

Swift: MVC, Class vs Struct, Mutating Keyword, Dictionary




  • MVC

Model (Should be UI independent.), View, Control 
三者獨立的運行自己的工作,但以”溝通“的方式互相協調、互不干預。



  1.  Model絕不干涉UI

  • Class vs Struct

Class has inheritance, Struct don't.
Class live in Heap, pointers pointing to them.
Struct move by copying them.
Struct has initializer automatically, Class don't.

以下內容來自:Developer's Note: Swift

1. 建構物件時

struct


var sRect = SRectangle()
// 或者 

sRect = SRectangle(width:300)

sRect.width // 結果就是 300

class


var cRet = CRectangle()
// class 不能直接用 CRectangle(width:300) 必需要定義一個 constructor
cRect.width // 為 200

主要的差別就是 class 在產生物件時不能很自然把 property 放在 constructor 的參數裡

2. 指定給另一個變數的行為不同 

struct


var sRect = SRectangle()
// 或者 

var sRect2 = sRect

sRect2.width // 目前值是 200,因為 sRect 直接 copy 一份完整記憶體給 sRect2
sRect2.width = 500
sRect.width // sRect.width 值不受 sRect2 影響還是 200

class


var cRect = CRectangle()
// 或者 

var cRect2 = cRect

cRect2.width // 目前值是 200,因為 sRect 直接 copy 一份完整記憶體給 sRect2
cRect2.width = 500
cRect.width // cRect.width 也改變成了 500

以上是 value type 和 reference type 最大的不同,在每次做 assignment 的時候,value type 都會複製一份完整相同的內容給另一個變數,而 class 則是把記憶體的位置給變數。所以 reference type 大多會保有一份記憶體而重覆利用。

  • Mutating func in struct

3. 關於 immutable 變數 

在 Swift 這個語言的特色之一就是可變動內容的變數和不可變動內容的變數用 var 和 let 來區別。如果一開始用 let 來修飾變數就會造成 compiler 的錯誤。如下

var name = "Michael"
name.write(" Pan") // 這樣是正常

let name = "Michael"
name.write(" Pan") // 會造成 compile 錯誤

struct

大至也遵循這個規則如下

let sRect = SRectangle()

sRect.width = 500 // 會造成錯誤

class


let cRect = CRectangle()

cRect.width = 500 // 預設可以直接更改雖然是 let 修飾的 cRect

let 這個效果無法延申至 class 。不過要提醒大家在 Swift 常用的 String, Array, Dictionary 都是 struct 所以 let 是會有效果的

4. mutating function 

我們先要為 struct 和 class 新增一個 method 名為 changeWidth() 而且我們在不改變原始的程式碼為前提下,新增一個 method。如下 

struct 


struct SRectangle {
    var width = 200
    
}

extension SRectangle {
    mutating func  changeWidth(width:Int){
        self.width = width
    }
}

class 


class CRectangle {
    var width = 0
}

extension CRectangle {
    func changeWidth(width:Int){
        self.width = width
    }
}

這裡用了 extension 新增 class 裡的 method 而不需要改到原本的程式碼。 以。struct 和 class 的差別是 struct 的 function 要去改變 property 的值的時候需要加上 mutating 字樣,而 class 不用這樣做

The Mutating Keyword

Let’s say you want to add an area function to your struct:
1
2
3
4
5
6
7
8
struct Rectangle {
    var width = 1
    var height = 1
     
    func area() -> Int {
        return width * height
    }
}
It’s just as you expect! This area function multiplies the existing width and height of the rectangle and returns the result. The key here is that this function does NOT change the width or height variables – it only uses the existing values.
In contrast, let’s say we wanted to have a function that scales the rectangle:
1
2
3
4
5
6
7
8
9
struct Rectangle {
    var width = 1
    var height = 1
    mutating func scaleBy(value: Int) {
        width *= value
        height *= value
    }
}
Notice that this function actually changes the width and height variables of the rectangle. So this is where you have to use the mutating keyword – when you’re actually changing the variables in your struct! (Via:Natasha the robot)

  • Dictionary usage 

Creating an Empty Dictionary




As with arrays, you can create an empty Dictionary of a certain type by using initializer syntax:
  1. var namesOfIntegers = [Int: String]()
  2. // namesOfIntegers is an empty [Int: String] dictionary
This example creates an empty dictionary of type [Int: String] to store human-readable names of integer values. Its keys are of type Int, and its values are of type String.
If the context already provides type information, you can create an empty dictionary with an empty dictionary literal, which is written as [:] (a colon inside a pair of square brackets):
  1. namesOfIntegers[16] = "sixteen"
  2. // namesOfIntegers now contains 1 key-value pair
  3. namesOfIntegers = [:]
  4. // namesOfIntegers is once again an empty dictionary of type [Int: String]

Creating a Dictionary with a Dictionary Literal




You can also initialize a dictionary with a dictionary literal, which has a similar syntax to the array literal seen earlier. A dictionary literal is a shorthand way to write one or more key-value pairs as a Dictionary collection.
key-value pair is a combination of a key and a value. In a dictionary literal, the key and value in each key-value pair are separated by a colon. The key-value pairs are written as a list, separated by commas, surrounded by a pair of square brackets:
  • [key 1: value 1, key 2: value 2, key 3: value 3]
The example below creates a dictionary to store the names of international airports. In this dictionary, the keys are three-letter International Air Transport Association codes, and the values are airport names:
  1. var airports: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
The airports dictionary is declared as having a type of [String: String], which means “a Dictionarywhose keys are of type String, and whose values are also of type String”.