2008年9月30日 星期二

取得圓周率值

math library提供了許多常見的數學運算函式,其中也包括三角函數。然而對於圓周率(pi)值並沒有常數的定義,我們可以利用反三角函數來取得pi值:

圓周率 = 4 * atan(1)

在數學運算中,我們比較熟悉的是夾角的角度,而math library的三角函數回傳值皆以弧度(radian),所以我們可以自行定義一個常數來轉換。

#define RADIAN_TO_DEGREE (180 / (4 * atan(1)))

2008年9月29日 星期一

ldd

ldd可以用來顯示每個程式所使用到的shared library。ldd其實是一個shell script而不是執行檔。

在linux,我們可以將程式編譯成靜態連結或是動態連結,在這以hello.c來解釋。

#include 
int main(void) {
printf("Hello world!\n");
return 0;
}


用gcc編譯
# gcc hello.c -o hello
則會產生hello的執行檔,而其預設是使用動態連結的方式:

用file指令來檢視其屬性
# file hello
hello: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.8, not stripped

用ldd來檢視共用了哪些shared library
# ldd hello
linux-gate.so.1 => (0xb7f6a000)
libc.so.6 => /lib/i686/cmov/libc.so.6 (0xb7dfd000)
/lib/ld-linux.so.2 (0xb7f6b000)

此外,此檔案的大小為
# ls -l hello
-rwxr-xr-x 1 howard howard 6256 2008-09-30 00:00 hello

上述為程式使用動態連結,我們也可以將程式編譯成靜態連結:
# gcc -static hello.c -o hello

用file來檢視,可以看到顯示為靜態連結
# file hello
hello: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, for GNU/Linux 2.6.8, not stripped

用ldd來檢視,自然沒使用到任何shared library
# ldd hello
not a dynamic executable

再來檢視檔案的大小
# ls -l hello
-rwxr-xr-x 1 howard howard 564881 2008-09-30 00:07 hello

我們可以看到檔案大小為564881 Bytes,相對於之前用動態連結只用了6256 Bytes,足足大上快一百倍。可見使用動態連結能大大節省空間。

2008年9月28日 星期日

Linux Library

Program library指的就是包含已編譯好的程式碼和資料,可以拿來被其它程式來運作。可以依程式與library結合的時間將library分成三類:

  • static library:
這些library必須先和程式結合成為執行檔,才能執行。static library其實就是一堆object file集合在一起,以.a為副檔名。
  • shared library:
在程式啟始時,這些library才被載入。library和執行檔是分開的,以.so為副檔名。
  • dynamically loaded library:
可以在程式執行的任何時間內載入這些library,就像Windows下的DLL。

2008年9月27日 星期六

願者上鉤

姜太公釣魚,願者上鉤。

今天是第二次和朋友們一塊去釣蝦,但與其說我去釣蝦,不如說是陪釣員,因為我不吃蝦子,所以我甚至希望朋友們釣到可以把他們放生回去,不過看來遊說是失敗的。
自從有了上次很悲慘的經驗,就是兩支釣竿共三小時竟然只釣到了三隻蝦子,就覺得釣蝦還真是需要一些技術阿,蝦子們看起來是會上鉤,但吃到了餌就跑了。

由於我在釣蝦場無所事事,只好來幫他們記錄第一隻釣到的蝦子。




不過,今天在釣蝦場遇到了一個阿伯,他非常的熱心的傳授他的釣蝦經驗給阿佑。結果阿,這次釣的量大約就十五、六隻左右,遠大於上次的三隻。


果然姜太公的釣法在現實生活是行不通的

2008年9月25日 星期四

三聚氰胺

毒奶粉事件愈演愈烈,主要的原兇就是三聚氰胺。那就來對三聚氰胺做個簡介:
摘錄自衛生署網站

三聚氰胺(Melamine):
它是一種白色化工原料,無味、略溶於水,可溶於酒精、甲醇,常用於製告美耐皿餐具、建材、塗料,具毒性,不可添加於食品。

對人體的危害:
經腸胃吸收後,可能於腎臟中結合沈積,形成腎結石,嚴重者會造成腎臟功能受損;這種現象較易發生在腎臟尚未發育完全的嬰幼兒。

不肖廠商為什麼要在奶粉中添加三聚氰胺?
奶粉主要以蛋白質含量高低為品級分類,為通過奶粉中蛋白質含量檢測,不肖廠商才加入三聚氰胺。

macro與inline差異

