隨筆 - 11  文章 - 2  trackbacks - 0
          <2025年6月>
          25262728293031
          1234567
          891011121314
          15161718192021
          22232425262728
          293012345

          常用鏈接

          留言簿

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          新聞分類

          link

          搜索

          •  

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          昨天突然決定開始寫博客,于是今天就開始寫了,也不知道怎么寫,就這樣吧先。。。
          posted @ 2010-02-25 21:29 poower 閱讀(143) | 評(píng)論 (0)編輯 收藏
          #!/bin/ksh
          DATE=`date +%Y%m%d`

          export ORACLE_HOME=/oracle/app/db
          export NLS_LANG="SIMPLIFIED CHINESE_CHINA.ZHS16GBK"


          DATE=`date +%Y%m%d`

          /oracle/app/db/bin/exp boss_v2/ owner=boss_v2 compress=n direct=y recordlength=65535 file=./boss_v2$DATE.dmp log=./log/boss_v2$DATE.log
          if [ -f boss_v2$DATE.dmp ]
          then
            rm -f old.dmp
            mv new.dmp old.dmp
            mv boss_v2$DATE.dmp new.dmp
          fi   
          posted @ 2009-12-11 13:57 poower 閱讀(201) | 評(píng)論 (2)編輯 收藏
          另外,FireFox收藏夾(書簽)也可以通過菜單選項(xiàng)直接導(dǎo)出,具體方法是:打開Firefox,點(diǎn)擊“書簽 -> 書簽管理”啟動(dòng)書簽管理器,點(diǎn)擊“文件 -> 導(dǎo)出”來備份現(xiàn)有的書簽。在另一臺(tái)機(jī)器上,再用書簽的“導(dǎo)入”功能把備份的書簽導(dǎo)入到新的Firefox的配置中即可。
          posted @ 2009-11-20 21:34 poower 閱讀(172) | 評(píng)論 (0)編輯 收藏

          輕松面試找到理想員工-非官方的面試技術(shù)指南

          簡(jiǎn)述:

          本文作者Joel Spolsky 是紐約市一家軟件公司Fog Creek Software的創(chuàng)始人。他畢業(yè)于耶魯大學(xué),曾分別在美國(guó)微軟、Viacom、Juno等公司任軟件設(shè)計(jì)師、經(jīng)理職位。本文來自于《祖兒談軟件》,文章原名為《輕松面試找到理想員工——非官方的面試技術(shù)指南》,作者最初本意是針?/p>

          作者:周思博 (Joel Spolsky   更新日期:2005-05-22
          來源:chinese.joelonsoftware.com   瀏覽次數(shù):

          譯: Chen Bin    編輯: Rick Ju    2000年3月23日

          雇傭合適的人對(duì)于Fog Creek軟件公司來說是非常關(guān)鍵的。在我們這個(gè)領(lǐng)域,有三類人可以挑選。在一個(gè)極端, 是哪些混進(jìn)來的, 甚至缺乏最基本的工作技巧. 只要問這類人兩三個(gè)簡(jiǎn)單的問題,再讀一下他們的簡(jiǎn)歷,就可以輕易地剔除他們。另一個(gè)極端的類型是 才華橫溢的超級(jí)明星 這些人僅僅為了好玩就用匯編語言為Palm Pilot(一種手掌電腦)寫了一個(gè)Lisp(一種人工智能編程語言)編譯器。在這兩種極端類型中間的是一大群不能確定水平的候選者,也許他們中的某些人能干些什么?這里的關(guān)鍵是明白超級(jí)明星和那一大堆屬于中間類型的人的區(qū)別,因?yàn)镕og Creek軟件公司只雇傭超級(jí)明星。下面我要介紹一些找出超級(jí)明星的技巧。

          Fog Creek公司最重要的雇傭標(biāo)準(zhǔn)是:

          有頭腦, 并且
          完成工作

          就是這些了。符合這樣標(biāo)準(zhǔn)的人就是我們公司需要的員工了。 記住這條標(biāo)準(zhǔn)。 每天上床前背誦這條標(biāo)準(zhǔn)。我們公司的目標(biāo)之一就是雇傭擁有這樣的潛質(zhì)的人,而不是雇傭懂某些技術(shù)的人。任何人所擁有的某些具體技術(shù)都會(huì)在幾年內(nèi)過時(shí),所以,雇傭有能力學(xué)習(xí)新技術(shù)的人,要比雇傭那些只在這一分鐘知道SQL編程是怎么回事的人對(duì)公司更劃算一點(diǎn)。

          有頭腦確實(shí)是一個(gè)很難定義的品質(zhì)。但是讓我們看一些在面試時(shí)能提問的一些問題,通過這些提問,我們可以找出擁有這種品質(zhì)的人。完成工作非常關(guān)鍵。看起來有頭腦但是不能完成工作的人經(jīng)常擁有博士學(xué)位,在大公司工作過,但是在公司中沒有人聽他們的建議,因?yàn)樗麄兪峭耆撾x實(shí)際的。比起準(zhǔn)時(shí)交活兒,他們寧愿對(duì)于一些學(xué)院派的東西沉思。這些人由以下特性而可以識(shí)別出來。他們總是愛指出兩個(gè)根本不同的概念間的相似性。例如,他們會(huì)說“Spreadsheets是一種特殊的編程語言”,然后花一個(gè)禮拜寫一篇?jiǎng)尤说模腔鄣陌灼_@篇白皮書論述了,作為一個(gè)編程語言,spreadsheet關(guān)于計(jì)算語言特性的方方面面。聰明,但是沒用。

          現(xiàn)在,我們來談?wù)?strong>完成工作但是沒有頭腦的人。他們愛做蠢事。從來也沒有考慮過將來得靠他們自己或者別的什么人來亡羊補(bǔ)牢。通過制造新的工作,他們成為了公司的負(fù)債而不是資產(chǎn)。因?yàn)樗麄儾粌H沒有為公司貢獻(xiàn)價(jià)值,還浪費(fèi)了好員工的時(shí)間。這些人通常到處粘貼大堆的代碼,而不愿意寫子程序。他們是完成了工作,但是不是以最聰明的方式完成工作。

          面試時(shí)最重要的法則是:

          做決定

          在面試結(jié)束時(shí),對(duì)于被面試者,你不得不做一個(gè)直截了當(dāng)?shù)臎Q定。這個(gè)決定只有兩個(gè)結(jié)果:雇傭或者不雇傭. 回到你的電腦前,立刻用電子郵件通知招聘負(fù)責(zé)人你的決定。電子郵件的主題應(yīng)該是雇傭或者不雇傭。接著你需要在正文中寫兩段來支持你的決定.

          沒有其他的答案。永遠(yuǎn)不要說,“雇傭你,但是不能在我的團(tuán)隊(duì)中”。這是非常粗魯?shù)模驗(yàn)槟阍诎凳緫?yīng)試者沒有聰明到能有和你一起工作的資格,但是以他的頭腦適合進(jìn)入那些天生輸家隊(duì)伍。如果你發(fā)覺自己被誘惑,想說出那句“雇傭你,但是不能在我的隊(duì)伍中”,那么就簡(jiǎn)單的把這句話變成“不雇傭”再說出口。這樣就沒事了。甚至如果某個(gè)人在特定領(lǐng)域很能干,但是在別的隊(duì)伍中將會(huì)表現(xiàn)不好,也是不雇傭。事物變化的如此之快,我們需要的是在任何地方都能成功的人。如果某些情況下你發(fā)現(xiàn)了一個(gè)白癡專家(擁有某些特殊能力的白癡),這個(gè)專家對(duì)于SQL非常,非常,非常的精通,但是除此之外什么也學(xué)不會(huì),不雇傭。在Fog Creek公司他們沒有將來。

          永遠(yuǎn)不要說,“也許,我吃不準(zhǔn)”。如果你吃不準(zhǔn),意味著不雇傭。看,比你想象的容易的多。吃不準(zhǔn)?就說不!同樣,如果你不能作出決定,那意味著不雇傭。不要說,”嗯,雇傭,我想是這樣的。但是關(guān)于...,我想知道 ...”。這種情況就是不雇傭

          最重要的是記住這點(diǎn),放棄一個(gè)可能的好人要比招進(jìn)一個(gè)壞人強(qiáng)(譯者按:中國(guó)有位哲人說過,寧可錯(cuò)殺一千,不可放過一個(gè),呵呵)。一個(gè)不合格的求職者如果進(jìn)入了公司,將要消耗公司大量的金錢和精力。其他優(yōu)秀員工的還要浪費(fèi)時(shí)間來修復(fù)這個(gè)人的錯(cuò)誤。如果現(xiàn)在你還在猶豫,不雇傭

          如果你是Fog Creek公司的面試官,當(dāng)你拒絕了大量的應(yīng)聘者時(shí),不要為Fog Creek公司將因此雇不到任何人了而憂慮。這不是你的問題。這是招聘負(fù)責(zé)人的問題。這是人力資源部的問題。這是Joel(譯者注: Fog Creek公司的老板,本文作者)的問題。但不是你的問題。不停地問自己,哪種情況更糟糕?一種情況是我們變成了一個(gè)龐大的,糟糕的軟件公司,充斥著許多腦袋空空如可可果殼的家伙,另一種情況是我們是一個(gè)小而高品質(zhì)的公司。當(dāng)然,找到優(yōu)秀的應(yīng)聘者(并聘用他們)是很重要的。找到有頭腦而且完成工作的人是公司中的每個(gè)員工的日常工作之一。但是當(dāng)你作為Joel Creek公司的一員真的開始面試一個(gè)應(yīng)聘者時(shí),要裝作現(xiàn)在正有很多優(yōu)秀的人想打破頭擠進(jìn)Fog Creek公司。總之,無論找到一個(gè)不錯(cuò)的應(yīng)聘者是多么的難,永遠(yuǎn)不要降低你的標(biāo)準(zhǔn)。

          但是你如何作出雇傭或者不雇傭這樣艱難的決定?你只要在面試過程中不停地問自己:這個(gè)人有頭腦嗎?這個(gè)人能完成工作嗎?要作出正確的回答,在面試時(shí)你必須問對(duì)問題。

          開個(gè)玩笑,下面我要問個(gè)有史以來最差的面試問題: “Oracle 8i中的數(shù)據(jù)類型varchar和varchar2有什么區(qū)別”這是一個(gè)可怕的問題。掌握這種瑣碎的技術(shù)細(xì)節(jié)和Fog Creek公司想雇傭你之間沒有任何聯(lián)系。誰會(huì)去記這種東西?如果有在線幫助,你可以在15秒內(nèi)找到答案。

          實(shí)際上,還有更差的問題,等會(huì)兒我會(huì)談到的。

          現(xiàn)在我們要談到有趣的部分了:面試時(shí)提哪些問題。我的面試問題清單來自于我去微軟公司找第一份工作的經(jīng)歷。這里實(shí)際上有幾百個(gè)微軟面試問題。每個(gè)人都有偏愛的問題。你也可以發(fā)展一套自己的面試問題以及面試的個(gè)人風(fēng)格,這樣你就可以比較容易地作出雇傭/不雇傭的決定。以下是我成功使用過的一些面試技巧,

          在面試前,我讀一遍應(yīng)試者的簡(jiǎn)歷,然后在一張紙片上隨便寫以下我的面試計(jì)劃。這個(gè)計(jì)劃實(shí)際上就是我要問的問題清單。以下是一個(gè)例子(用來面試程序員的):

            1. 介紹
            2. 應(yīng)試者參加過的項(xiàng)目
            3. 無法回答的問題
            4. C語言函數(shù)
            5. 你滿意嗎?
            6. 設(shè)計(jì)問題
            7. 挑戰(zhàn)
            8. 你還有什么問題?

          在面試前,我非常,非常當(dāng)心,避免自己先入為主。如果在面試前你就已經(jīng)想當(dāng)然地認(rèn)為,一個(gè)麻省理工的博士一定是一個(gè)有頭腦的人。那么在接下來的一小時(shí)的面試時(shí)間內(nèi),無論那個(gè)麻省理工的博士說什么都不能改變你的最初印象。如果在面試前你就認(rèn)為這個(gè)應(yīng)試者是個(gè)傻瓜,那么他面試時(shí)說什么也無濟(jì)于事。面試就象一個(gè)非常精巧的天平。一小時(shí)的面試結(jié)束后就要對(duì)一個(gè)人下結(jié)論是不容易的(但是你又必須在面試結(jié)束后得出結(jié)論)。一些不起眼的細(xì)節(jié)可能會(huì)影響最后的結(jié)論。如果你在面試開始前對(duì)于應(yīng)試者有了一點(diǎn)了解的話,就好比天平的某一端加上了重重的砝碼。這樣面試本身就會(huì)變得沒有用處了。以前有一次在面試前,一個(gè)招聘負(fù)責(zé)人跑進(jìn)我的房間說,“你肯定會(huì)愛上這個(gè)家伙的!" 對(duì)一個(gè)男孩? 天哪,這簡(jiǎn)直讓我發(fā)瘋。我本來應(yīng)該說,“嗯,如果你這么確定我會(huì)喜歡他,為什么你不干脆雇傭他,何必讓我浪費(fèi)時(shí)間來面試?”但是那時(shí)我還太年輕幼稚, 所以還是面試了那個(gè)人。當(dāng)這個(gè)家伙開始說一些蠢話時(shí),我對(duì)自己說,“哇塞,這應(yīng)該是個(gè)例外情況,也許是大智若愚。”我開始帶著玫瑰色眼鏡看他了。于是我以說“雇傭”結(jié)束了面試,雖然他是一個(gè)糟糕的面試者。接下來發(fā)生了什么事?除了我,其他的面試官都說,不要雇傭這個(gè)人。教訓(xùn)是,不要聽別的人的話,在面試應(yīng)試者前不要四處打探這個(gè)面試者的情況。最重要的是不要和別的面考官談?wù)搼?yīng)試者,除非你們都已經(jīng)作出了獨(dú)立的判斷。這才是科學(xué)的做法。

          作為面試步驟的第一步,介紹的目的是讓應(yīng)試者放輕松。我通常花30秒鐘,講一下我是誰,接下來面試會(huì)如何進(jìn)行。我總是使得應(yīng)試者確信,我們關(guān)心的是他(她)如何解決問題的,而不是他(她)的最終答案是對(duì)還是錯(cuò)。順便說一下,面試時(shí),你不要和應(yīng)試者隔著一個(gè)桌子坐著,否則在你和面試者之間就有了一個(gè)障礙,并且暗示著一種比較正式嚴(yán)肅的氣氛,這樣應(yīng)試者就很難放松了。更好的辦法是把桌子靠墻放著,或者和應(yīng)試者坐在桌子的同一邊,這樣有助于應(yīng)試者放松。只有應(yīng)試者不會(huì)因?yàn)榫o張而表現(xiàn)失常,你才能更有效的進(jìn)行面試.

          第二步的內(nèi)容就是問應(yīng)試者最近做了些什么項(xiàng)目。對(duì)剛畢業(yè)的學(xué)生, 如果有論文就問問論文, 沒有的話, 就問問他們做過什么很喜歡的大作業(yè).例如,有時(shí)候我會(huì)問一下,“你最喜歡上學(xué)期哪門課程?不一定要和計(jì)算機(jī)相關(guān)的。”事實(shí)上,如果應(yīng)試者回答的課程和計(jì)算機(jī)沒有關(guān)系,我會(huì)比較高興。有時(shí)候你會(huì)發(fā)現(xiàn)這個(gè)計(jì)算機(jī)系應(yīng)屆生選擇了盡可能少的計(jì)算機(jī)相關(guān)課程,但是卻選修了很多和音樂相關(guān)的課程。但是他(她)卻說最喜歡的課程是《面向?qū)ο髷?shù)據(jù)庫(kù)》。哼哼,不錯(cuò)啊. 不過如果你直接承認(rèn)你喜歡音樂勝于計(jì)算機(jī), 而不是在這兒胡說八道的話, 我會(huì)更高興一點(diǎn)。

          當(dāng)面試有工作經(jīng)驗(yàn)的人時(shí),你可以讓他們談一下前一份工作。

          我問這個(gè)問題的目的是在尋找一樣品質(zhì):熱情。在應(yīng)試者談到他(她)最近做過的項(xiàng)目時(shí),你觀察到以下跡象都是不錯(cuò)的:

          • 談到他們做過的項(xiàng)目時(shí)變得熱情洋溢;他們的語速更快,語言更生動(dòng)活潑。這說明他們對(duì)某些東西有興趣,有熱情(因?yàn)楝F(xiàn)實(shí)中有許多人對(duì)所做的項(xiàng)目根本漠不關(guān)心呢)。即使他們激動(dòng)地表達(dá)對(duì)做過的項(xiàng)目的負(fù)面感情,這也是一個(gè)好的信號(hào)。“我曾經(jīng)為上一個(gè)老板安裝Foo Bar Mark II,但他是個(gè)傻瓜!”表現(xiàn)出熱情的人就是我們要雇傭的人。差的應(yīng)試者對(duì)工作根本就不關(guān)心,所以根本不會(huì)激動(dòng)。一個(gè)非常好的信號(hào)是當(dāng)應(yīng)試者很激動(dòng)地談?wù)撋弦环莨ぷ鳎灾劣跁簳r(shí)忘記了他們正在被面試。有時(shí)候應(yīng)試者剛開始面試時(shí)表現(xiàn)的很緊張 -- 這是很正常的現(xiàn)象,所以我通常忽略不計(jì)。但是當(dāng)他們談到單色計(jì)算藝術(shù)(Computational Monochromatic Art)時(shí),這個(gè)家伙變得極端興奮, 一點(diǎn)都不緊張了。不錯(cuò),我喜歡這樣的應(yīng)試者,因?yàn)樗麄冴P(guān)心他們做的事。(什么是單色計(jì)算藝術(shù)?拔掉你的電腦顯示器的電源就可以看到了)
          • 能認(rèn)真地去解釋事情。某些人被我拒掉的原因就是他們不會(huì)用普通人能明白的語言去解釋他們做過的項(xiàng)目。很多工科專業(yè)的人總是以為所有人都知道Bates理論(譯者注: Bates Theorem,一種經(jīng)濟(jì)學(xué)的理論)或者Peano公理組(譯者注: Peano's Axioms,數(shù)論中的一些定理)是什么。如果應(yīng)試者開始滿口行話了,讓他們停一停,然后你說,“能幫我個(gè)忙嗎?就是為了練習(xí)一下,你能把剛才說的用我老祖母也能理解的話說一遍嗎?”但即便如此, 有些人還是繼續(xù)用那些術(shù)語, 而且根本沒法讓人明白他們?cè)谡f什么。天哪!
          • 如果這個(gè)項(xiàng)目是一個(gè)團(tuán)隊(duì)項(xiàng)目,看看他們是否在有承擔(dān)領(lǐng)導(dǎo)責(zé)任的跡象?一個(gè)應(yīng)試者可能會(huì)說:“我們用的是X方法,但是老板說應(yīng)該是Y,而客戶說應(yīng)該是Z。”我會(huì)問,“那么怎么做的?”一個(gè)好的回答可能是“我設(shè)法和團(tuán)隊(duì)中別的人開了個(gè)會(huì),然后一起搞出個(gè)辦法...”壞的回答看起來象,“嗯,我什么也不能做。這樣的問題我解決不了。”記住,聰明并且能完成工作。要搞清楚某人是否能完成工作的一個(gè)辦法就是看看他(她)過去是否傾向于完成任務(wù)。事實(shí)上,你可以主動(dòng)要求他們給你個(gè)例子證明他們能擔(dān)任領(lǐng)導(dǎo)作用,完成任務(wù)。-例如克服公司的陳規(guī)陋習(xí)。

          現(xiàn)在我們談?wù)勄鍐紊系牡谌睿?em>無法回答的問題。這很有趣。這個(gè)主意的關(guān)鍵在于問一些不可能有答案的問題,就是想看一下應(yīng)試者怎么辦。“西雅圖有多少眼科醫(yī)生?”“華盛頓紀(jì)念碑有多重?”“洛杉機(jī)有多少加油站?”“紐約有多少鋼琴調(diào)音師?”

          • 聰明的應(yīng)試者猜到你不是要測(cè)驗(yàn)他們的專業(yè)知識(shí),他們會(huì)積極地給出一個(gè)估計(jì)。“嗯,洛杉機(jī)的人口是七百萬;每個(gè)人平均擁有2.5輛轎車...”當(dāng)然如果他們的估計(jì)完全錯(cuò)誤了也沒有關(guān)系。重要的是他們能積極地試著回答問題。他們可能會(huì)試著搞清楚每個(gè)加油站的儲(chǔ)量。“嗯,需要四分鐘給一個(gè)儲(chǔ)油罐加滿油,一個(gè)加油站有十個(gè)油泵每天運(yùn)行十八個(gè)小時(shí)...”他們也可能試著從占地面積來估計(jì)。有時(shí), 他們的想法的創(chuàng)造力讓你吃驚. 而有時(shí), 他們直接要一個(gè)LA的黃頁(yè)去查。這都是好跡象。
          • 不聰明的應(yīng)試者則被難住了。他們目瞪口呆地望著你,好像你來自火星。你不得不提示:“嗯,如果你想建立一個(gè)象洛杉機(jī)那么大的城市,你需要建立多少個(gè)加油站?”你還可以提示他們:“加滿一個(gè)儲(chǔ)油罐要多長(zhǎng)時(shí)間?”不過,這些榆木疙瘩腦袋還是只會(huì)坐在那里發(fā)呆,你得拖著他們往前走才行。這類人不會(huì)解決問題,我們可不要這樣的人。

          關(guān)于編程問題,我通常要求應(yīng)試者用C語言寫一些小函數(shù)。以下是我通常會(huì)出的題目:

          1. 將一個(gè)字符串逆序
          2. 將一個(gè)鏈表(linked list)逆序
          3. 計(jì)算一個(gè)字節(jié)(byte)里有多少bit被置1
          4. 搜索給定的字節(jié)(byte)
          5. 在一個(gè)字符串中找到可能的最長(zhǎng)的子字符串,該字符串是由同一字符組成的
          6. 字符串轉(zhuǎn)換成整數(shù)
          7. 整數(shù)轉(zhuǎn)換成字符串(這個(gè)問題很不錯(cuò),因?yàn)閼?yīng)試者要用到堆棧或者strev函數(shù))

          注意,通常你不會(huì)希望他們寫的代碼多于5行,因?yàn)槟銢]有時(shí)間理解太長(zhǎng)的代碼。

          現(xiàn)在我們來詳細(xì)看一看其中幾個(gè)問題: 第一個(gè)問題: 逆序一個(gè)字符串。我這輩子還沒有見過那個(gè)面試者能把這題目一次做對(duì)。所有的應(yīng)試者都試圖動(dòng)態(tài)生成緩沖區(qū),然后將逆序的字符串輸出到該緩沖區(qū)中。問題的關(guān)鍵在于,誰負(fù)責(zé)分配這個(gè)緩沖區(qū)?誰又負(fù)責(zé)釋放那個(gè)緩沖區(qū)?通過這個(gè)問題,我發(fā)現(xiàn)了一個(gè)有趣的事實(shí),就是大多數(shù)認(rèn)為自己懂C的人實(shí)際上不理解指針和內(nèi)存的概念。他們就是不明白。這真叫人吃驚,無法想象這種人也能做程序員。但他們真的就是!這個(gè)問題可以從多個(gè)角度判斷應(yīng)試者:

          • 他們的函數(shù)運(yùn)行快嗎?看一下他們多少此調(diào)用了strlen函數(shù)。我曾經(jīng)看到應(yīng)試者寫的strrev的算法竟然只有O(n^2) 的效率,而標(biāo)準(zhǔn)的算法效率應(yīng)該是O(n),效率如此底下的原因是因?yàn)樗麄冊(cè)谘h(huán)中一次又一次調(diào)用strlen函數(shù)。
          • 他們使用指針運(yùn)算嗎(譯者按:原文為pointer arithmetic,指的是加減指針變量的值)?使用指針運(yùn)算是個(gè)好現(xiàn)象。許多所謂的“C程序員”竟然不知道如何使用指針運(yùn)算(pointer arithmetic)。當(dāng)然,我在前文說過我不會(huì)因?yàn)閼?yīng)試者不掌握一種特定的技巧而拒絕他。但是,理解C語言中的指針不是一種技巧,而是一種與生俱來的才能。每年一所大學(xué)要招進(jìn)200多個(gè)計(jì)算機(jī)系的新生,所有這些小孩子4歲就開始用BASIC語言在Atari 800s寫冒險(xiǎn)游戲了。在大學(xué)里他們還學(xué)Pascal語言,學(xué)得也很棒。直到有一天他們的教授講了指針的概念,突然,他們開始搞不懂了。他們就是不能再理解C語言中的任何東西了。于是90%的計(jì)算機(jī)系學(xué)生轉(zhuǎn)系去學(xué)政治學(xué)。為了挽回面子,他們告訴朋友,他們之所以轉(zhuǎn)系是因?yàn)樗麄冇?jì)算機(jī)系英俊貌美的異性太少。許多人注定腦子里就沒有理解指針的那根弦。所以說理解指針是一種與生俱來的品質(zhì),而不是一種單純的技巧。理解指針需要腦子轉(zhuǎn)好幾個(gè)彎,某些人天生不擅長(zhǎng)轉(zhuǎn)這幾個(gè)彎。

          第三個(gè)問題可以考考面試者對(duì)C的位運(yùn)算的掌握,但這是一種技巧,不是一種品質(zhì),所以你可以幫助他們。有趣的等他們建立了一個(gè)子函數(shù)用來計(jì)算byte中為1的位的數(shù)目,然后你要求他們優(yōu)化這個(gè)子函數(shù),盡量加快這個(gè)函數(shù)的運(yùn)行速度。聰明的應(yīng)試者會(huì)使用查表算法(畢竟這個(gè)表只有 256個(gè)元素,用不了多少內(nèi)存),整個(gè)表只需要建立一次。跟聰明的應(yīng)試者討論一下提高時(shí)間/空間效率的不同策略是十分有意思的事情. 進(jìn)一步告訴他們你不想在程序啟動(dòng)時(shí)初始化查詢表。聰明的面試者可能會(huì)建議使用緩沖機(jī)制,對(duì)于一個(gè)特定的byte,只有在第一次被查詢時(shí)進(jìn)行計(jì)算,然后計(jì)算結(jié)果會(huì)被放入查詢表。這樣以后再被查詢時(shí)直接查表就行了。而特別特別聰明的面試這會(huì)嘗試有沒有建立查詢表的捷徑,如一個(gè)byte和它的置1的bit數(shù)之間有沒有規(guī)律可循? 

          當(dāng)你觀察應(yīng)試者寫C代碼時(shí),以下一些技巧會(huì)對(duì)你有幫助:

          • 事先向應(yīng)試者說明,你完全理解,沒有一個(gè)好的編輯器光在紙上寫代碼是困難的,所以你不在乎他們手寫的代碼是否看上去不整潔。你也完全明白沒有好的編譯器和調(diào)試器,很難第一次就寫出完全沒有bug的程序,所以請(qǐng)他們不必為此擔(dān)心。
          • 好程序員的標(biāo)志:好程序員寫完“{”符號(hào)后,通常立刻跟上“}”符號(hào),然后再在當(dāng)中填上代碼。他們也傾向于使用命名規(guī)則,雖然這個(gè)規(guī)則可能很原始。如果一個(gè)變量用作循環(huán)語句的索引,好程序員通常使用盡可能少的字符為它命名。如果他們的循環(huán)語句的索引變量的名字是CurrentPagePositionLoopCounter,顯而易見他們寫代碼的經(jīng)驗(yàn)還不夠多。偶爾,你會(huì)看到一個(gè)C程序員寫下象if (0==strlen(x))一樣的代碼,常量被放在==的左邊。這是非常好的現(xiàn)象。這說明他因?yàn)榭偸前眩胶停剑礁慊欤呀?jīng)強(qiáng)迫自己養(yǎng)成這種習(xí)慣以避免犯錯(cuò)。
          • 好的程序員在寫代碼前會(huì)訂一個(gè)計(jì)劃,特別是當(dāng)他們的代碼用到了指針時(shí)。例如,如果你要求逆序一個(gè)鏈表,好程序員通常會(huì)在紙的一邊畫上鏈表的草圖,并表明算法中的索引指針當(dāng)前移動(dòng)到的位置。他們不得不這樣做。正常人是不可能不借助草圖就開始寫一個(gè)逆序鏈表的程序的。差的程序員立刻開始寫代碼。

          不可避免的,你會(huì)在他們的程序中發(fā)現(xiàn)bug,于是我們現(xiàn)在來到了第五個(gè)問題:你對(duì)代碼滿意嗎? 你可能想問,“好吧,bug在哪里?”這是來自地獄的一針見血的問題,要回答這個(gè)問題可要大費(fèi)口舌。所有的程序員都會(huì)犯錯(cuò)誤,這不是問題。但他們必須能找到錯(cuò)誤。對(duì)于字符串操作的函數(shù),他們通常會(huì)忘記在輸出緩沖區(qū)加上字符串結(jié)束符。所有的函數(shù),他們都會(huì)犯off-by-one錯(cuò)誤(譯者按:指的是某個(gè)變量的最大值和最小值可能會(huì)和正常值差1)。他們會(huì)忘掉正常的C語句結(jié)尾的分號(hào)。如果輸入是零長(zhǎng)度字符串,他們的函數(shù)會(huì)運(yùn)行錯(cuò)誤。如果malloc調(diào)用失敗而他們沒有為此寫好錯(cuò)誤處理代碼,程序會(huì)崩潰。一次就能把所有事情做對(duì)的程序員非常,非常,非常地少.不過要是真的碰上一個(gè)的話, 提問就更有意思了. 你說,"還有Bug"。他們會(huì)再仔細(xì)地檢查一遍代碼。這個(gè)時(shí)候, 觀察一下他們內(nèi)心是否開始動(dòng)搖了, 只是表面上勉強(qiáng)堅(jiān)持說代碼沒有問題。總之,在程序員寫完代碼后,問一下他們是否對(duì)代碼滿意是個(gè)好主意。就像Regis那樣問他們!(譯者按,Regis Philbin是美國(guó)ABC電視網(wǎng)的游戲電視節(jié)目主持人,他的口頭禪是“這是你的最后的答案嗎?”)

          第六部分:關(guān)于設(shè)計(jì)的問題。讓應(yīng)試者設(shè)計(jì)某樣?xùn)|西。Jabe Blumenthal,Excel的原始設(shè)計(jì)者,喜歡讓應(yīng)試者設(shè)計(jì)房子。Jabe說,曾經(jīng)有一個(gè)應(yīng)試者跑到白板前,畫了一個(gè)方塊,這就是他的全部設(shè)計(jì)。天哪,一個(gè)方塊!立刻拒絕這樣的家伙。你喜歡問什么樣的設(shè)計(jì)問題?

          • 好的程序員會(huì)問更多的信息。房子為誰造的?我們公司的政策是,我們不會(huì)雇傭那些在設(shè)計(jì)前不問為誰設(shè)計(jì)的人。通常,我會(huì)很煩惱我得打斷他們的設(shè)計(jì),說“事實(shí)上,你忘記問這個(gè)房子是給誰設(shè)計(jì)的了。這個(gè)房子是給一群長(zhǎng)頸鹿造的。”
          • 笨笨的應(yīng)試者認(rèn)為設(shè)計(jì)就像畫畫,你想畫什么就畫什么。聰明的應(yīng)試者明白設(shè)計(jì)的過程是一系列艱難的權(quán)衡。一個(gè)很棒的設(shè)計(jì)問題是:設(shè)計(jì)一個(gè)放在街角的垃圾箱。想一想你得做多少權(quán)衡!垃圾箱必須易于清空,但是很難被偷走;易于放進(jìn)垃圾,但是碰到狂風(fēng)大作,里面的垃圾不會(huì)被吹出來;垃圾箱必須堅(jiān)固而便宜。在某些城市,垃圾箱必須特別設(shè)計(jì),以防恐怖分子在里面藏一個(gè)定時(shí)炸彈。
          • 有創(chuàng)造力的應(yīng)試者會(huì)給出有趣而獨(dú)特的設(shè)計(jì)。我最喜歡的問題之一是為盲人設(shè)計(jì)一個(gè)放調(diào)味品的架子(譯者按:原文為spice rack,老外的廚房里有個(gè)專門放調(diào)味品的架子,上面放了很多小罐罐,里面裝了各種各樣的調(diào)料)通常許多應(yīng)試者的建議是把布萊葉文(一種盲人使用的文字)刻在放調(diào)料的罐子上,這樣文字會(huì)卷起來而變形。我碰到一個(gè)應(yīng)試者,他的設(shè)計(jì)是把調(diào)料放在抽屜里,因?yàn)樗X得水平地感知布萊葉文比垂直地做更方便。(試試看!)這個(gè)答案這樣有創(chuàng)意,使我震驚!我面試了有一打得程序員,從來沒有人想到過類似的答案。這樣有創(chuàng)意的答案確實(shí)躍過了普通人考慮問題的條條框框。僅僅因?yàn)檫@個(gè)答案太有創(chuàng)意了,而且應(yīng)試者別的方面還過得去,我雇傭了這個(gè)應(yīng)試者,他現(xiàn)在已經(jīng)成為Excel團(tuán)隊(duì)中一個(gè)優(yōu)秀的項(xiàng)目經(jīng)理了(譯者按,本文作者曾在微軟工作過)。
          • 總是爭(zhēng)取一個(gè)確定的了結(jié)。這也是完成工作的特質(zhì)的一部分。有時(shí)候應(yīng)試者會(huì)猶猶豫豫不能作出一個(gè)決定,試圖回避困難的問題,留著困難的問題不作決定就直接向下進(jìn)行,這很不好。好的應(yīng)試者有一種推動(dòng)事情自然地前進(jìn)的傾向,即使你有意把他們拖回來。如果關(guān)于某個(gè)話題的討論開始原地打轉(zhuǎn)變得沒有意義了,好的應(yīng)試者會(huì)說,“嗯,我們可以整天談?wù)撨@個(gè),但是我們得做點(diǎn)什么。為什么我們不開始...”

          于是我們來到了第七部分,挑戰(zhàn)。這部分很好玩。在面試中留心一下, 當(dāng)面試者的回答絕對(duì)的百分之百毫無爭(zhēng)議時(shí), 你可以說: " 嗯, 等一下等一下." 然后花上兩分鐘玩一下魔鬼的游戲(譯者按,原文為devil's advocate,魔鬼代言人指的是違背自己的良知,為錯(cuò)誤邪惡的觀點(diǎn)辯護(hù)). 記住一定要在你可以肯定他正確時(shí)和他爭(zhēng)論。

          這個(gè)很有意思.  
          • 軟弱的應(yīng)試者會(huì)屈服。那我就和他說拜拜了。
          • 堅(jiān)定的應(yīng)試者會(huì)找到一個(gè)辦法說服你。他們會(huì)以肯尼迪總統(tǒng)的口才來說服你,“也許我誤會(huì)了你的意思,”他們這樣開頭,但是正文仍是堅(jiān)定地站穩(wěn)立場(chǎng)。這樣的人我就雇傭

          不得不承認(rèn),面試雙方的地位并不是平等的。有可能應(yīng)試者由于害怕你的權(quán)力而不敢于你爭(zhēng)辯。但是,好的應(yīng)試者有足夠的熱情和勇氣堅(jiān)持正確的觀點(diǎn),他們由于熱切希望說服你而會(huì)暫時(shí)忘記正在被面試。這樣的人就是我們要雇傭的人。

          最后,可以問一下應(yīng)試者有什么想問的。一些人喜歡看看應(yīng)試者這時(shí)是否會(huì)問一些聰明的問題。這是市面上流行的面試書籍的標(biāo)準(zhǔn)技巧。我個(gè)人不在乎應(yīng)試者問什么,因?yàn)檫@時(shí)我已經(jīng)做了決定。麻煩在于,應(yīng)試者也許已經(jīng)見了5、6個(gè)人,進(jìn)行了好幾輪面試,他們可能很累了,以至于不能為每輪面試都準(zhǔn)備一個(gè)聰明而獨(dú)特的問題。所以如果他們沒有可問的,沒關(guān)系。

          我總是留下面試的最后5分鐘來推銷我的公司。這很重要。即使我不打算雇傭眼前這個(gè)應(yīng)試者。如果你幸運(yùn)的找到一個(gè)很棒的應(yīng)試者,你當(dāng)然愿意做任何事情說服他(她)來你的公司。即使他們不是好的應(yīng)試者,你也要盡力讓他們?yōu)镕og Creek公司激動(dòng),這樣面試結(jié)束時(shí)他們會(huì)對(duì)Fog Creek公司留下一個(gè)很好的印象。記住,應(yīng)試者并不僅僅是可能的雇員,他們也是顧客,也是我們公司的推銷員。如果他們覺得我們的公司很棒,他們也許會(huì)推薦朋友來面試。

          啊哈,我記得我說過我會(huì)給出一些應(yīng)該避免的非常不好的反面的試題例子。

          首先,避免不合法的問題。有關(guān)種族,宗教,性別,出生國(guó),年齡,服役記錄,是否老兵,性取向,生理障礙的問題都是不合法的。即使他們的簡(jiǎn)歷說他們1990年在軍中服役,也不要問有關(guān)問題。也許這會(huì)讓他們愉快地談?wù)撛诤硲?zhàn)爭(zhēng)中的經(jīng)歷。但是你的問題還是不合法的。如果簡(jiǎn)歷上寫著他們上過Technion in Haifa, 不要問他們是否是以色列人, 即使只是為了閑談, 因?yàn)檫@是違法的. 下面有一個(gè)很好的不合法的例子。點(diǎn)擊這里有很多關(guān)于什么是違法的討論。(但是這個(gè)網(wǎng)站的其余問題夠愚蠢的。)

          其次,不要在問題中給予應(yīng)試者暗示,我們公司喜歡或者不喜歡什么樣的員工。我能想到的一個(gè)例子是問應(yīng)試者是否有小孩或者是否結(jié)婚了。應(yīng)試者也許會(huì)想我們不喜歡有家庭拖累的員工。

          最后,不要問那些腦筋急轉(zhuǎn)彎的題目,例如6根火柴怎么拼出4個(gè)三角形。象這樣的靈機(jī)一動(dòng)的問題是不能看出應(yīng)試者是否有“有頭腦/完成工作”的品質(zhì)。

          面試與其說是科學(xué)不如說是藝術(shù)。但是只要你記住有頭腦/完成工作這個(gè)原則,你就可以應(yīng)對(duì)自如。有機(jī)會(huì)就問問你的同事他們喜歡的面試問題和答案。這是我們公司員工午飯時(shí)熱衷的話題之一。

          本文最先用英文出版,題為 The Guerrilla Guide to Interviewing

          作者簡(jiǎn)介   Joel Spolsky 是紐約市一家小軟件公司,Fog Creek Software, 的創(chuàng)始人。他畢業(yè)于耶魯大學(xué),曾在美國(guó)微軟公司,Viacom,  Juno 任軟件設(shè)計(jì)師及經(jīng)理。

           

           

          [顯示打印版本]

          相關(guān)文章

          • No Relative Articles.

          相關(guān)評(píng)論   發(fā)表評(píng)論

          • No Comments
          posted @ 2008-11-04 21:29 poower 閱讀(225) | 評(píng)論 (0)編輯 收藏

          想成為嵌入式程序員應(yīng)知道的0x10個(gè)基本問題

          簡(jiǎn)述:

          這是嵌入式C程序員的基本知識(shí)。作者在Embedded Systems Programming雜志上發(fā)表了很多嵌入式系統(tǒng)開發(fā)方面的文章。

          作者:Jones Nigel   更新日期:2005-04-08
          來源:internet   瀏覽次數(shù):

                  C語言測(cè)試是招聘嵌入式系統(tǒng)程序員過程中必須而且有效的方法。這些年,我既參加也組織了許多這種測(cè)試,在這過程中我意識(shí)到這些測(cè)試能為面試者和被面試者提供許多有用信息,此外,撇開面試的壓力不談,這種測(cè)試也是相當(dāng)有趣的。
                  從被面試者的角度來講,你能了解許多關(guān)于出題者或監(jiān)考者的情況。這個(gè)測(cè)試只是出題者為顯示其對(duì)ANSI標(biāo)準(zhǔn)細(xì)節(jié)的知識(shí)而不是技術(shù)技巧而設(shè)計(jì)嗎?這是個(gè)愚蠢的問題嗎?如要你答出某個(gè)字符的ASCII值。這些問題著重考察你的系統(tǒng)調(diào)用和內(nèi)存分配策略方面的能力嗎?這標(biāo)志著出題者也許花時(shí)間在微機(jī)上而不是在嵌入式系統(tǒng)上。如果上述任何問題的答案是"是"的話,那么我知道我得認(rèn)真考慮我是否應(yīng)該去做這份工作。
                  從面試者的角度來講,一個(gè)測(cè)試也許能從多方面揭示應(yīng)試者的素質(zhì):最基本的,你能了解應(yīng)試者C語言的水平。不管怎么樣,看一下這人如何回答他不會(huì)的問題也是滿有趣。應(yīng)試者是以好的直覺做出明智的選擇,還是只是瞎蒙呢?當(dāng)應(yīng)試者在某個(gè)問題上卡住時(shí)是找借口呢,還是表現(xiàn)出對(duì)問題的真正的好奇心,把這看成學(xué)習(xí)的機(jī)會(huì)呢?我發(fā)現(xiàn)這些信息與他們的測(cè)試成績(jī)一樣有用。
                  有了這些想法,我決定出一些真正針對(duì)嵌入式系統(tǒng)的考題,希望這些令人頭痛的考題能給正在找工作的人一點(diǎn)幫助。這些問題都是我這些年實(shí)際碰到的。其中有些題很難,但它們應(yīng)該都能給你一點(diǎn)啟迪。
                  這個(gè)測(cè)試適于不同水平的應(yīng)試者,大多數(shù)初級(jí)水平的應(yīng)試者的成績(jī)會(huì)很差,經(jīng)驗(yàn)豐富的程序員應(yīng)該有很好的成績(jī)。為了讓你能自己決定某些問題的偏好,每個(gè)問題沒有分配分?jǐn)?shù),如果選擇這些考題為你所用,請(qǐng)自行按你的意思分配分?jǐn)?shù)。

          預(yù)處理器(Preprocessor)

          1 . 用預(yù)處理指令#define 聲明一個(gè)常數(shù),用以表明1年中有多少秒(忽略閏年問題)
                   #define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL
          我在這想看到幾件事情:
          1) #define 語法的基本知識(shí)(例如:不能以分號(hào)結(jié)束,括號(hào)的使用,等等)
          2)懂得預(yù)處理器將為你計(jì)算常數(shù)表達(dá)式的值,因此,直接寫出你是如何計(jì)算一年中有多少秒而不是計(jì)算出實(shí)際的值,是更清晰而沒有代價(jià)的。
          3) 意識(shí)到這個(gè)表達(dá)式將使一個(gè)16位機(jī)的整型數(shù)溢出-因此要用到長(zhǎng)整型符號(hào)L,告訴編譯器這個(gè)常數(shù)是的長(zhǎng)整型數(shù)。
          4) 如果你在你的表達(dá)式中用到UL(表示無符號(hào)長(zhǎng)整型),那么你有了一個(gè)好的起點(diǎn)。記住,第一印象很重要。

          2 . 寫一個(gè)"標(biāo)準(zhǔn)"宏MIN ,這個(gè)宏輸入兩個(gè)參數(shù)并返回較小的一個(gè)。
                  #define MIN(A,B) ((A) <= (B) ? (A) : (B))
          這個(gè)測(cè)試是為下面的目的而設(shè)的:
          1) 標(biāo)識(shí)#define在宏中應(yīng)用的基本知識(shí)。這是很重要的。因?yàn)樵?nbsp; 嵌入(inline)操作符 變?yōu)闃?biāo)準(zhǔn)C的一部分之前,宏是方便產(chǎn)生嵌入代碼的唯一方法,對(duì)于嵌入式系統(tǒng)來說,為了能達(dá)到要求的性能,嵌入代碼經(jīng)常是必須的方法。
          2)三重條件操作符的知識(shí)。這個(gè)操作符存在C語言中的原因是它使得編譯器能產(chǎn)生比if-then-else更優(yōu)化的代碼,了解這個(gè)用法是很重要的。
          3) 懂得在宏中小心地把參數(shù)用括號(hào)括起來
          4) 我也用這個(gè)問題開始討論宏的副作用,例如:當(dāng)你寫下面的代碼時(shí)會(huì)發(fā)生什么事?
                  least = MIN(*p++, b);

          3. 預(yù)處理器標(biāo)識(shí)#error的目的是什么?
          如果你不知道答案,請(qǐng)看參考文獻(xiàn)1。這問題對(duì)區(qū)分一個(gè)正常的伙計(jì)和一個(gè)書呆子是很有用的。只有書呆子才會(huì)讀C語言課本的附錄去找出象這種問題的答案。當(dāng)然如果你不是在找一個(gè)書呆子,那么應(yīng)試者最好希望自己不要知道答案。


          死循環(huán)(Infinite loops)

          4. 嵌入式系統(tǒng)中經(jīng)常要用到無限循環(huán),你怎么樣用C編寫死循環(huán)呢?
          這個(gè)問題用幾個(gè)解決方案。我首選的方案是:

          while(1)
          {

          }

          一些程序員更喜歡如下方案:

          for(;;)
          {

          }

          這個(gè)實(shí)現(xiàn)方式讓我為難,因?yàn)檫@個(gè)語法沒有確切表達(dá)到底怎么回事。如果一個(gè)應(yīng)試者給出這個(gè)作為方案,我將用這個(gè)作為一個(gè)機(jī)會(huì)去探究他們這樣做的基本原理。如果他們的基本答案是:"我被教著這樣做,但從沒有想到過為什么。"這會(huì)給我留下一個(gè)壞印象。

          第三個(gè)方案是用 goto
          Loop:
          ...
          goto Loop;
          應(yīng)試者如給出上面的方案,這說明或者他是一個(gè)匯編語言程序員(這也許是好事)或者他是一個(gè)想進(jìn)入新領(lǐng)域的BASIC/FORTRAN程序員。


          數(shù)據(jù)聲明(Data declarations)

          5. 用變量a給出下面的定義
          a) 一個(gè)整型數(shù)(An integer)
          b)一個(gè)指向整型數(shù)的指針( A pointer to an integer)
          c)一個(gè)指向指針的的指針,它指向的指針是指向一個(gè)整型數(shù)( A pointer to a pointer to an intege)r
          d)一個(gè)有10個(gè)整型數(shù)的數(shù)組( An array of 10 integers)
          e) 一個(gè)有10個(gè)指針的數(shù)組,該指針是指向一個(gè)整型數(shù)的。(An array of 10 pointers to integers)
          f) 一個(gè)指向有10個(gè)整型數(shù)數(shù)組的指針( A pointer to an array of 10 integers)
          g) 一個(gè)指向函數(shù)的指針,該函數(shù)有一個(gè)整型參數(shù)并返回一個(gè)整型數(shù)(A pointer to a function that takes an integer as an argument and returns an integer)
          h) 一個(gè)有10個(gè)指針的數(shù)組,該指針指向一個(gè)函數(shù),該函數(shù)有一個(gè)整型參數(shù)并返回一個(gè)整型數(shù)( An array of ten pointers to functions that take an integer argument and return an integer )

          答案是:
          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 functions that take an integer argument and return an integer

          人們經(jīng)常聲稱這里有幾個(gè)問題是那種要翻一下書才能回答的問題,我同意這種說法。當(dāng)我寫這篇文章時(shí),為了確定語法的正確性,我的確查了一下書。但是當(dāng)我被面試的時(shí)候,我期望被問到這個(gè)問題(或者相近的問題)。因?yàn)樵诒幻嬖嚨倪@段時(shí)間里,我確定我知道這個(gè)問題的答案。應(yīng)試者如果不知道所有的答案(或至少大部分答案),那么也就沒有為這次面試做準(zhǔn)備,如果該面試者沒有為這次面試做準(zhǔn)備,那么他又能為什么出準(zhǔn)備呢?

          Static

          6. 關(guān)鍵字static的作用是什么?
          這個(gè)簡(jiǎn)單的問題很少有人能回答完全。在C語言中,關(guān)鍵字static有三個(gè)明顯的作用:
          1)在函數(shù)體,一個(gè)被聲明為靜態(tài)的變量在這一函數(shù)被調(diào)用過程中維持其值不變。
          2) 在模塊內(nèi)(但在函數(shù)體外),一個(gè)被聲明為靜態(tài)的變量可以被模塊內(nèi)所用函數(shù)訪問,但不能被模塊外其它函數(shù)訪問。它是一個(gè)本地的全局變量。
          3) 在模塊內(nèi),一個(gè)被聲明為靜態(tài)的函數(shù)只可被這一模塊內(nèi)的其它函數(shù)調(diào)用。那就是,這個(gè)函數(shù)被限制在聲明它的模塊的本地范圍內(nèi)使用。

          大多數(shù)應(yīng)試者能正確回答第一部分,一部分能正確回答第二部分,同是很少的人能懂得第三部分。這是一個(gè)應(yīng)試者的嚴(yán)重的缺點(diǎn),因?yàn)樗@然不懂得本地化數(shù)據(jù)和代碼范圍的好處和重要性。


          Const

          7.關(guān)鍵字const有什么含意?
          我只要一聽到被面試者說:"const意味著常數(shù)",我就知道我正在和一個(gè)業(yè)余者打交道。去年Dan Saks已經(jīng)在他的文章里完全概括了const的所有用法,因此ESP(譯者:Embedded Systems Programming)的每一位讀者應(yīng)該非常熟悉const能做什么和不能做什么.如果你從沒有讀到那篇文章,只要能說出const意味著"只讀"就可以了。盡管這個(gè)答案不是完全的答案,但我接受它作為一個(gè)正確的答案。(如果你想知道更詳細(xì)的答案,仔細(xì)讀一下Saks的文章吧。)
          如果應(yīng)試者能正確回答這個(gè)問題,我將問他一個(gè)附加的問題:
          下面的聲明都是什么意思?

          const int a;
          int const a;
          const int *a;
          int * const a;
          int const * a const;

          /******/
          前兩個(gè)的作用是一樣,a是一個(gè)常整型數(shù)。第三個(gè)意味著a是一個(gè)指向常整型數(shù)的指針(也就是,整型數(shù)是不可修改的,但指針可以)。第四個(gè)意思a是一個(gè)指向整型數(shù)的常指針(也就是說,指針指向的整型數(shù)是可以修改的,但指針是不可修改的)。最后一個(gè)意味著a是一個(gè)指向常整型數(shù)的常指針(也就是說,指針指向的整型數(shù)是不可修改的,同時(shí)指針也是不可修改的)。如果應(yīng)試者能正確回答這些問題,那么他就給我留下了一個(gè)好印象。順帶提一句,也許你可能會(huì)問,即使不用關(guān)鍵字 const,也還是能很容易寫出功能正確的程序,那么我為什么還要如此看重關(guān)鍵字const呢?我也如下的幾下理由:
          1) 關(guān)鍵字const的作用是為給讀你代碼的人傳達(dá)非常有用的信息,實(shí)際上,聲明一個(gè)參數(shù)為常量是為了告訴了用戶這個(gè)參數(shù)的應(yīng)用目的。如果你曾花很多時(shí)間清理其它人留下的垃圾,你就會(huì)很快學(xué)會(huì)感謝這點(diǎn)多余的信息。(當(dāng)然,懂得用const的程序員很少會(huì)留下的垃圾讓別人來清理的。)
          2) 通過給優(yōu)化器一些附加的信息,使用關(guān)鍵字const也許能產(chǎn)生更緊湊的代碼。
          3) 合理地使用關(guān)鍵字const可以使編譯器很自然地保護(hù)那些不希望被改變的參數(shù),防止其被無意的代碼修改。簡(jiǎn)而言之,這樣可以減少bug的出現(xiàn)。


          Volatile

          8. 關(guān)鍵字volatile有什么含意?并給出三個(gè)不同的例子。
          一個(gè)定義為volatile的變量是說這變量可能會(huì)被意想不到地改變,這樣,編譯器就不會(huì)去假設(shè)這個(gè)變量的值了。精確地說就是,優(yōu)化器在用到這個(gè)變量時(shí)必須每次都小心地重新讀取這個(gè)變量的值,而不是使用保存在寄存器里的備份。下面是volatile變量的幾個(gè)例子:
          1) 并行設(shè)備的硬件寄存器(如:狀態(tài)寄存器)
          2) 一個(gè)中斷服務(wù)子程序中會(huì)訪問到的非自動(dòng)變量(Non-automatic variables)
          3) 多線程應(yīng)用中被幾個(gè)任務(wù)共享的變量

          回答不出這個(gè)問題的人是不會(huì)被雇傭的。我認(rèn)為這是區(qū)分C程序員和嵌入式系統(tǒng)程序員的最基本的問題。搞嵌入式的家伙們經(jīng)常同硬件、中斷、RTOS等等打交道,所有這些都要求用到volatile變量。不懂得volatile的內(nèi)容將會(huì)帶來災(zāi)難。
          假設(shè)被面試者正確地回答了這是問題(嗯,懷疑是否會(huì)是這樣),我將稍微深究一下,看一下這家伙是不是直正懂得volatile完全的重要性。
          1)一個(gè)參數(shù)既可以是const還可以是volatile嗎?解釋為什么。
          2); 一個(gè)指針可以是volatile 嗎?解釋為什么。
          3); 下面的函數(shù)有什么錯(cuò)誤:

          int square(volatile int *ptr)
          {
                  return *ptr * *ptr;
          }

          下面是答案:
          1)是的。一個(gè)例子是只讀的狀態(tài)寄存器。它是volatile因?yàn)樗赡鼙灰庀氩坏降馗淖儭K莄onst因?yàn)槌绦虿粦?yīng)該試圖去修改它。
          2); 是的。盡管這并不很常見。一個(gè)例子是當(dāng)一個(gè)中服務(wù)子程序修該一個(gè)指向一個(gè)buffer的指針時(shí)。
          3) 這段代碼有點(diǎn)變態(tài)。這段代碼的目的是用來返指針*ptr指向值的平方,但是,由于*ptr指向一個(gè)volatile型參數(shù),編譯器將產(chǎn)生類似下面的代碼:

          int square(volatile int *ptr)
          {
              int a,b;
              a = *ptr;
              b = *ptr;
              return a * b;
          }

          由于*ptr的值可能被意想不到地該變,因此a和b可能是不同的。結(jié)果,這段代碼可能返不是你所期望的平方值!正確的代碼如下:

          long square(volatile int *ptr)
          {
              int a;
              a = *ptr;
              return a * a;
          }

          位操作(Bit manipulation)

          9. 嵌入式系統(tǒng)總是要用戶對(duì)變量或寄存器進(jìn)行位操作。給定一個(gè)整型變量a,寫兩段代碼,第一個(gè)設(shè)置a的bit 3,第二個(gè)清除a 的bit 3。在以上兩個(gè)操作中,要保持其它位不變。
          對(duì)這個(gè)問題有三種基本的反應(yīng)
          1)不知道如何下手。該被面者從沒做過任何嵌入式系統(tǒng)的工作。
          2) 用bit fields。Bit fields是被扔到C語言死角的東西,它保證你的代碼在不同編譯器之間是不可移植的,同時(shí)也保證了的你的代碼是不可重用的。我最近不幸看到 Infineon為其較復(fù)雜的通信芯片寫的驅(qū)動(dòng)程序,它用到了bit fields因此完全對(duì)我無用,因?yàn)槲业木幾g器用其它的方式來實(shí)現(xiàn)bit fields的。從道德講:永遠(yuǎn)不要讓一個(gè)非嵌入式的家伙粘實(shí)際硬件的邊。
          3) 用 #defines 和 bit masks 操作。這是一個(gè)有極高可移植性的方法,是應(yīng)該被用到的方法。最佳的解決方案如下:

          #define BIT3 (0x1 << 3)
          static int a;

          void set_bit3(void)
          {
              a |= BIT3;
          }
          void clear_bit3(void)
          {
              a &= ~BIT3;
          }

          一些人喜歡為設(shè)置和清除值而定義一個(gè)掩碼同時(shí)定義一些說明常數(shù),這也是可以接受的。我希望看到幾個(gè)要點(diǎn):說明常數(shù)、|=和&=~操作。


          訪問固定的內(nèi)存位置(Accessing fixed memory locations)

          10. 嵌入式系統(tǒng)經(jīng)常具有要求程序員去訪問某特定的內(nèi)存位置的特點(diǎn)。在某工程中,要求設(shè)置一絕對(duì)地址為0x67a9的整型變量的值為0xaa66。編譯器是一個(gè)純粹的ANSI編譯器。寫代碼去完成這一任務(wù)。
          這一問題測(cè)試你是否知道為了訪問一絕對(duì)地址把一個(gè)整型數(shù)強(qiáng)制轉(zhuǎn)換(typecast)為一指針是合法的。這一問題的實(shí)現(xiàn)方式隨著個(gè)人風(fēng)格不同而不同。典型的類似代碼如下:
              int *ptr;
              ptr = (int *)0x67a9;
              *ptr = 0xaa55;

           A more obscure approach is:
          一個(gè)較晦澀的方法是:

              *(int * const)(0x67a9) = 0xaa55;

          即使你的品味更接近第二種方案,但我建議你在面試時(shí)使用第一種方案。

          中斷(Interrupts)

          11. 中斷是嵌入式系統(tǒng)中重要的組成部分,這導(dǎo)致了很多編譯開發(fā)商提供一種擴(kuò)展—讓標(biāo)準(zhǔn)C支持中斷。具代表事實(shí)是,產(chǎn)生了一個(gè)新的關(guān)鍵字 __interrupt。下面的代碼就使用了__interrupt關(guān)鍵字去定義了一個(gè)中斷服務(wù)子程序(ISR),請(qǐng)?jiān)u論一下這段代碼的。

          __interrupt double compute_area (double radius)
          {
              double area = PI * radius * radius;
              printf("\nArea = %f", area);
              return area;
          }

          這個(gè)函數(shù)有太多的錯(cuò)誤了,以至讓人不知從何說起了:
          1)ISR 不能返回一個(gè)值。如果你不懂這個(gè),那么你不會(huì)被雇用的。
          2) ISR 不能傳遞參數(shù)。如果你沒有看到這一點(diǎn),你被雇用的機(jī)會(huì)等同第一項(xiàng)。
          3) 在許多的處理器/編譯器中,浮點(diǎn)一般都是不可重入的。有些處理器/編譯器需要讓額處的寄存器入棧,有些處理器/編譯器就是不允許在ISR中做浮點(diǎn)運(yùn)算。此外,ISR應(yīng)該是短而有效率的,在ISR中做浮點(diǎn)運(yùn)算是不明智的。
          4) 與第三點(diǎn)一脈相承,printf()經(jīng)常有重入和性能上的問題。如果你丟掉了第三和第四點(diǎn),我不會(huì)太為難你的。不用說,如果你能得到后兩點(diǎn),那么你的被雇用前景越來越光明了。


          代碼例子(Code examples)

          12 . 下面的代碼輸出是什么,為什么?

          void foo(void)
          {
              unsigned int a = 6;
              int b = -20;
              (a+b > 6) ? puts("> 6") : puts("<= 6");
          }
          這個(gè)問題測(cè)試你是否懂得C語言中的整數(shù)自動(dòng)轉(zhuǎn)換原則,我發(fā)現(xiàn)有些開發(fā)者懂得極少這些東西。不管如何,這無符號(hào)整型問題的答案是輸出是 ">6"。原因是當(dāng)表達(dá)式中存在有符號(hào)類型和無符號(hào)類型時(shí)所有的操作數(shù)都自動(dòng)轉(zhuǎn)換為無符號(hào)類型。因此-20變成了一個(gè)非常大的正整數(shù),所以該表達(dá)式計(jì)算出的結(jié)果大于6。這一點(diǎn)對(duì)于應(yīng)當(dāng)頻繁用到無符號(hào)數(shù)據(jù)類型的嵌入式系統(tǒng)來說是豐常重要的。如果你答錯(cuò)了這個(gè)問題,你也就到了得不到這份工作的邊緣。

          13. 評(píng)價(jià)下面的代碼片斷:

          unsigned int zero = 0;
          unsigned int compzero = 0xFFFF;
          /*1's complement of zero */

          對(duì)于一個(gè)int型不是16位的處理器為說,上面的代碼是不正確的。應(yīng)編寫如下:

          unsigned int compzero = ~0;

          這一問題真正能揭露出應(yīng)試者是否懂得處理器字長(zhǎng)的重要性。在我的經(jīng)驗(yàn)里,好的嵌入式程序員非常準(zhǔn)確地明白硬件的細(xì)節(jié)和它的局限,然而PC機(jī)程序往往把硬件作為一個(gè)無法避免的煩惱。
          到了這個(gè)階段,應(yīng)試者或者完全垂頭喪氣了或者信心滿滿志在必得。如果顯然應(yīng)試者不是很好,那么這個(gè)測(cè)試就在這里結(jié)束了。但如果顯然應(yīng)試者做得不錯(cuò),那么我就扔出下面的追加問題,這些問題是比較難的,我想僅僅非常優(yōu)秀的應(yīng)試者能做得不錯(cuò)。提出這些問題,我希望更多看到應(yīng)試者應(yīng)付問題的方法,而不是答案。不管如何,你就當(dāng)是這個(gè)娛樂吧...


          動(dòng)態(tài)內(nèi)存分配(Dynamic memory allocation)

          14. 盡管不像非嵌入式計(jì)算機(jī)那么常見,嵌入式系統(tǒng)還是有從堆(heap)中動(dòng)態(tài)分配內(nèi)存的過程的。那么嵌入式系統(tǒng)中,動(dòng)態(tài)分配內(nèi)存可能發(fā)生的問題是什么?
          這里,我期望應(yīng)試者能提到內(nèi)存碎片,碎片收集的問題,變量的持行時(shí)間等等。這個(gè)主題已經(jīng)在ESP雜志中被廣泛地討論過了(主要是 P.J. Plauger, 他的解釋遠(yuǎn)遠(yuǎn)超過我這里能提到的任何解釋),所有回過頭看一下這些雜志吧!讓應(yīng)試者進(jìn)入一種虛假的安全感覺后,我拿出這么一個(gè)小節(jié)目:
          下面的代碼片段的輸出是什么,為什么?

          char *ptr;
          if ((ptr = (char *)malloc(0)) == NULL)
              puts("Got a null pointer");
          else
              puts("Got a valid pointer");

          這是一個(gè)有趣的問題。最近在我的一個(gè)同事不經(jīng)意把0值傳給了函數(shù)malloc,得到了一個(gè)合法的指針之后,我才想到這個(gè)問題。這就是上面的代碼,該代碼的輸出是"Got a valid pointer"。我用這個(gè)來開始討論這樣的一問題,看看被面試者是否想到庫(kù)例程這樣做是正確。得到正確的答案固然重要,但解決問題的方法和你做決定的基本原理更重要些。

          Typedef
           
          15 Typedef 在C語言中頻繁用以聲明一個(gè)已經(jīng)存在的數(shù)據(jù)類型的同義字。也可以用預(yù)處理器做類似的事。例如,思考一下下面的例子:

          #define dPS struct s *
          typedef struct s * tPS;

          以上兩種情況的意圖都是要定義dPS 和 tPS 作為一個(gè)指向結(jié)構(gòu)s指針。哪種方法更好呢?(如果有的話)為什么?
          這是一個(gè)非常微妙的問題,任何人答對(duì)這個(gè)問題(正當(dāng)?shù)脑颍┦菓?yīng)當(dāng)被恭喜的。答案是:typedef更好。思考下面的例子:

          dPS p1,p2;
          tPS p3,p4;

          第一個(gè)擴(kuò)展為

          struct s * p1, p2;
          .
          上面的代碼定義p1為一個(gè)指向結(jié)構(gòu)的指,p2為一個(gè)實(shí)際的結(jié)構(gòu),這也許不是你想要的。第二個(gè)例子正確地定義了p3 和p4 兩個(gè)指針。



          晦澀的語法

          16 . C語言同意一些令人震驚的結(jié)構(gòu),下面的結(jié)構(gòu)是合法的嗎,如果是它做些什么?

          int a = 5, b = 7, c;
          c = a+++b;

          這個(gè)問題將做為這個(gè)測(cè)驗(yàn)的一個(gè)愉快的結(jié)尾。不管你相不相信,上面的例子是完全合乎語法的。問題是編譯器如何處理它?水平不高的編譯作者實(shí)際上會(huì)爭(zhēng)論這個(gè)問題,根據(jù)最處理原則,編譯器應(yīng)當(dāng)能處理盡可能所有合法的用法。因此,上面的代碼被處理成:

          c = a++ + b;

          因此, 這段代碼持行后a = 6, b = 7, c = 12。
          如果你知道答案,或猜出正確答案,做得好。如果你不知道答案,我也不把這個(gè)當(dāng)作問題。我發(fā)現(xiàn)這個(gè)問題的最大好處是這是一個(gè)關(guān)于代碼編寫風(fēng)格,代碼的可讀性,代碼的可修改性的好的話題。


          好了,伙計(jì)們,你現(xiàn)在已經(jīng)做完所有的測(cè)試了。這就是我出的C語言測(cè)試題,我懷著愉快的心情寫完它,希望你以同樣的心情讀完它。如果是認(rèn)為這是一個(gè)好的測(cè)試,那么盡量都用到你的找工作的過程中去吧。天知道也許過個(gè)一兩年,我就不做現(xiàn)在的工作,也需要找一個(gè)。

          作者介紹:
                  Nigel Jones 是一個(gè)顧問,現(xiàn)在住在Maryland,當(dāng)他不在水下時(shí),你能在多個(gè)范圍的嵌入項(xiàng)目中找到他。 他很高興能收到讀者的來信,他的email地址是: NAJones@compuserve.com

          參考文獻(xiàn)
          1) Jones, Nigel, "In Praise of the #error directive," Embedded Systems Programming, September 1999, p. 114.
          2) Jones, Nigel, " Efficient C Code for Eight-bit MCUs ," Embedded Systems Programming, November 1998, p. 66.


          [顯示打印版本]

          相關(guān)文章

          • No Relative Articles.

          相關(guān)評(píng)論   發(fā)表評(píng)論

          • leslie  [2005-04-08]

            挺考驗(yàn)基本知識(shí)的

          posted @ 2008-11-04 21:27 poower 閱讀(188) | 評(píng)論 (0)編輯 收藏
          #include "stdio.h"
          #include "conio.h"
          #include <dos.h>
          #include<graphics.h>
          /*****
          Key struct:
              position:x1,y1,x2,y2
              State:isdown
              white or black key:iswhite
              nearby key:lwbk,rwbk
          *******/

          typedef struct _Key{
              int x1;
              int y1;
              int x2;
              int y2;
              int isdown;
              int iswhite;
              int lwbk;
              int rwbk;
          } Key;

          /*****
          static grobal Variables statement:
              7 white keys:wk[7]
              5 black keys:bk[5]
              width,height:kw,kh
              frequant:frequ[8]
              pcfrequant:pcfre
              keynum
              count
          *******/
          static wknum=14;
          static Key wk[14];
          static bknum=10;
          static Key bk[10];
          static int kw=32,kh=160;
          static int leftwidth=2*32;
          int frequ[8]={262, 294, 330, 349, 392, 440, 494, 524};
          static long int pcfre=1190000;
          static int keyindex;
          static int count;

          /*****
          function statement:
              makesound():
              initkey();
              change key state:setup(),setdown()
              initdrawkey();
          *******/


          void makesound();
          Key set(int x1,int w,int h);
          void setup(Key *k);
          void setdown(Key *k);
          void keyinit();
          void initdrawkey();

          /*initkey*/
          Key initset(int x1,int w,int h,int isw,int lwbk,int rwbk){
              Key k;
              k.x1=x1;
              k.y1=0;
              k.x2=x1+w;
              k.y2=h;
              k.isdown=0;
              k.iswhite=isw;
              k.lwbk=lwbk;
              k.rwbk=rwbk;

              return k;
          }
          /*keyinit()*/
          void keyinit(){

              wk[0]=initset(leftwidth+0*kw,kw,kh,1,-1,0);
              wk[1]=initset(leftwidth+1*kw,kw,kh,1,0,1);
              wk[2]=initset(leftwidth+2*kw,kw,kh,1,1,-1);
              wk[3]=initset(leftwidth+3*kw,kw,kh,1,-1,2);
              wk[4]=initset(leftwidth+4*kw,kw,kh,1,2,3);
              wk[5]=initset(leftwidth+5*kw,kw,kh,1,3,4);
              wk[6]=initset(leftwidth+6*kw,kw,kh,1,4,-1);
              wk[7]=initset(leftwidth+7*kw,kw,kh,1,-1,6);
              wk[8]=initset(leftwidth+8*kw,kw,kh,1,6,7);
              wk[9]=initset(leftwidth+9*kw,kw,kh,1,7,-1);
              wk[10]=initset(leftwidth+10*kw,kw,kh,1,-1,8);
              wk[11]=initset(leftwidth+11*kw,kw,kh,1,8,9);
              wk[12]=initset(leftwidth+12*kw,kw,kh,1,9,10);
              wk[13]=initset(leftwidth+13*kw,kw,kh,1,10,-1);


              bk[0]= initset(leftwidth+kw-kw/4,kw/2,kh/2,0,0,1);
              bk[1]= initset(leftwidth+kw*2-kw/4,kw/2,kh/2,0,1,2);
              bk[2]= initset(leftwidth+kw*4-kw/4,kw/2,kh/2,0,3,4);
              bk[3]= initset(leftwidth+kw*5-kw/4,kw/2,kh/2,0,4,5);
              bk[4]= initset(leftwidth+kw*6-kw/4,kw/2,kh/2,0,5,6);

              bk[5]= initset(leftwidth+kw*8-kw/4,kw/2,kh/2,0,7,8);
              bk[6]= initset(leftwidth+kw*9-kw/4,kw/2,kh/2,0,8,9);
              bk[7]= initset(leftwidth+kw*11-kw/4,kw/2,kh/2,0,10,11);
              bk[8]= initset(leftwidth+kw*12-kw/4,kw/2,kh/2,0,11,12);
              bk[9]= initset(leftwidth+kw*13-kw/4,kw/2,kh/2,0,12,13);
          }

          /*draw black key*/
          void drawblackkey(Key *k){
               if(!(*k).isdown){
                  setfillstyle(SOLID_FILL,DARKGRAY);
                  bar((*k).x1,(*k).y1,(*k).x2,(*k).y2);

              }
              else{
                  setfillstyle(SOLID_FILL,LIGHTBLUE);
                  bar((*k).x1,(*k).y1,(*k).x2,(*k).y2);

              }
             
          }
          /*draw white key*/
          void drawwhitekey(Key *k){
              if(!(*k).isdown){
                  setfillstyle(SOLID_FILL,WHITE);
                  bar((*k).x1,(*k).y1,(*k).x2,(*k).y2);
                  setcolor(DARKGRAY);
                  rectangle((*k).x1,(*k).y1,(*k).x2,(*k).y2);
                  /*draw nearby key*/
                  if(!(*k).lwbk>-1){
                     drawblackkey(&bk[(*k).lwbk]);
                  }
                  if(!(*k).rwbk>-1){
                     drawblackkey(&bk[(*k).rwbk]);
                  }
              }
              else{
                  setfillstyle(SOLID_FILL,LIGHTBLUE);
                  bar((*k).x1,(*k).y1,(*k).x2,(*k).y2);
                  setcolor(DARKGRAY);
                  rectangle((*k).x1,(*k).y1,(*k).x2,(*k).y2);
                  /*draw nearby key*/
                  if(!(*k).lwbk>-1){
                     drawblackkey(&bk[(*k).lwbk]);
                  }
                  if(!(*k).rwbk>-1){
                     drawblackkey(&bk[(*k).rwbk]);
                  }
              }
          }
          /*setdown() and setup()*/
          void setdown(Key *k){
              (*k).isdown=1;
              if((*k).iswhite)
                  drawwhitekey(k);
              else
                  drawblackkey(k);
          }
          void setup(Key *k){
             (*k).isdown=0;
             if((*k).iswhite)
                  drawwhitekey(k);
              else
                  drawblackkey(k);
          }

           /*initdrawkey()*/
          void initdrawkey(){
              int gdriver,gmode,i;

              gdriver=DETECT;
              initgraph(&gdriver,&gmode,"c:\\tc");
              setbkcolor(YELLOW);
              cleardevice();

              for(i=0;i<wknum;i++){
                  setfillstyle(SOLID_FILL,WHITE);
                  bar(wk[i].x1,wk[i].y1,wk[i].x2,wk[i].y2);
                  setcolor(DARKGRAY);
                  rectangle(wk[i].x1,wk[i].y1,wk[i].x2,wk[i].y2);

              }
              for(i=0;i<bknum;i++){
                  setfillstyle(SOLID_FILL,DARKGRAY);
                  bar(bk[i].x1,bk[i].y1,bk[i].x2,bk[i].y2);
              }
          }
           /*makesound()*/
          void makesound(){
              count=(int)(pcfre/frequ[keyindex]);
              asm mov al, 10110110b
              asm out 43h, al

              asm mov ax,count

              asm out 42h, al
              asm mov al, ah
              asm out 42h, al

              asm in  al, 61h
              asm or  al, 03h
              asm out 61h, al

              delay(0xfffff000);
             
              asm in  al, 61h
              asm and al, 11111100b
              asm out 61h, al
          }


          void main(){
              keyinit();
              initdrawkey();

              settextstyle(4, 0, 10);
              outtextxy(200, 230, "Interface Principle Course Design");
              outtextxy(200, 250, "------------Piano----------------");
              outtextxy(200, 270, "-------Input 1...7 Play----------");
              outtextxy(200, 290, "-------Input CTRL+C Exit---------");
              outtextxy(200, 310, "-------Auther:Ying Wenjie--------");
              outtextxy(200, 340, "---------Date:2008-7-3-----------");
              while(1){
                  keyindex=getch();
                  if(keyindex==3)
                      break;

                  keyindex=keyindex-0x30;
                  if(keyindex<1||keyindex>8)
                      continue;
                  keyindex--;
                  setdown(&wk[keyindex]);

                  makesound();
                  setup(&wk[keyindex]);
              }
          }
          posted @ 2008-07-02 16:35 poower 閱讀(221) | 評(píng)論 (0)編輯 收藏

          author: scruffybear

          release time: 28/10/2006

          company: Watchdata

          如有轉(zhuǎn)載,請(qǐng)注明出處,并保持文章的完整性,謝謝!

              做java卡開發(fā)需要用到JNI,也就是本地化接口,說白了java程序要用到其它語言代碼,這樣就可以使用JNI來進(jìn)行達(dá)到調(diào)用的目的,暫時(shí)理解到這里,還沒有時(shí)間細(xì)究。網(wǎng)上看到了一篇很好的介紹JNI的文章《JNI入門介紹上》、《JNI入門介紹下》,只研究了前一篇,進(jìn)行了實(shí)踐,后一篇實(shí)踐覺得寫得不好,沒有花時(shí)間進(jìn)行實(shí)踐。

          1.簡(jiǎn)介
            
            JNI是Java Native Interface的縮寫,它的設(shè)計(jì)目的是:
            
            The standard Java class library may not support the platform-dependent features needed by your application.
            
            You may already have a library or application written in another programming language and you wish to make it accessible to Java applications.
            
            You may want to implement a small portion of time-critical code in a lower-level programming language, such as assembly, and then have your Java application call these functions
            
          2.JNI的書寫步驟
            
            編寫帶有native聲明的方法的java類
            
            使用javac命令編譯所編寫的java類
            
            使用javah -jni java類名生成擴(kuò)展名為h的頭文件
            
            使用C/C++實(shí)現(xiàn)本地方法
            
            將C/C++編寫的文件生成動(dòng)態(tài)連接庫(kù)
            
            ok
            
          1) 編寫java程序:
            
            這里以HelloWorld為例。
            
            代碼1:
            
            class HelloWorld {
            public native void displayHelloWorld();
            
            static {
            System.loadLibrary("hello");
            }
            
            public static void main(String[] args) {
            new HelloWorld().displayHelloWorld();
            }
            }
            
              聲明native方法:如果你想將一個(gè)方法做為一個(gè)本地方法的話,那么你就必須聲明改方法為native的,并且不能實(shí)現(xiàn)。其中方法的參數(shù)和返回值在后面講述。
            
            Load動(dòng)態(tài)庫(kù):System.loadLibrary("hello");加載動(dòng)態(tài)庫(kù)(我們可以這樣理解:我們的方法displayHelloWorld()沒有實(shí)現(xiàn),但是我們?cè)谙旅婢椭苯邮褂昧耍员仨氃谑褂弥皩?duì)它進(jìn)行初始化)這里一般是以static塊進(jìn)行加載的。同時(shí)需要注意的是System.loadLibrary();的參數(shù)“hello”是動(dòng)態(tài)庫(kù)的名字。
            
            main()方法
            
            2) 編譯沒有什么好說的了
            
            javac HelloWorld.java

              這里是運(yùn)行不了的,因?yàn)檫@時(shí)候目錄下面沒有hello.dll文件供調(diào)用,如果輸入java HelloWorld會(huì)出現(xiàn)以下錯(cuò)誤:
             C:\Documents and Settings\huilin.xiong\桌面>java HelloWorld
             Exception in thread "main" java.lang.UnsatisfiedLinkError: no hello in java.library.path
                  at java.lang.ClassLoader.loadLibrary(Unknown Source)
                  at java.lang.Runtime.loadLibrary0(Unknown Source)
                  at java.lang.System.loadLibrary(Unknown Source)
                  at HelloWorld.<clinit>(HelloWorld.java:5)

              下面就用c語言生成hello.dll文件供java語言來調(diào)用。如下:
            
          3) 生成擴(kuò)展名為h的頭文件
            
            javah -jni HelloWorld

              在這里自動(dòng)生成文件名為HelloWorld.h的頭文件。
            
            頭文件的內(nèi)容:
            /* DO NOT EDIT THIS FILE - it is machine generated */
            #include
            /* Header for class HelloWorld */
            
            #ifndef _Included_HelloWorld
            #define _Included_HelloWorld
            #ifdef __cplusplu*
            **tern "C" {
            #endif
            /*
            * Class:   HelloWorld
            * Method:  displayHelloWorld
            * Signature: ()V
            */
            JNIEXPORT void JNICALL Java_HelloWorld_displayHelloWorld
            (JNIEnv *, jobject);
            
            #ifdef __cplusplus
            }
            #endif
            #endif
            
            (這里我們可以這樣理解:這個(gè)h文件相當(dāng)于我們?cè)趈ava里面的接口,這里聲明了一個(gè)Java_HelloWorld_displayHelloWorld (JNIEnv *, jobject);方法,然后在我們的本地方法里面實(shí)現(xiàn)這個(gè)方法,也就是說我們?cè)诰帉慍/C++程序的時(shí)候所使用的方法名必須和這里的一致)。
            
          4) 編寫本地方法
            
            實(shí)現(xiàn)和由javah命令生成的頭文件里面聲明的方法名相同的方法。
            
            代碼2:
            
            #include <jni.h>
            #include "HelloWorld.h"
            #include <stdio.h>
            JNIEXPORT void JNICALL Java_HelloWorld_displayHelloWorld(JNIEnv *env,jobject obj)
            {
            printf("Hello world!\n");
            return;
            }
            
            注意代碼2中的第1行,需要將jni.h(該文件可以在%JAVA_HOME%/include文件夾下面找到)文件引入,因?yàn)樵诔绦蛑械腏NIEnv、jobject等類型都是在該頭文件中定義的;另外在第2行需要將HelloWorld.h頭文件引入(我是這么理解的:相當(dāng)于我們?cè)诰帉慾ava程序的時(shí)候,實(shí)現(xiàn)一個(gè)接口的話需要聲明才可以,這里就是將HelloWorld.h頭文件里面聲明的方法加以實(shí)現(xiàn)。當(dāng)然不一定是這樣)。然后保存為HelloWorldImpl.c就ok了。
            
            5) 生成動(dòng)態(tài)庫(kù)
            
            這里以在Windows中為例,需要生成dll文件。在保存HelloWorldImpl.c文件夾下面,使用VC的編譯器cl成。
            
            cl -I%java_home%\include -I%java_home%\include\win32 -LD HelloWorldImp.c -Fehello.dll
            
            注意:生成的dll文件名在選項(xiàng)-Fe后面配置,這里是hello,因?yàn)樵贖elloWorld.java文件中我們loadLibary的時(shí)候使用的名字是hello。當(dāng)然這里修改之后那里也需要修改。另外需要將-I%java_home%\include -I%java_home%\include\win32參數(shù)加上,因?yàn)樵诘谒牟嚼锩婢帉懕镜胤椒ǖ臅r(shí)候引入了jni.h文件。
              
              這里在實(shí)際的操作中找不到頭文件<stdio.h>,找不出原因,檢查了我的環(huán)境變量設(shè)置也沒有錯(cuò),沒辦法,只有從目錄D:\Software\Microsoft Visual Studio .NET\Vc7\include目錄下拷貝過來,另外又找不到stdarg.h,一并拷貝過來。頭文件都找不到后,又出現(xiàn)了找不到好幾個(gè)LIB文件,分別為libcmt.lib,oldnames.lib,kernel32.lib,檢查環(huán)境變量也沒錯(cuò),沒辦法,只能從D:\Software\Microsoft Visual Studio.NET\Vc7\lib拷貝過來。最后在目錄下生成了這樣幾個(gè)文件:HelloWorldImpl.obj,hello.dll,hello.exp,hello.lib,當(dāng)然,只有hello.dll是有用的,它是被HelloWorld.class所調(diào)用。
            
            6) 運(yùn)行程序
            
            java HelloWorld,輸出了碩大的“Hello world!”。:-)

          /************************************************************************
          轉(zhuǎn)至:http://blog.csdn.net/scruffybear/archive/2007/12/01/1910418.aspx

          posted @ 2008-06-30 10:00 poower 閱讀(631) | 評(píng)論 (0)編輯 收藏

          /*sound.h*/
          /*http://blog.csdn.net/scs2000/archive/2006/09/14/1221079.aspx*/
          #include <stdio.h>
          #include <conio.h>
          #define NOO 1450
          int music1[8][6]={
              {262,262,294,262,349},
              {330,262,262,294,262},
              {392,349,262,262,523},
              {440,349,262,262,466},
              {466,440,262,392,349}
          };
          int time1[8][6]={
              {100,100,200,200,200},
              {200,200,100,100,200},
              {200,200,200,200,200},
              {200,200,200,200,200},
              {100,200,200,200,200}
          };
          int music2[3][10]={
              {330,392,330,294,330,392,330,294,330,330},
              {330,392,330,294,262,294,330,392,294,294},
              {262,262,220,196,196,220,262,294,332,262}
          };
          int time2[3][11]={
              {200,200,200,100,100,200,100,100,200,200},
              {200,200,100,100,200,200,100,100,200,200},
              {200,100,100,200,100,100,200,100,100,400}
          };
          int music3[4][11]={
              {441,393,330,393,131,441,393,441,441,1450,1450},
              {330,393,441,393,330,262,882,393,330,294,294},
              {294,330,393,393,441,330,294,262,262,1450,1450},
              {393,330,294,262,882,262,786,786,786,1450,1450}
          };
          int time3[4][11]={
              {200,100,200,200,200,100,100,200,200,0,0},
              {200,100,100,200,200,100,100,100,100,200,200},
              {200,100,200,100,100,200,200,200,200,0,0},
              {200,100,100,100,100,100,200,200,200,0,0}
          };
          const char * process_file[]={
                             " ",
                             "┌───┬┬┐┌┬┐┌┬┐┌┬┐┌┬┐┌┬┐┌┬┐┌┬┬───┐",
                             "│     ├接┤├口┤├技┤├術(shù)┤├課┤├程┤├設(shè)┤├計(jì)┤     │",
                             "├───┴┴┘└┴┘└┴┘└┴┘└┴┘└┴┘└┴┘└┴┴───┤",
                             "│                     《音樂發(fā)生器》                       │",
                             "├──────────────────────────────┤",
                             "│                                                           │",
                             "├──────────────────────────────┤",
                             "│                                                           │",
                             "│                   A.播放第一首音樂                       │",
                             "│                   B.播放第二首音樂                       │",
                             "│                   C.播放第三首音樂                       │",
                             "│                   Q.退出該程序                           │",
                             "│                                                           │",
                             "├──────────────────────────────┤",
                             "│   制作:王康                                             │",
                             "│   日期:年月日                                    │",
                             "│                                                            │",
                             "└──────────────────────────────┘"};
          const char * end_file[]={
                             " ",
                             "┌─────┐   ┌─┐┌─┐     ┌─┐┌─┐   ┌─────┐",
                             "│★★★★★├☆☆┤個(gè)││人├☆☆☆┤簡(jiǎn)││介├☆☆┤★★★★★│",
                             "├─────┘   └─┘└─┘☆└─┘└─┘   └─────┤",
                             "├───────────────☆───────────────┤",
                             "│姓名:王康                                                   │",
                             "├───────────────────────────────┤",
                             "│性別:男                                                     │",
                             "├───────────────────────────────┤",
                             "│班級(jí):                                                        │",
                             "├───────────────────────────────┤",
                             "│電話:--XXXXXXXX                                          │",
                             "├───────────────────────────────┤",
                             "│QQ號(hào):                                                │",
                             "├───────────────────────────────┤",
                             "│郵箱:wkjs@163.com                                            │",
                             "├───────────────────────────────┤",   
                             "│                        謝謝您的使用                        │",
                             "└───────────────────────────────┘"};
          void light(int a)
          {
              asm MOV DX,283H
              asm MOV AL,80H
              asm OUT DX,AL
              asm MOV DX,280H
              asm MOV AL,0H;
              asm OUT DX,AL
              switch(a)
              {
              case 262:
              case 131:
                  asm MOV AL,01H
                  asm OUT DX,AL
                  break;
              case 294:
                  asm MOV AL,03H
                  asm OUT DX,AL
                  break;
              case 330:
                  asm MOV AL,07H
                  asm OUT DX,AL
                  break;
              case 350:
                  asm MOV AL,0FH
                  asm OUT DX,AL
                  break;
              case 393:
              case 786:
                  asm MOV AL,1FH
                  asm OUT DX,AL
                  break;
              case 441:
              case 882:
                  asm MOV AL,3FH
                  asm OUT DX,AL
                  break;
              case 495:
                  asm MOV AL,7FH
                  asm OUT DX,AL
                  break;
              };
          }
          void sound_A(int a,int b)
          {              
                  int i=0;
                  asm MOV DI,a    /*選擇號(hào)計(jì)數(shù)器,先寫低字節(jié),后寫高字節(jié),選擇工作方式,二進(jìn)制*/
                  asm MOV AL,10110110B
                  asm MOV DX,12H
                  asm MOV AX,34DEH
                  asm DIV DI
                  asm OUT 42H,AL /*先送低字節(jié)到號(hào)計(jì)數(shù)器*/
                  asm MOV AL,AH   /*取高字節(jié)送AL*/
                  asm OUT 42H,AL /*后送高字節(jié)到號(hào)計(jì)數(shù)器*/
                  asm IN AL,61H   /*讀入的PB口原輸出值*/
                  asm MOV AH,AL  
                  asm OR AL,3     /*8255的PB0口PB1口輸出有效*/
                  asm OUT 61H,AL
                  /*調(diào)用燈亮函數(shù)*/
                  light(a);
                  /*時(shí)間延遲*/
                  for(i=0;i<b;i++)
                  {
                      delay(2000);
                  }
                  /*關(guān)閉揚(yáng)聲器*/
                  asm MOV AL,AH
                  asm OUT 61H,AL
          }
          void sound(char a)
          {
              int i,j;
              if(a=='a')
              {
                  for(i=0;i<5;i++)
                  {
                      for(j=0;j<5;j++)
                      {
                          sound_A(music1[i][j],time1[i][j]);
                      }
                  }
              }
              else if(a=='b')
              {
                  for(i=0;i<3;i++)
                  {
                      for(j=0;j<11;j++)
                      {
                          sound_A(music2[i][j],time2[i][j]);
                      }
                  }
              }
              else if(a=='c')
              {
                  for(i=0;i<4;i++)
                  {
                      for(j=0;j<11;j++)
                      {
                          sound_A(music3[i][j],time3[i][j]);
                      }
                  }
              }
              else
              {
                  printf("\t對(duì)不起,沒有該音樂!\n");
              }
          }
          void face()
          {
              int i;
              system("cls");
              for(i=0;i<19;i++)
              {
                  printf("\t%s\n",process_file[i]);
                  delay(20000);
              }
              printf("\t請(qǐng)輸入您的指令:");
          }
          void endface()
          {
              int i;
              system("cls");
              for(i=0;i<19;i++)
              {
                  printf("\t%s\n",end_file[i]);
                  delay(20000);
              }
              printf("\t");
          }
          void operate()
          {
              char a;
              face();
              while(1)
              {
                  a=getche();
                  switch(a)
                  {
                  case 'a':
                  case 'A':
                      sound('a');
                      printf("\n\t音樂播放結(jié)束,謝謝你的收聽,點(diǎn)任意鍵繼續(xù)!");
                      getch();
                      face();
                      break;
                  case 'b':
                  case 'B':
                      sound('b');
                      printf("\n\t音樂播放結(jié)束,謝謝你的收聽,點(diǎn)任意鍵繼續(xù)!");
                      getch();
                      face();
                      break;
                  case 'c':
                  case 'C':
                      sound('c');
                      printf("\n\t音樂播放結(jié)束,謝謝你的收聽,點(diǎn)任意鍵繼續(xù)!");
                      getch();
                      face();
                      break;
                  case 'q':
                  case 'Q':
                      endface();
                      exit(1);
                      break;
                  default:
                      printf("\t您的輸入有誤,請(qǐng)核實(shí),謝謝!");
                      getch();
                      face();
                      break;
                  }
              }
          }
           /*sound.c*/

          void main()
          {
              operate();
          }

          posted @ 2008-06-30 09:58 poower 閱讀(671) | 評(píng)論 (0)編輯 收藏

          public class bigadd {

              /**
               * @param args
               */
              //***********************兩個(gè)相等數(shù)相加**********************************88
              public static String add(String s){
                  char c[]=s.toCharArray();
                  for(int i=0;i<c.length/2;i++){
                      char t=c[i];
                      c[i]=c[c.length-1-i];
                      c[c.length-1-i]=t;
                  }
                  int r[]=new int[c.length+1];
                  int carry=0;
                  for(int i=0;i<c.length;i++){
                      int t=Integer.parseInt(c[i]+"")+Integer.parseInt(c[i]+"")+carry;
                      carry=t/10;
                      r[i]=t%10;
                  }
                  r[c.length]=carry;
                  String sr;
                  if(r[c.length]==0)
                      sr="";
                  else
                      sr="1";
                  for(int j=r.length-2;j>=0;j--){
                      sr+=r[j];
                  }
                  return sr;
              }
              //*******************************兩個(gè)不同數(shù)相加*****************************************
              public static String adddif(String s1,String s2){
                  char c1[] ;
                  char c2[] ;
                  if (s1.length() >= s2.length()) {
                      c1 = s1.toCharArray();
                      c2 = s2.toCharArray();
                  }
                  else{
                      c2 = s1.toCharArray();
                      c1 = s2.toCharArray();
                  }
                  for(int i=0;i<c1.length/2;i++){
                      char t=c1[i];
                      c1[i]=c1[c1.length-1-i];
                      c1[c1.length-1-i]=t;
                  }
                  for(int i=0;i<c2.length/2;i++){
                      char t=c2[i];
                      c2[i]=c2[c2.length-1-i];
                      c2[c2.length-1-i]=t;
                  }
                 
                  int r[]=new int[c1.length+1];
                  int carry=0;
                  for(int i=0;i<c2.length;i++){
                      int t=Integer.parseInt(c1[i]+"")+Integer.parseInt(c2[i]+"")+carry;
                      carry=t/10;
                      r[i]=t%10;
                  }
                  for(int i=c2.length;i<c1.length;i++){
                      int t=Integer.parseInt(c1[i]+"")+carry;
                      carry=t/10;
                      r[i]=t%10;
                  }
                  r[c1.length]=carry;
                  String sr;
                  if(r[c1.length]==0)
                      sr="";
                  else
                      sr="1";
                  for(int j=r.length-2;j>=0;j--){
                      sr+=r[j];
                  }
                  return sr;
              }
              //*************************求2的N次冪*********************************8
              public static String pow(int n){
                  if(n==0)
                      return "1";
                  else if(n==1)
                      return "2";
                  else
                      return add(pow(n-1));       
              }
             
              public static String sumpow(int p1,int n,int q){
                  String sum="";
                  String pre=pow(p1);
                  for(int i=p1;i<=n;i=i+q){
                      sum=adddif(sum,pre);
                      for(int j=1;j<=2;j++)               
                          pre=add(pre);
                  }
                  return sum;
              }
              //************************************相減***********************************
              public static String minus(String s1,String s2){
                  char c1[] ;
                  char c2[] ;
                  if (s1.length() >= s2.length()) {
                      c1 = s1.toCharArray();
                      c2 = s2.toCharArray();
                  }
                  else{
                      c2 = s1.toCharArray();
                      c1 = s2.toCharArray();
                  }
                  for(int i=0;i<c1.length/2;i++){
                      char t=c1[i];
                      c1[i]=c1[c1.length-1-i];
                      c1[c1.length-1-i]=t;
                  }
                  for(int i=0;i<c2.length/2;i++){
                      char t=c2[i];
                      c2[i]=c2[c2.length-1-i];
                      c2[c2.length-1-i]=t;
                  }
                 
                  int r[]=new int[c1.length];
                  int carry=0;
                  for(int i=0;i<c2.length;i++){
                      int t=Integer.parseInt(c1[i]+"")-Integer.parseInt(c2[i]+"")-carry;
                      if(t<0){
                          r[i]=Integer.parseInt(c1[i]+"")-Integer.parseInt(c2[i]+"")+10-carry;
                          carry=1;
                      }
                      else{
                          r[i]=t;
                          carry=0;
                      }
                  }
                  for(int i=c2.length;i<c1.length;i++){
                      int t=Integer.parseInt(c1[i]+"")-carry;
                      if(t<0){
                          carry=1;
                          r[i]=9;
                      }
                      else{
                          r[i]=t;
                          carry=0;
                      }
                  }
                  String str;
                  if(r[c1.length-1]==0){
                      str="";
                  }
                  else{
                      str=""+r[c1.length-1];
                  }
                  for(int j=r.length-2;j>=0;j--){
                      str+=r[j];
                  }
                  return str;
                 
              }
              //**********************************減1****************************************
              public static String minus1(String s){
                  char c[]=s.toCharArray();
                  int i;
                  for(i=0;i<c.length/2;i++){
                      char t=c[i];
                      c[i]=c[c.length-1-i];
                      c[c.length-1-i]=t;
                  }
                  int t=0;
                  for(i=0;i<c.length;i++){
                      t=Integer.parseInt(c[i]+"");
                      if(t>0){
                          t=t-1;
                          break;
                      }           
                  }
                  c[i]=(t+"").charAt(0);
                  System.out.println(t+" "+i);
                  String str;
                  if(c[c.length-1]=='0')
                      str="";
                  else
                      str=c[c.length-1]+"";
                 
                  for(int j=c.length-2;j>=i;j--)
                      str=str+c[j];
                  for(int j=i-1;j>=0;j--)
                      str+=9;
                  return str;
              }
              //*************************************加1************************************
              public static String add1(String s){
                  char c[]=s.toCharArray();
                  int i;
                  for(i=0;i<c.length/2;i++){
                      char t=c[i];
                      c[i]=c[c.length-1-i];
                      c[c.length-1-i]=t;
                  }
                  int t=0;
                  for(i=0;i<c.length;i++){
                      t=Integer.parseInt(c[i]+"");
                      if(t<9){
                          t=t+1;
                          break;
                      }   
                  }
                  String str;
                  if(i==c.length)
                      str="1";
                  else{
                      c[i]=(t+"").charAt(0);
                      str="";
                  }
                  for(int j=c.length-1;j>=i;j--)
                      str=str+c[j];
                  for(int j=i-1;j>=0;j--)
                      str+=0;
                  return str;
              }
             
              public static void main(String[] args) {
                  // TODO 自動(dòng)生成方法存根
                  //System.out.println(pow(1000));
                  //System.out.println(pow(999));
                  //System.out.println(adddif(pow(999),pow(999)));
                  //System.out.println(adddif("19","999"));
                  System.out.println(sumpow((4-3),(1000-3),2));
                  //System.out.println(minus(pow(1000),pow(999)));
                  //System.out.println(add1(pow(1000)));
              }

          }


          posted @ 2008-06-13 13:36 poower 閱讀(441) | 評(píng)論 (0)編輯 收藏
          中學(xué)就學(xué)過排列,組合 ,比如 C5,2 = 10; C6,2 = 15
          如果用算法實(shí)現(xiàn)的話,難道也要先做一連串的乘法,然后再相除嗎? 比如: C5,2 = (5*4*3*2)/(3*2)

          如果數(shù)很大的話,又是乘又做除的,多牛的計(jì)算機(jī)才能搞定呢?

          先看看簡(jiǎn)單的:
          2個(gè)數(shù)選2個(gè),共有1種方法
          3個(gè)數(shù)選2個(gè),共有3種方法
          4個(gè)數(shù)選2個(gè),共有6種方法
          n個(gè)數(shù)選2個(gè),共有多少種方法?

          F(n,2) = F(n-1,2) + F(n-1,1) //這樣寫看的更清楚些.

          那么N個(gè)數(shù)選M出來,有多少種選擇呢?
          F(N,M) = F(N-1,M) + F(N-1,M-1)
          到此處,DP的遞歸解空間已經(jīng)出來了.

          F(N,M) = 1                                          M=0 or N=0 or N=M
          F(N,M) = N                                          M=1
          F(N,M) = F(N-1,M) + F(N-1,M-1)         M!=N 當(dāng)然N>M


          剩下的工作就是程序?qū)崿F(xiàn)了.但是還有個(gè)小問題,就是在DP迭代的過程中是否需要記憶.在這個(gè)算法當(dāng)然需要記憶.

          實(shí)現(xiàn)的過程中,可以做些小優(yōu)化,比如N=5 M=3 可以求C5,2的組合數(shù)就是要少遞歸幾次.

          #include "stdafx.h"
          #include <iostream>
          using namespace std;

          __int64 Aug[200][200] = {0};

          __int64 getComposite(int m,int n)
          {
              __int64 preResult0;
              __int64 preResult1;

              if (m==0 || n== 0 || m== 1 || m == n)
                  return 1;
              if (Aug[m][n] != 0)
                  return Aug[m][n];
              else
              {
                  preResult0    = getComposite(m-1,n);
                  Aug[m-1][n]   = preResult0;
                  preResult1    = getComposite(m-1,n-1);
                  Aug[m-1][n-1] = preResult1;
              }
              return preResult0 + preResult1;
          }
          int main()
          {
              int count;
              int m,n;
              int m0,n0;

              cin >> n >> m;
              m0 = m >= n ? m : n;
              n0 = m >= n ? n : m;
              n0 = m0 - n0 >= n0 ? n0 : m0-n0;
              cout << getComposite(m0,n0) << endl;

              return 0;
          }
          //*********************************************************************************
          注:其實(shí)我沒看明白......
          posted @ 2008-06-11 00:58 poower 閱讀(840) | 評(píng)論 (0)編輯 收藏
          僅列出標(biāo)題  下一頁(yè)
          主站蜘蛛池模板: 隆化县| 元朗区| 铜川市| 涡阳县| 贡觉县| 苏尼特右旗| 岐山县| 辽宁省| 綦江县| 三江| 沁水县| 柳河县| 宣化县| 广平县| 彩票| 乌拉特后旗| 青海省| 绥德县| 邓州市| 梁山县| 辛集市| 贵德县| 陆河县| 邹城市| 郸城县| 沛县| 特克斯县| 云梦县| 汽车| 德化县| 独山县| 扶余县| 新野县| 门源| 漳州市| 渭南市| 塔城市| 中西区| 顺平县| 城步| 乡宁县|