C99標準新增了inline function的定義,標準說:「Making a function an inline function suggests that calls to the function be as fast as possible.」其中由suggest一詞就可以知道實際的運作要看compiler如何實作,也許真的會讓function的呼叫變快,也可能什麼事都沒發生。

而macro與inline的差異:

  • macro是由preprocessor處理,由inline則是compiler來負責
  • macro對於檢查傳入參數的型別,而inline則會檢查型別

假設定義平方的巨集如下:
#define SQUARE(x) x * x
若執行
SQUARE(3+2);
則答案並不會預期印出25,而是11,因為macro只是當純的文字替換,所以式子將會變成:
3 + 2 * 3 + 2

因此,正確安全的寫法如下:
#define SQUARE(x) ((x) * (x))
而inline的寫法就和一般的function寫法一樣:
inline int square(int x) {
return x * x;
}

取得Macro的參數字串

除了一般function的寫法外,function也可以用macro來定義,例如定義一個可以印出某數的平方值:

#define SQUARE(x) printf("The square of x is %d\n", ((x)*(x)))
當程式碼始用
SQUARE(5);
則會輸出
The square of x is 25

我們可以利用#來取得macro參數的名字
#define SQUARE(x) printf("The square of " #x " is %d\n", ((x)*(x)))
輸出結果則會變成
The square of 5 is 25

2008年9月23日 星期二

就是愛計較 (Java版)

記得在幾個月前,曾經也動手要寫一個記帳的程式,來記錄每一天的開銷。但寫了一小部份後,開始對於該如何存放資料感到煩惱,感覺用一般的檔案讀寫,不是很符合程式的需求,因為隨時都可能須要對過去的資料做查詢、刪除及一些處理,用資料庫系統來管理會比較適合。但說到資料庫,若要求每個使用者都自己先建好一個可用的資料庫又不太可能,所以這個程式就開始停擺沒寫了。

前些日子,看到昔日的強者同學剛好也寫了一個記帳程式,發現他是用一種嵌入式的資料庫SQLite,也就是可以和所開發的程式包在一起,程式啟動時同時也啟動資料庫,感覺蠻適合用來開發程式的。但由於SQLite是用C寫的,所以便開始想找找看有沒有用Java寫的嵌入式資料庫系統,很幸運的被我找到了,原來在Java 6本身就已經包含一個名為Java DB(Apache Derby)的資料庫系統,所以就開始著手找一些相關的文件,學學如何使用Java DB。

既然資料庫的問題解決了,所以便打算重新繼續開發記帳程式,在寫程式之前,有先參考了這位強者同學寫的記帳軟體,因為我使用者介面的設計能力真的很差,所以介面就有點模仿他的,但功能還是沒有他寫的完整就是了,大家可以到下面網址使用他的軟體。

豬頭記帳


接下來就來簡介一下自己寫的程式,當然是不能和強者同學寫的相提並論,我只是單純練習用的。

程式下載區

程式外觀主要有四個分頁

  • 新增記錄 - 可用來新增每一筆的收入與支出,類別的部分可以自行修改,下面會列出最近十筆的輸入資料。

  • 資料統計 - 列出本日、本月、本年以及全部的收入支出總額,另外以圓餅圖來顯示所有支出中,各類別所佔的比例。


  • 檢視/刪除 - 可以用來查詢任何一天的記錄,並刪除該筆記錄。



  • 類別設定 - 可以修改、新增、刪除類別與子類別項目,若修改或刪除的類別或子類別包含已存在的記錄,則該筆記錄的類別或子類別項目會變成不分類。




第一次寫程式用到資料庫系統,雖然研究所時修過資料庫系統,但真的都忘的差不多了。害我趕緊把書給挖了出來,但由於我把系統寫的很單純,所以也沒有用到什麼複雜的查詢。資料庫系統真是一門很深的學問,我還要再多學學才行。

在寫這一個程式時,漸漸發覺當程式功能愈多的時候,還是多人一起開發會比較輕鬆吧,雖說這個程式沒有很大,但因為很多東西都第一次碰,所以寫到最後,開始有點討厭程式。其實本來預期的功能應該不只這些,只是有點累了,就先寫到這樣吧!

2008年9月22日 星期一

記得這裡的愛最多

為了去辦役期抵免的證明,今天又重新踏進永春高中的校園。在一路往永春高中的路途上,漸漸喚醒我快遺忘的記憶,公車路線依舊不變,但卻已經隔了五年之久。299號公車坐到最後一站就到了。對於高中時候的我,這公車可是我天天的夢魘。由於我家下一站就是台北車站,所以每次公車到了我家這一站的時候,乘客可以說是滿滿滿,每個人都要各憑本事才能擠上299。因此為了避免遲到,每天都六點就起床了,六點二十分就去等公車,但因為我沒有搶公車的本領,所以常常還是會錯過好多班才搭上公車,有一次最扯的就是竟然遲到了。
高中生活除了等公車這個不好的印象外,另一個比較有印象的就是永春的校歌『記得這裡的愛最多』。到現在我還是會唱喔,這可是我從小到大唯一記得的一首校歌,常常閒來沒事也會來啍個幾句。詞曲是小蟲所創作的,大家若有興趣的話,可以按下面的連結聽聽看。

這裡的愛最多


到了永春高中,就先到教務處先申請成績單,然後就到旁邊的教官室蓋個章就完成,過程蠻快的。不過,走在永春校園,我發現一切都好陌生喔,怎麼會這樣呢?懷疑我真的在這讀了三年嗎?
今天要特別感謝大山貓陪我一起到永春去,不然一個人去有種近鄉情怯的感覺。拿到證明後,本來想要順便在校園逛逛的,但天公真的是不作美,只好作罷。拿起手機隨手拍了幾張照片記念一下,因為不知下次何時才會再回來了。

操場


永春高中其實有很多階梯,這只是冰山一角


永春高中就位於象山上


將照片放到電腦上才發現原來階梯上排了YC二字,就是永春啦

2008年9月21日 星期日

倦怠期

沒想到寫部落格也會有倦怠期...

記得以前閒來無事,可能一天就發個一兩篇的心情文;一出去玩,回家就找個一兩張照片寫個遊記;學會新的事物,馬上就寫個教學文來幫助自己記憶。

但最近這些文章愈來愈少了,感覺少了一點動力。最近新學會了許多關於程式方面的用法、前天晚上烤肉從半夜烤到天亮,還有剛和一群朋友看完海角七號回來。以前的我,早寫了好幾篇文章了,只是到現在一篇都沒有。好在現在正在打這一篇。

會感到這麼沒動力,我想可能是因為最近在寫一個記帳程式,從開始寫到現在,無時無刻都在想該怎麼寫比較好,這樣寫會有什麼問題,搞到自己都開始有點討厭寫程式了。朋友都說當兵前還寫什麼程式,應該讓自己放鬆才是。其實這麼說好像也有點道理,而且自己也沒多會寫程式,與其說寫給別人用,不如說是寫給自己用,想了太多自己不會遇到的問題。總覺得自己太急了,想要很快的寫好每一個功能,犯了欲速則不達的大忌。

以前開始寫部落格的原因,最主要的就是想記錄生活的點點滴滴和一些自己的學習歷程。看來不能再偷懶了,改天趕緊補上幾篇自己學會的新事物。

2008年9月14日 星期日

防禦SQL Injection

SQL Injection一般指使用者藉由輸入的資料內嵌的SQL指令來攻擊系統。

例:一個登入系統要求使用者輸入帳號密碼

若程式碼為下:
String sql = "select * from user where username='" + username +"' and password='" + password + "'";
stmt = conn.createStatement();
rs = stmt.executeQuery(sql);


若使用者已知某帳號如admin,可輸入admin'--。或是用未知的使用者登入,可輸入'or 1=1--,密碼欄位亂填,則SQL語法將變成:

select * from user where username='admin'-- and password='xxxx'
select * from user where username=''or 1=1-- and password=' '

即可成功登入系統,--為註解。

Java程式語言可以用Prepared Statements來解決,也就是預先參數化你想要的SQL語法。

例:
String sql = "select * from user where userId = ? ";
PreparedStatement preparedStmt = con.prepareStatement(sql);
preparedStmt.setString(1, userId);
ResultSet rs = prepStmt.executeQuery();

如此便不用擔心userId變數包含SQL語法了。

2008年9月13日 星期六

Key

資料庫的Key簡介

  • super key:屬性的集合可以用來唯一辨識資料表中的每一筆紀綠
  • candidate key:最小的super key都稱為candidate key
  • primary key:資料庫設計者選擇其中一個candidate key來辨識每一筆資料
  • foreign key:資料表的某些屬性剛好對應到其它資料表的primary key,稱為foreign key

2008年9月8日 星期一

樂透機(Java版)

最近怎麼開始都在寫簡單的程式了呢?主要是因為恰巧有這個需求,所以就順手來寫了一個。像若是單純只寫文字介面的話,只要短短幾行就寫好了。不過,我想或許其它人也有這個需求,所以就把它寫成視窗程式,有興趣的可以下載使用看看。

程式下載區 (若不能執行表示你的系統未安裝JRE 6)

IE好像下載時會將以.zip儲存,若要正確執行,請將附檔名改成.jar。


例:希望從1到1000中,隨機產生5組號碼,且這5組號碼可以重複。

執行畫面如下:




所以,功能很單純。就是使用者可以自己設定一個範圍,並選擇想要產生幾組數字,按下好運氣,結果會產生在下面。像大樂透的玩法是1到49任選六個號碼,所以就可以在程式中輸到1和49,選擇6組數字,千萬別勾選可重複號碼喔!

p.s. 要是真的那麼好中就好了,所以千萬別這樣就簽下去了,除非你是抱著做公益的心態去簽^__^

2008年9月7日 星期日

蝴蝶效應

記得當時在看求婚大作戰的時候,小書書有推薦我看一部電影「蝴蝶效應」,一樣是透過照片而回到過去,但可惜的就是目前還沒機會看到這部。不過今天晚上cinemax要播出蝴蝶效應二,所以我當然就守在電視機前,沒看過一,不能再錯過二了。
電影的情節大致就是男主角的女朋友在一場車禍身亡後,男主角偶然透過照片回到了發生車禍前的那段時間,閃避了那場車禍,回到現在的時間,過去的確被改變了。於是他便發覺他具有回到過去的能力。因此,往後只要發生不滿意的事,他便想回到過去再改變...。然而事情當然沒他想得那麼簡單,每當他回去改變了某件事,對未來便會產生層層的連鎖效應。哪怕只是小小的改變,便足以影響許多人的命運。

或許很多人都一樣,對於過去的某些事感到懊悔,多麼希望過去能重新來過,改變這一切。但實際上,你我並沒有回到過去的能力,與其想改變過去,不如學習接受過去的一切,活在當下。「改變,從現在開始。」

不過,我也多麼希望我能有回到過去的能力阿~~~但要真的有這種能力,那還真是恐佈阿~~

2008年9月4日 星期四

calloc()

C有提供在程式執行時,可以向系統要求分配記憶體,如常用的malloc(),用法如下:

double * ptr;
ptr = (double *)malloc(20 * sizeof(double));

上例是向系統要求20個記憶體空間,每個空間可以存放double值。除了malloc()外,還有另一個要求記憶體的函式calloc()。用法如下:

double * ptr;
ptr = (double *)calloc(20, sizeof(double));

差別在於calloc需要兩個參數,第一個是多少個記憶體空間,第二個則是每個空間所需要的大小。calloc()的另一個特色是他會將所有bit都設成0。

2008年9月2日 星期二

firefox 3.0.1異常

自從Debian(Lenny)的firefox升級到3.0.1後,開啟firefox時,系統就會出現回報錯誤的視窗。造成這個問題的原因主要是在gcin和firefox相容的問題。目前Lenny的gcin版本停留在1.4.0,只要升級到1.4.2以上的版本便可解決此問題。

指標常見的錯誤

先看以下的例子:

int *ptr;
*ptr = 5;

這程式碼有什麼問題呢?第二行是要將5存在ptr指標指向的位置,然而實際上ptr並沒有做初始化的動作,所以裡面的值存的是一個亂數值,所以5會不知道該存在哪,可能導致資料會覆寫或者讓程式crash。要記住的一點是當宣告一個指標變數時,系統只分配了儲存此指標的記憶體空間,我們應該還要將它初始化,如指派已配置空間的記憶體位址或者使用malloc()。


印象中我好像常常犯這個錯誤~~

陣列相加

若要計算陣列的總合,可以用以下簡單的function解決:

int sum(int array[], int size) {
    int i;
    int total = 0

    for(i = 0; i < n; i++) 
        total += array[i];

    return total;
}

然而,我們也可以用指標的方式來達到這個效果:

int sum(int *start, int *end) {
    int total = 0;

    // 這邊的end是指向陣列最後元素的下一個
    while(start < end) {
        total += *start;
        start++
        // 也可以用*start++來取代上述兩行
    }

    return total;
}

其中*start++的意思就是*(start++),加上括號可以讓程式碼更清楚明瞭。