kowala's home

kowala's home
這裡是我的學習筆記,陸續增加中。
http://kowala21.blogspot.com

2011-12-26

Dev C++ 中文轉碼測試(UTF-8 to big5) Convert Code in Dev C++ Using iconv.

在目前網際網路普遍的情況下,為了避免亂碼產生,通常都會使用 UTF-8 來編碼,然而,在 Windows 環境下作業,作業系統預設的是區域編碼(big5),這也是常常發生亂碼的原因。本文主要是針對 Dev C++ 開發環境下,使用 iconv 元件來轉碼做說明,對象是 UTF-8 轉 big5 碼,當然,簡體的部分只要改成 gb2312 就行了。

若是使用 Visual C++ 的開發者,可以使用內建的的工具來轉碼,但這不是本文探討對象,請參考這篇。
http://blog.csdn.net/password318/article/details/6958853
主要使用的函式為
MultiByteToWideChar( CP_ACP, 0, chr, strlen(chr)+1, wchar, size/sizeof(wchar[0]) );

WideCharToMultiByte( CP_ACP, 0, wchar, -1, chr, length, NULL, NULL );

在進入主題以前,先簡單的說明 UTF-8 碼與 big5 碼的差別,我們先用筆記本存一段文字,
"中文轉碼測試"
分別存成 ansi 及 UTF-8 ,然後使用 HEX 編輯器開啟它,我們可以看到,ansi 下的中文,一個字佔了 2 bytes,而 UTF-8 下的中文,一個字佔了 3 bytes,並且有前導識別碼 EF BB BF,如下圖所示。



在下面程式碼中,我們必須手動輸入 UTF-8 碼來測試用,如下

    //"中文轉碼測試";
    char utf8buf[] = {
        0xE4,0xB8,0xAD, 0xE6,0x96,0x87, 0xE8,0xBD,0x89,    0xE7,0xA2,0xBC,
        0xE6,0xB8,0xAC, 0xE8,0xA9,0xA6, 0};

因為使用的是字元陣列,所以必須在後面補個 0,作為字串結束。
先來看看執行畫面,轉碼前先顯示來源及目的字串,以供轉碼後對照之用。首先是從 UTF-8 轉到 big5,接著是把 UTF-8 清空,再從 big5 轉回去 UTF-8。



要使用 iconv 之前,我們需先對 Dev C++ 做一些前置工作,包括下載 iconv 元件,lib 載入,及一些 source code 修正等等。

首先是下載 iconv 元件,這裡的範例是使用這個,為了保證能正確運行,請下載一樣的版本。
http://www.d2school.com/cpp_lib_ex/iconv.rar

然後開啟 iconv.h ,找到第 88 行,把 const 前置詞去掉,這是因為不同的作業環境下而做的修正[1]。

extern LIBICONV_DLL_EXPORTED size_t iconv (iconv_t cd, const char* * inbuf, size_t *inbytesleft, char* * outbuf, size_t *outbytesleft);

把 const 前置詞去掉,像這樣。

 extern LIBICONV_DLL_EXPORTED size_t iconv (iconv_t cd, char* * inbuf, size_t *inbytesleft, char* * outbuf, size_t *outbytesleft);

接著把一些相關的檔案複製到 Dev C++ 下的資料夾之中

copy iconv.dll C:\Dev-Cpp\bin
copy iconv.h C:\Dev-Cpp\include
copy libiconv.a C:\Dev-Cpp\lib

再來是設定載入 iconv,開啟  專案\專案選項\參數,並加上 -liconv ,如下圖


這樣就完成前置工作了,接著開個專案,把下面的代碼貼上,執行。

/*****************************************************
  Dev C++ 中文轉碼測試 UTF-8 <-> big5
  Convert Code in Dev C++ Using iconv.
  http://kowala21.blogspot.com
  write by kowala.
  Date: 2011-12-26
 
  reference:
  [1]http://wang.yuxuan.org/blog/?itemid=64
  [2]http://www.haogongju.net/art/1081728
  [3]http://worldant.blog.sohu.com/96069463.html
  [4]http://www.gnu.org/software/libiconv
 
  dll download:
  http://www.dlldump.com/
 
  iconv package download:
  http://www.d2school.com/cpp_lib_ex/iconv.rar
******************************************************/
#include <cstdlib>
#include <iostream>
#include <iconv.h>
using namespace std;

void u2b(char src[],char tar[]);
void b2u(char src[],char tar[]);
//-----------------------------------------
int main(int argc, char *argv[]){
    cout << "中文轉碼測試 iconv ..." << endl;

    char utf8buf[] = {
        0xE4,0xB8,0xAD, 0xE6,0x96,0x87, 0xE8,0xBD,0x89,   
        0xE7,0xA2,0xBC, 0xE6,0xB8,0xAC, 0xE8,0xA9,0xA6, 0};
    char big5buf[strlen(utf8buf)/3*2+1];   

    memset(big5buf,0,strlen(big5buf));
    printf("\nUTF-8>\t%s\nbig5 >\t%s",utf8buf,big5buf);
    printf("\nUTF-8\tlen=%d\nbig5\tlen=%d\n",strlen(utf8buf),strlen(big5buf));
       
    u2b(utf8buf,big5buf);   
    printf("\nUTF-8>\t%s\nbig5 >\t%s",utf8buf,big5buf);
    printf("\nbig5\tlen=%d\n",strlen(big5buf));   
   
    memset(utf8buf,0,strlen(utf8buf));
    printf("\nbig5 >\t%s\nUTF-8>\t%s",big5buf,utf8buf);   
    printf("\nbig5\tlen=%d\nUTF-8\tlen=%d\n",strlen(big5buf),strlen(utf8buf));
   
    b2u(big5buf,utf8buf);
    printf("\nbig5 >\t%s\nUTF-8>\t%s",big5buf,utf8buf);   
    printf("\nUTF-8\tlen=%d\n",strlen(utf8buf));   
   
    system("PAUSE");
    return EXIT_SUCCESS;
}
/*----------------
  big5 轉 UTF-8
------------------*/
void b2u(char src[],char tar[]){
    cout << "\nConvert code From big5 to UTF-8...";
    size_t srclen = strlen(src);
    size_t tarlen = srclen/2*3+1;
    memset(tar,0,tarlen);
    iconv_t cd = iconv_open("UTF-8","big5");
    size_t error = iconv(cd,&src,&srclen,&tar,&tarlen);
    iconv_close(cd);
}
/*----------------
  UTF-8 轉 big5
------------------*/
void u2b(char src[],char tar[]){
    cout << "\nConvert code From UTF-8 to big5...";
    size_t srclen = strlen(src);
    size_t tarlen = srclen/3*2+1;   
    memset(tar,0,tarlen);
    iconv_t cd = iconv_open("big5","UTF-8");
    size_t error = iconv(cd,&src,&srclen,&tar,&tarlen);
    iconv_close(cd);
}

最後,轉貼請註明出處,謝謝。

kowala's home
http://kowala21.blogspot.com

參考:

  [1] http://wang.yuxuan.org/blog/?itemid=64
  [2] http://www.haogongju.net/art/1081728
  [3] http://worldant.blog.sohu.com/96069463.html
  [4] http://www.gnu.org/software/libiconv
  [5] http://blog.163.com/fqq_41/blog/static/9602733720081110104834115/

2011-11-21

兩款免費好用的編輯器 HxD & Notepad++

下面這兩款文件編輯器都是免費的,小巧好用,不會太癡肥,一個是專門處理 Hex,一個是處理Txt。

HxD 這是專看16進位碼的編輯器,輕巧好用,可以右鍵載入檔案,可以直接改機器碼,類似pctools一樣。

先與作業系統整合

右鍵開啟

內容顯示

 


Notepad++ 這是文件編輯,也是輕巧好用,內採折頁方式,開啟多個文件很方便。

 右鍵開啟

 內容顯示
 

  

 下載頁面

http://download.cnet.com/HxD-Hex-Editor/3000-2352_4-10891068.html

http://download.cnet.com/Notepad/3000-2352_4-10327521.html

2011-11-04

Dev C++ 奇數與偶數(odd and even test)

奇數與偶數在寫演算法時會常常碰到,這裡提供一個簡單的區分方法

直接來看代碼
#include <cstdlib>
#include <iostream>

using namespace std;

int main(int argc, char *argv[]){
    int i,n;
    cout << "本例測試奇數與偶數(odd and even test)\n";
    n=10;
    for(i=0;i<n;i++){
        if((i+n)%2==0)printf("i=%d 偶數(even)\n",i);                       
        if((i+n+1)%2==0)printf("i=%d 奇數(odd)\n",i);
    }   
    system("PAUSE");
    return EXIT_SUCCESS;
}

執行結果


2011-10-26

Dev C++ 亂數產生器-究竟版

嘿嘿!此究竟非彼究竟,這只是限於使用time來產生的最亂,當然,這還不真亂,眼尖者必能覺察。

先看一下代碼

//亂數產生器
int getRandom(int min,int max){
    int r;
    clock_t seed = clock();
    srand(seed);
    r= min + rand()%(max-min+1);
    return r;
}

這是取時間來當種子,使用的值是毫秒,下圖是模擬大樂透開獎,49選6... 主要是要產生49個不重複的亂數,但是現在電腦都算太快,亂數結果數值會一樣...


這時就要想個辦法減速一下,在前一個主題,遞迴函數-費式數列(Fibonacci),就派上用場了,我們可以利用遞迴函數算很慢的特性,來當減速器,隨便找個質數填進去,f(31)

#include <cstdlib>
#include <iostream>
#include <iomanip.h>

using namespace std;

//亂數產生器
int getRandom(int min,int max){
    int r;
    clock_t seed = clock();
    srand(seed);
    r= min + rand()%(max-min+1);
    return r;
}
//費式數列(Fibonacci)
double f(double n){   
    if(n<=2)return 1;   
    return f(n-1)+f(n-2);
}
int main(int argc, char *argv[]){
    int i;
    system("cls");
   
    cout << "亂數測試..." << endl;
    for(int i=1;i<=49;i++){
        f(31);    //減速器
        cout << setw(3) << setprecision(3) << getRandom(1,49) << " ";       
    }
    cout << endl;

    system("PAUSE");
    return EXIT_SUCCESS;
}

看來有點亂了,減速成功!

接著是消去重複數,這需要用個陣列來幫忙。

int main(int argc, char *argv[]){
    int i,n,v,lo[49];
    system("cls");
   
    cout << "亂數測試..." << endl;
    for(int i=0;i<49;i++){
        f(37);
        v=getRandom(1,49);
        n=0;
        while(n<i){           
            if(lo[n++]==v){
                f(23);
                v=getRandom(1,49);
                n=0;
            }
        }
        lo[i]=v;       
        cout << setw(3) << setprecision(3) << lo[i] << " ";       
    }
    cout << endl;

    system("PAUSE");
    return EXIT_SUCCESS;
}

這還是不夠亂,生氣,最後一招,改良種子,取 UTC + 毫秒  來當種子

clock_t seed = time(0)+clock();

結果不錯,每次都不一樣,這樣就夠亂了。



//亂數產生器-究竟版
int getRandom(int min,int max){
    int r;
    clock_t seed = time(0)+clock();
    srand(seed);
    r= min + rand()%(max-min+1);
    return r;
}

其實,這還是不夠亂,上圖每個數字都差3-4之間,而且都是規律遞增,所謂亂數,就是無規律,閉著眼亂點,點中就算,這樣才夠亂,我深深懷疑,電腦或是數學式能否產生出真正的亂數,要真亂的話,我只想到一個,自己拿骰子擲,然後記錄點數。

下表是我找的亂數表,懶得自己打字,所以從網路copy來的, 應該是比這個時間產生的要亂些,可以充當種子。

http://www.stat.nuk.edu.tw/prost/content2/statics_2.htm

29280 39655 18902 92531 90374 07109 26627 59587 84340 98351
20123 82082 55477 22059 43168 12903 13436 25523 21090 73449
66405 35287 33248 67657 07702 01474 66068 01125 59258 30138
97299 83419 13069 17826 76984 48906 10567 17829 00723 46700
83923 92076 98880 33942 46841 58731 36513 16681 88722 61984
11258 92175 94894 97606 11134 51941 43733 00514 06694 27706

http://wiki.mbalib.com/zh-tw/%E9%9A%8F%E6%9C%BA%E5%8F%B7%E7%A0%81%E8%A1%A8%E6%B3%95

03 47 43 73 86 36 96 47 36 61 46 98 63 71 62
97 74 24 67 62 42 81 14 57 20 42 53 32 37 32
16 76 02 27 66 56 50 26 71 07 32 90 79 78 53
12 56 85 99 26 96 96 68 27 31 05 03 72 93 15
55 59 56 35 64 38 54 82 46 22 31 62 43 09 90
16 22 77 94 39 49 54 43 54 82 17 37 93 23 78
84 42 17 53 31 57 24 55 06 88 77 04 74 47 67
63 01 63 78 59 16 95 55 67 19 98 10 50 71 75
33 21 12 34 29 78 64 56 07 82 52 42 07 44 28
57 60 86 32 44 09 47 02 96 54 49 17 46 09 62
18 18 07 92 46 44 17 16 58 09 79 83 86 19 62
26 62 38 97 75 84 16 07 44 99 83 11 46 32 24
23 42 40 54 74 82 97 77 77 81 07 45 32 14 08
62 36 28 19 95 50 92 26 11 97 00 56 76 31 38
37 85 94 35 12 83 39 50 08 30 42 34 07 96 88
70 29 17 12 13 40 33 20 38 26 13 89 51 03 74
56 62 18 37 35 96 83 50 87 75 97 12 25 93 47
99 49 57 22 77 88 42 95 45 72 16 64 36 16 00
16 08 15 04 72 33 27 14 34 09 45 59 34 68 49
31 16 93 32 43 50 27 89 87 19 20 15 37 00 49

假定這兩張表是真亂數,但是引用時,仍然會有決定哪個數值,索引值取捨的問題,你索引如何產生?如果還是時間來源的話,那依舊是陷入先前同樣的問題。


再接再厲,引入亂數表充當種子,再把前次結果加入種子,結果看起來似乎很亂了,改善了數字差3-4之間,規律遞增的問題,這樣的結果是可以接受,但是缺點是複雜了點...

 //亂數產生器-引入亂數表充當種子+反饋
int getRandom(int min,int max,int res){   
    int n,v,seed[]={
        29280,39655,18902,92531,90374, 7109,26627,59587,84340,98351,
        20123,82082,55477,22059,43168,12903,13436,25523,21090,73449,
        66405,35287,33248,67657, 7702, 1474,66068, 1125,59258,30138,
        97299,83419,13069,17826,76984,48906,10567,17829,  723,46700,
        83923,92076,98880,33942,46841,58731,36513,16681,88722,61984,
        11258,92175,94894,97606,11134,51941,43733,  514, 6694,27706    };   
    n=(time(0)+clock())%60;
    v=seed[n]+clock()+res;
    srand(v);
    return (min + rand()%(max-min+1));
}

執行結果,似乎很亂,這樣的結果是可以接受了。


完整測試列表

#include <cstdlib>
#include <iostream>
#include <iomanip.h>

using namespace std;

//亂數產生器-引入亂數表充當種子+反饋
int getRandom(int min,int max,int res){   
    int n,v,seed[]={
        29280,39655,18902,92531,90374, 7109,26627,59587,84340,98351,
        20123,82082,55477,22059,43168,12903,13436,25523,21090,73449,
        66405,35287,33248,67657, 7702, 1474,66068, 1125,59258,30138,
        97299,83419,13069,17826,76984,48906,10567,17829,  723,46700,
        83923,92076,98880,33942,46841,58731,36513,16681,88722,61984,
        11258,92175,94894,97606,11134,51941,43733,  514, 6694,27706    };   
    n=(time(0)+clock())%60;
    v=seed[n]+clock()+res;
    srand(v);
    return (min + rand()%(max-min+1));
}
//費式數列(Fibonacci)
double f(double n){   
    if(n<=2)return 1;   
    return f(n-1)+f(n-2);
}
int main(int argc, char *argv[]){
    int i,n,v,lo[49];
    long k=0;
    system("cls");
   
    cout << "亂數測試..." << endl;
    for(int i=0;i<49;i++){
        v=getRandom(1,49,lo[i]);
        f(i%31);  //減速器
        n=0;k=0;
        while(n<i){           
            if(lo[n++]==v){
                 v=getRandom(1,49,lo[i]);           
                f(i%11);  //減速器
                n=0;
            }
            k++;   //計次
        }
        lo[i]=v;       
        cout << setw(3) << setprecision(3) << lo[i] << " ";       
    }
    cout << "\n共計算了 " << k << " 次..." <<endl;

    system("PAUSE");
    return EXIT_SUCCESS;
}

2011-10-25

Dev C++ 有趣的遞迴函數-費式數列(Fibonacci)

C 語言有個好玩的寫法,就是遞迴函數(Recursive call),遞迴函數有幾項特徵,就是


1.自己呼叫自己
2.必須存在終止條件

來找個例子,一般談到遞迴,總是喜歡拿費式數列(Fibonacci)來說明,這裡也簡單的介紹一下,詳細的資料可以在維基百科[1]找到。

費式數列(Fibonacci)
數列的前兩項為 1、1,之後的每一項為前兩項之和,
即 Fn=Fn-1+Fn-2,數列的前 10 項為:
1、1、2、3、5、8、13、21、34、55、89。

是使用一種線性遞迴關係式來定義:
F_{0} = 0 \,
F_{1} = 1 \,
F_{n} = F_{n-1}+F_{n-2} \,
 設若:F_{n} / F_{n-1}\, 當n趨於無限大之極限值存在,則其值為 1+\sqrt{5} \over 2\, = Φ 恰為黃金分割之ㄧ值,1.618....,另一值則為0.618....,兩值互為倒數,也就是說1.618....分之1=0.618....,反之亦然。

我們任意取兩個連續的數來除,很容易可以得到一比值

    89/55=1.618181818181...
    55/34=1.617647058823...
    34/21=1.619047619047...
    21/13=1.615384615384...
    13/8=1.625
    8/5=1.6
    5/3=1.66666666666666...

這就是有名的黃金比例 1.618...

好了,介紹到這裡,讓我們來看看如何在 C++ 中實現...

這是費式數列(Fibonacci)的寫法,C++可以很簡潔的表示出來[2].

double f(double n){
    if(n<=2)return 1;   
    return f(n-1)+f(n-2);
}

簡單說明一下遞迴函數的特徵

if(n<=2)return 1;          這是中止條件
return f(n-1)+f(n-2);     這是自己呼叫自己

來實做一下
//-----------------------------------------------------------
#include <cstdlib>
#include <iostream>
#include <iomanip.h>

using namespace std;

//費式數列(Fibonacci)
double f(double n){
    if(n<=2)return 1;  
    return f(n-1)+f(n-2);
}
int main(int argc, char *argv[]){
    int i,n;
    system("cls");
  
    cout << "遞迴測試 - 費式數列(Fibonacci)" << endl;
    cout << "------------------------------" << endl;
  
    n=30;
    for(int i=1;i<=n;i++){
        cout << "Loop " << setw(5) << setprecision(5) << setfill(' ') << i
        << setw(10) << setprecision(10) << setfill(' ')<< f(i) << "\n";
    }
  
    cout << "\n黃金比例 (f(9)/f(8)) = " << f(9)/f(8) << endl << endl;
  
    system("PAUSE");
    return EXIT_SUCCESS;
}

//-----------------------------------------------------------


結果如下


這個是為了對齊而對 cout 做了一些指定
cout << "Loop " << setw(5) << setprecision(5) << setfill(' ') << i

setw(5)  設定5個字組寬
setprecision(5)  設定5個數字
setfill(' ')  空格補 space

為了觀察遞迴函數的運作,我們在裏頭加一行顯示其值,如下

double fi(double n){
    cout << n << " ";   
    if(n<=2)return 1;   
    return fi(n-1)+fi(n-2);
}

再把 n 改小一點,n=10,再跑看看

    n=10;
    for(int i=1;i<=n;i++){
        cout << "Loop " << setw(5) << setprecision(5) << setfill(' ') << i
        << setw(10) << setprecision(10) << setfill(' ')<< fi(i) << "\n";
    }
這次就可以清楚看到它被執行幾次了。

參考資料:
1.遞迴關係式
http://zh.wikipedia.org/wiki/%E9%81%9E%E8%BF%B4%E9%97%9C%E4%BF%82%E5%BC%8F

2.費式(Fibonacci)數列  
http://dhcp.tcgs.tc.edu.tw/c/p014.htm

2011-10-12

Dev C++ 製作動態三維陣列物件

資料存取物件化之二

kowala's home
http://kowala21.blogspot.com

繼前一篇 物件化的資料存取-動態二維陣列物件,再接再厲推出了三維陣列物件,其實原理都一樣,就是ㄧ串指標陣列,後面接個 int 元素陣列(本例為int),示意如下。

二維陣列物件     指標陣列->int 元素陣列

三維陣列物件    指標陣列-> 指標陣列->int 元素陣列

然後把它封裝起來,三維陣列物件應該很夠用了,已能處理大多數的問題了。

先來看看執行結果


紅色圈選處是測試寫入,最下面三個是讀出測試,完整程式碼如下。

#include <cstdlib>
#include <iostream>

using namespace std;

/*******************************************************************
3D array Object
2011-10-12
kowala's home  http://kowala21.blogspot.com
ref: http://www.programmer-club.com.tw/ShowSameTitleN/c/37868.html  
********************************************************************/
typedef int** array3d;
class SrcData3D{
    array3d *matrix;
    int m_rows;
    int m_cols;
    int m_hight;
    public:
    SrcData3D();
    void initData(int row,int col,int hight,int var);
    void relaxData();
    void dumpData();
    void setData(int row,int col,int hight,int var);
    int getData(int row,int col,int hight);
};

int main(int argc, char *argv[]){
    system("cls");
    int row=3,col=7,hight=5;

    SrcData3D s3d;

    cout << "initial 3D array by -1 ..." << endl;
    s3d.initData(row,col,hight,-1);
    s3d.dumpData();
  
    cout << "set value to 3D array..." << endl;
    s3d.setData(0,1,0,1);
    s3d.setData(0,2,1,2);
    s3d.setData(0,3,2,3);
    s3d.setData(1,2,1,4);
    s3d.setData(1,3,2,5);
    s3d.setData(1,4,3,6);
    s3d.setData(2,3,2,7);
    s3d.setData(2,4,3,8);
    s3d.setData(2,5,4,9);
    s3d.dumpData();
  
    cout << "get value from 3D array..." << endl;
    cout << "[0,3,2]=" << s3d.getData(0,3,2) << endl;
    cout << "[1,4,3]=" << s3d.getData(1,4,3) << endl;
    cout << "[2,5,4]=" << s3d.getData(2,5,4) << endl;
  
    s3d.relaxData();  

    system("PAUSE");
    return EXIT_SUCCESS;
}
//建構子
SrcData3D::SrcData3D(){    m_rows=1;m_cols=2;m_hight=3;}
//設定參數
void SrcData3D::setData(int row,int col,int hight,int var){    matrix[row][col][hight]=var;}
//取出參數
int SrcData3D::getData(int row,int col,int hight){    return matrix[row][col][hight];}
//初始化陣列
void SrcData3D::initData(int row,int col,int hight,int var){
    m_rows=row;m_cols=col;m_hight=hight;
    SrcData3D::matrix=new array3d[m_rows];
    for(int i=0;i<m_rows;i++){
        SrcData3D::matrix[i]=new int*[m_cols];
        for(int j=0;j<m_cols;j++){
            SrcData3D::matrix[i][j]=new int[m_hight];
            for(int k=0;k<m_hight;k++){
                SrcData3D::matrix[i][j][k]=var;
            }
        }
    }
}
//釋放陣列
void SrcData3D::relaxData(){
    for(int i=0;i<m_rows;i++){      
        for(int j=0;j<m_cols;j++){
            delete [] SrcData3D::matrix[i][j];      
        }
        delete [] SrcData3D::matrix[i];
    }
    delete [] SrcData3D::matrix;
}
//傾印資料
void SrcData3D::dumpData(){  
    cout << "rows=" << m_rows << ",cols=" << m_cols << ",hight=" << m_hight << endl;
    for(int i=0;i<m_rows;i++){      
        for(int j=0;j<m_cols;j++){
            for(int k=0;k<m_hight;k++){
                cout << "[" << i << "," << j << "," << k << "]=" << SrcData3D::matrix[i][j][k] << "  ";
            }
            cout << endl;
        }
        cout << endl;
    }
    cout << endl;
}

2011-10-11

Dev C++ 物件化的資料存取-動態二維陣列物件

資料存取物件化

kowala's home
http://kowala21.blogspot.com

這裡使用Dev C++ 來製作動態二維陣列物件,通常在使用陣列時,常常會被指標搞的暈頭轉向,但是使用陣列用來儲存資料,卻又是必須的工具,如何避免被複雜的指標干擾寫作程式,使用物件的觀念卻是必要的,把底層複雜運算封裝起來,上層就可以單純的存取,這對於大型程式開發,是很重要的觀念。

底下程式是先製作一個動態二維陣列物件,然後實作,存取測試,完整程式碼如下:
本篇是使用 C++ 語法



#include <cstdlib>
#include <iostream>

using namespace std;
/*******************************************************************
2D Array Object
2011-10-11kowala's home  http://kowala21.blogspot.com
ref: http://www.programmer-club.com.tw/ShowSameTitleN/c/37868.html   
********************************************************************/
typedef int* array;
class SrcData{
    array *matrix;
    int m_rows;
    int m_cols;
    public:
    SrcData();
    void initData(int row,int col,int var);
    void relaxData();
    void dumpData();
    void setData(int row,int col,int var);
    int getData(int row,int col);
};

int main(int argc, char *argv[]){
    system("cls");
    int row=3,col=7;
    SrcData sd;
   
    cout << "initial array by -1 ..." << endl;
    sd.initData(row,col,-1);
    sd.dumpData();
   
    cout << "set value to array..." << endl;
    sd.setData(0,1,1);
    sd.setData(0,2,2);
    sd.setData(0,3,3);
    sd.setData(1,2,4);
    sd.setData(1,3,5);
    sd.setData(1,4,6);
    sd.setData(2,3,7);
    sd.setData(2,4,8);
    sd.setData(2,5,9);
    sd.dumpData();
   
    cout << "get value from array..." << endl;
    cout << "[0,1]=" << sd.getData(0,1) << endl;
    cout << "[1,2]=" << sd.getData(1,2) << endl;
    cout << "[2,3]=" << sd.getData(2,3) << endl;
   
    sd.relaxData();   
   
    system("PAUSE");
    return EXIT_SUCCESS;
}
//--------------------------------------------------
//建構子
SrcData::SrcData(){    m_rows=1;m_cols=2;}
//設定參數
void SrcData::setData(int row,int col,int var){    matrix[row][col]=var;}
//取出參數
int SrcData::getData(int row,int col){    return matrix[row][col];}
//初始化陣列
void SrcData::initData(int row,int col,int var){
    m_rows=row;m_cols=col;
    SrcData::matrix=new array[m_rows];
    for(int i=0;i<m_rows;i++){
        SrcData::matrix[i]=new int[m_cols];
        for(int j=0;j<m_cols;j++){
            SrcData::matrix[i][j]=var;
        }
    }
}
//釋放陣列
void SrcData::relaxData(){
    for(int i=0;i<m_rows;i++){
        delete [] SrcData::matrix[i];       
    }
    delete [] SrcData::matrix;
}
//傾印資料
void SrcData::dumpData(){
    cout << "rows=" << m_rows << ",cols=" << m_cols << endl;
    for(int i=0;i<m_rows;i++){       
        for(int j=0;j<m_cols;j++){           
            cout << "[" << i << "," << j << "]=" << SrcData::matrix[i][j] << "  ";
        }
        cout << endl;
    }
    cout << endl;
}

執行結果如下圖




參考資料:
1.如何傳遞動態的二維陣列給函式 doggie (franklin)
http://www.programmer-club.com.tw/ShowSameTitleN/c/37868.html
2.C++教學(二十八):在參數列傳遞陣列 大頭嬰
http://www.hala.bz/read.php?tid=7138

2011-10-01

Dev C++ 參數 main(int argc, char *argv[])

這是第一篇介紹 Dev C++ 如何操作,開始先介紹環境設定,再來是如何讀入參數,用 Dev C++ 這個工具可以完全取代 Turbo C 2.0,毫無問題.

經過這幾天測試,它可以正確的編譯32位元命令列程式,不再有定址的限制了 ^^
但是它預設的編輯視窗,若在要左邊顯示行號,則會出現一片黑,或者用滑鼠反白,也會出現一片黑,這是預設前景色跟背景色沒設好的關係,沒關係,直接找到 Visual Studio 風格套用,就一切正常了。



 一開始要先開個專案,名稱隨意,然後選擇 Console Application,這就是命令列模式,然後找個地方存起來,我是在桌面弄一個資料夾來放,比較方便。


可以先試跑一下看看,這是 DevC++ 產生的程式碼。



接著來看看如何傳參數給程式,當作第一個範例。我們必須先設定執行的參數,然後再用程式碼去取出來,最後印出來。先找到

執行\參數\要傳給程式的參數

輸入

70230 out70230 20 2 2

 一共5個,然後按確定,如下圖。



然後輸入下列程式碼


 #include <stdio.h>
#include <stdlib.h>
    char msg[128]="\nKG Ver:\t1.0.0\nDate:\t2011-09-30\nUsage:\tKG infile outfile samples chknum continuenum\n";
    char inputfile[32];        //資料檔名
    char outputfile[32];    //輸出檔名
    int samples;            //樣本數
    int chknum;                //比對基數
    int contnum;            //連續次數
 int main(int argc, char *argv[]){
     int i,n;
     system("cls");
    printf("%s",msg);
    //取參數
    strcpy(inputfile,argv[1]);
    strcpy(outputfile,argv[2]);
    samples=atoi(argv[3]);
    chknum=atoi(argv[4]);
    contnum=atoi(argv[5]);
    printf("\nargc = %d\n",argc);
    for(i=0;i<argc;i++)printf("argv[%d] = %s\n",i,argv[i]);
    system("PAUSE");
    return 0;
}

輸入完成後,按下工具列圖示,左上第2排第3個,編譯並執行,就可以看到執行畫面了,很簡單就可以上手的,語法就是標準的C語言。
上面程式碼中,用 system("cls"); 來清畫面,以取代以前 Turbo C 的  clrscr();

執行畫面,如何?正確取得參數並秀出來了。 ^^


附帶一提,我在除錯過程中,發生過 lag 現象,CPU跑到99%,等了許久,原因不明,當時是使用單步執行 F7。若是迴圈太多的話,建議直接看程式跑的結果,或是加入暫停的副程式碼來代替單步執行 F7,如下所示。

 mywait("now, it is at where...");
 ...

 /***************************
    暫停,Enter繼續,除錯用
****************************/
void mywait(char *msg){
    char ch;
    printf("\n%s",msg);
    while ((ch=getchar())!='\n'){}  
}


Dev C++ 網址  http://www.bloodshed.net/dev/devcpp.html
這篇本來昨天就要寫的,結果都在看 youtube,昨天的大熱門新聞,就是天宮一號了,現在有太空站的國家就是美、俄、中 三國了,真強。

天宮一號發射圓滿成功 
http://www.youtube.com/watch?v=IVZSs1GmG5M

這是之前神州七號的太空漫步,回顧一下。
http://www.youtube.com/watch?v=gMxQEHfU6hM&feature=like-suggest&list=UL

2011-09-28

Turbo C 2.0 的陣列大小限制

若在程式中使用大量的陣列元素,很容易產生 Array size too large in function main 錯誤,如下圖所示。


本例的結構體如下

    struct node{
        int period;        /* 期別 */
        int length;        /* 資料長度 */
        int numbers[60];    /* 資料 */
        int marks[60];        /* 標記 */
    };
    struct fnode{
        char fname[32];        /* 資料名 */
        struct node *data[100];    /* 資料長度 */
    };

在 main() 中宣告
    struct fnode tarData[5];
...
    tarData[0].data = (struct node*) malloc(100 * sizeof(struct node));
    tarData[1].data = (struct node*) malloc(100 * sizeof(struct node));

若大小超過 tarData[2] 就會發生上述錯誤了

 Array size too large in function main

其發生原因為Turbo C 2.0 它是16位元編譯器,最大定址能力是 2^16 = 65536
超過就會產生錯誤了

解決辦法

在試過許多方法後,我的建議是換一個32位元編譯器 = ="
這裡我建議使用 Dev C++ 5.0
網址 http://www.bloodshed.net/dev/devcpp.html
下載 SourceForge
它的優點很多,它是免費軟體,window 介面,可以寫視窗及命令列程式,支援 C & C++。

最重要的是我會陸續寫操作方法 ^ ^
無痛上手,這也是選擇工具的重要因素之一。

2011-09-20

UFO 關於飛碟

最近看到網路上流傳的 FBI 飛碟解密消息,說羅茲威爾事件是真的,讓我找了一堆相關消息,都是網路上的資料,讀者須自己去驗證真偽。

一、契子
就由這裡當作一個起點,來一趟飛碟之旅。


二、事件觀察
這是羅茲威爾事件 UFO Roswell Crash 的部分影片,注意,操作盤是6根手指,這與解剖外星人的影片吻合。


 以下是解剖影片,較為血腥,未成年不宜觀賞。

再來看看較為清晰飛碟的影片,這是美國世貿還沒倒塌之前的影片,可以看到飛碟的大角度高速飛行,目前人類科技還無法做到。

最清晰的飛碟影片,似乎是從望遠鏡拍的,還可以看見兩位外星人身影。

他們很關心我們的科技發展,常常被戰鬥機拍到飛碟。


三、蘇聯發現的 UFO 墬毀事件
四、常見的外星人
常見的有兩種(網路上的影片),一種是頭部比例較大,另一種是眼睛很大,像是戴墨鏡般,這也是俗稱的小灰人,據信,他們有傳遞訊息給我們,如下圖的麥田圈。


五、飛碟的原理探討
目前世界各國都視為最高機密,關起門來偷偷研究,所以到底如何,也只能用猜的,這裡討論兩個,一個 Bob Lazar 口述,他是位物理學者,曾被美國海軍吸收到 Area51 區中的 s4 計畫案,那是研究飛碟原理的一個案子,他提到,在強大重力下,時間及空間可以被扭曲,那穿過這個空間到下個空間,不就成了瞬間移動,其實這在飛船上感覺是正常飛行,但是我們看來就變成瞬間移動了,這不同於光速飛行,因為若以光速通過小行星帶,飛船有可能被撞擊而解體,而空間扭曲飛行就沒這問題,這是挺有趣的問題。

超時空旅行
http://www.youtube.com/watch?v=UT28xx5xx1c&feature=related


天狼星記錄片《SIRIUS》
http://www.youtube.com/watch?v=g4_h21ogf68
《SIRIUS》是一部史無前例紀錄片!製作人Dr. Greer花了十多年的心血從事揭秘UFO,ET,自由能源等被政府隱瞞了長達60年­­的秘密,並且成立了Disclosure Project (揭秘計劃),CSETI(外星人研究中心),還有和本片有很大關係的SIRIUS Project(天狼星計劃).
影片的一大亮點是Dr. Greer會與大家分享在智利沙漠被找到的"ATACAMA外星人"遺體,並且把它送­­往美國斯坦福大學醫學院進行全面的專業鑑定,包括DNA,CT,X光,骨髓等方面的­檢­測,具體內容還是請大家看影片......



以下 Bob Lazar 專訪影片,中文翻譯出處如下連結,感謝小老虎的翻譯,並期待能有更多的作品。
http://blog.xuite.net/whitefang/UFO?st=c&p=1&w=2521444







 另一個稱為哈奇森效應 Hutchison effect,這看起來像是應用磁場來造成反重力的現象,還能使金屬液化,奇怪的是,網路上此類討論並不熱絡,不知為何,這似乎最有可能成為飛碟動力的候選原理之一。

下面第一支影片中提到實驗的鉬棒彎曲,美國軍方亞歷山大上校提到,可能是由於精神力造成(特異功能),個人認為,他想誤導別人的研究方向,由此推斷,或許這是正確的方向,他們在此方向研究可能已取得進展,並且不希望別人趕上,當然,這只是個人的猜測,希望讀者能自行判斷。










最後一個是知識頻道在十幾年前撥出過的影片,科學家們運用磁場使青蛙及蚱蜢及蔬菜飄浮在6m高的管中。

六、結語
看完了上列影片,哈奇森效應 Hutchison effect,如果反重力可以透過強大電場及磁場的機制產生,那飛船上的設備該由何種方式來提供足夠的電力呢?總不能把整座核電廠搬上飛船去吧,再根據 Bob Lazar 提到,某種元素安定的特性(原子量115,不具放射性),若以它來做為特殊的反應爐,就是不會傷害人體的能源產生器了。
飛碟這外星科技,也不是短期就能有所突破的,也正如 Bob Lazar 所提,應該公開研究,也許會比較有進展,這也是多數人的好奇心與期待。 ^^


相關資料

1. 其实人类早就能操纵反重力了—哈奇森效应(Hutchison Effect)

2.  H效应(The Hutchison Effect / 零重力效应)的详细介绍 

2011-09-19

The Coriolis Effect 科里奧利效應

這個應該算是物理課吧! 從小在洗澡後,把排水塞子拔起後,水總是產生一個順時針旋渦,經過擾亂後,不一會又恢復成順時針旋渦,真是奇怪阿~

其實這就是科里奧利效應 The Coriolis Effect,它是慣性與地球自轉所產生的一種結果[1],來看看下面的影片就可以了解了。

Source from  http://www.youtube.com/watch?v=__SlJtnpCD8&feature=related


這除了可以解釋為何旋渦總是順時針,還可以解釋颱風總是從菲律賓來,然後跑去日本 = ="
當然,如果你住在南半球,例如澳洲,那漩渦可就變成逆時針了喔。

在應用方面,可能有關的科技包括火箭、飛彈、導彈... 等等。

參考資料
[1]. 筑龙百科 http://wiki.zhulong.com/baike/read283635.htm
如果你从靠近中心的一点出发,向靠近外缘的一点走去,然后回头向靠近中心的一点走去,而且沿着阻力最小的路径前进,你就会发现,你走的路径大体上是一个圆形。法国物理学家科里奥利于1835年第一次详细地研究了这种现象,因此这种现象称为“科里奥利效应”。有时也把它称为“科里奥利力”,但它并不真是一种力;它只不过是惯性的结果。

2011-08-25

Turbo C 小技巧篇-如何齊頭列印連續數字

8月底了,竟然沒半篇文章,快弄一篇上來湊版面...

我們如果想要列印數字行頭,我們會希望整齊顯示,並且不要有空白。

#01>
#02>
#03>
...
#99>

但是通常會變成這樣,


#1>
#2>
#3>
...
#99>

那是因為使用整數列印的關係

例如:

for(i=1;i<100;i++){
 printf("#%d> ",i);
}

但是若把它改成字串,就可以了

char tmp[3];
...
for(i=1;i<100;i++){
    if(i<10){
        tmp[0]='0';tmp[1]=i+0x30+1;tmp[2]=0;
    }else{
        itoa(i,tmp,10);
    }

    printf("#%s> ",tmp);
}

如此就可以正確整齊顯示了。

2011-07-26

Turbo C 結構體的使用

本範例示範結構體的使用
如何傳遞結構體給函數,
有如物件般,把資料封裝起來.

執行如圖



由於結構太大,所以無法一一列出,故只能跳著列出,每20層一印,每層又有20筆,總執行次數為 n = 11000次,結構示意如下

<01期>
    |--<01層>
    |        |--<10筆>
    |        |--<10筆>
    |--<02層>
            |--<10筆>
            |--<10筆>
 ...
    |--<100層>
            |--<10筆>
            |--<10筆>
 ...
<10期>
    |--<01層>
    |        |--<10筆>
    |        |--<10筆>
    |--<02層>
            |--<10筆>
            |--<10筆>

 ...
    |--<100層>
            |--<10筆>
            |--<10筆>

程式碼如下

#include <conio.h>
#include <stdio.h>
#include <string.h>
    char msg[128]="TC struct data test.\nby kowala... \t2011-07-26\n";
    struct data{
        int position[10];
        int mapping[10];
    };
    struct node{
        int period;
        struct data numbers[100];
    };
    struct node srcNode[10];        /* 示範結構體 */

/* 畫線 */
void print_line(){printf("\n---------------------------------\n");}
/* 清結構體 */
void clrNode(struct node *map,int len){
    int i,j,k;   
    for(i=0;i<=len;i++){
        map[i].period=0;
        for(j=0;j<100;j++){
            for(k=0;k<10;k++){
                map[i].numbers[j].position[k]=0;
                map[i].numbers[j].mapping[k]=0;
            }       
        }
    }   
}
/*******************************
本範例示範結構體的使用
*******************************/
void main() {
    int i,j,k,n,nodeCount=10;   
    clrscr();
    printf("%s\n",msg);

    clrNode(&srcNode,nodeCount);    /* 清結構體 */
    n=0;
    for(i=0;i<=nodeCount;i++){       
        printf("1-%d(%d) ",i,srcNode[i].period);
        for(j=0;j<100;j++){
            for(k=0;k<10;k++){
            n++;
            if(j%20==0 && k==0)
            printf("2-%d(%d,%d) ",j,srcNode[i].numbers[j].position[k],srcNode[i].numbers[j].mapping[k]);
            }
        }
        printf("\n");
    }   
    printf("After %d calculation...\n",n);
    print_line();
}

2011-07-19

Win7 批次檔 for 寫法

我發現有些指令都沒動作了,像是以前常用的 inkey.com [1] ,現在都不行用了!
剛測試還能跑 for 迴圈,簡單寫個 Memo 起來備查。

測試 kb.exe  <-- 這是我要跑的目標程式
輸入檔 input01, input02, input03 .... input20
輸出結果 01.out,  02.out,  03.out,  ... 20.out

執行畫面轉向到 dbg.txt

使用了兩個批次檔,一個跑迴圈,一個帶參數執行,FOR 迴圈指令,我是寫成一行,沒換行。

go.bat
-------------------檔案開始-----------------------
@echo off
echo Debug for KB.EXE v.1.0.1 > dbg.txt
FOR %%A IN (01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20) DO call gokb input%%A %%A >> dbg.txt
del *.out
type dbg.txt
echo.
echo You can reading dbg.txt for test detail. @_@
echo.
pause
---------------------檔案結束---------------------


gokb.bat
----------------------檔案開始--------------------
@echo off
echo.
echo  ========================= start %1 =========================
kb %1 %2.out
-------------------檔案結束-----------------------

在 win7 下可以跑
ASCII 表
這也是很常用的ASCII對照表: 


註:
[1].inkey.com 是讀鍵值小程式,通常都是搭配 if errorlevel==27  goto xxx 來使用
製作方法如下( 27 = 0x1B = ESC )

製作 inkey.com ,由 Windows 內建的工具 debug 來製作即可,按下開始按鈕後,上面搜尋欄位輸入 cmd 再按 enter ,就會跑出命令列視窗,


 輸入debug 就可以叫出如下畫面,然後依照下圖輸入組合語言指令,輸入完成後,按 Ctrl+C 中止輸入,指定長度 rcx 為 24,指定名稱 n,再寫出 w,離開 q ... 就完成了。

接受合法鍵值 ESC, 0-9, a-z, A-Z
其他鍵值會重新輸入,直到正確鍵值為止,傳回鍵值可以用 errorlevel 去接

Microsoft Windows [???? 6.1.7600]
Copyright (c) 2009 Microsoft Corporation.  All rights reserved.

C:\Users\aaa>debug

-a 100
1392:0100 mov ah,00
1392:0102 int 16
1392:0104 cmp al,1b
1392:0106 je 120
1392:0108 cmp al,30
1392:010A jl 0100
1392:010C cmp al,7a
1392:010E jg 100
1392:0110 cmp al,39
1392:0112 jle 120
1392:0114 cmp al,61
1392:0116 jge 120
1392:0118 cmp al,41
1392:011A jl 100
1392:011C cmp al,5a
1392:011E jg 100
1392:0120 mov ah,4c
1392:0122 int 21
1392:0124 ^C
-rcx
CX 0000
:24
-n inkey
-w
Writing 00024 bytes
-q

C:\Users\aaa>

再把它改名為 inkey.com 就能用了,但在 windows 環境中不能跑 = =,只能用在 dos 環境。

2011-07-14

Turbo C - 字串陣列參數處理

能夠看到這裡,就是有緣,可以為您省下大半天的時間,說實在的,TC的字串功能不太友善,相信有經驗的人就知道,字串陣列又比較麻煩,常常都耗掉許多時間測試。

字串陣列的問題是出在 "不定長度",它不像數值陣列,每個元素長度固定,字串都是以 '\0' 做結尾的,舉例來說

char a[3];
a[0] <= "不定"
a[1] <= "不定長"
a[2] <= "不定長度"

看了上例知道,字串就是不定長度。能正確使用字串,大約有兩種方法,一是固定長度,二是用指標,其實指標也是固定長度,傳遞位址的長度就是int。下面範例兩種方法都用,先把數字轉成字串再存入陣列之中,因為是要實驗字串,不是數字。

在下面範例中,固定長度的關鍵在於宣告字串陣列的長度 [1]

 void setArr2(char nodeArr[][3] )

這樣才能正確取到陣列元素


void setArr1();
void setArr2();

void main() {
    char msg[50];
    char data[50][3];
    int i;

    clrscr();
    printf("\n\tArray test...\n\n");

    setArr1(&msg);
    printf("%s\n",msg);
    setArr2(&data);
    for(i=0;i<50;i++)printf("data[%d] = %s\t",i,data[i]);
}
/* 用指標 */
void setArr1(char *msgArr){
    strcpy(msgArr,"Hello, here show you how to deal with char[].\n");
}
/* 固定長度 */
void setArr2(char nodeArr[][3]){
    int i;
    char tmp[3];
    for(i=0;i<50;i++){
        itoa(i,tmp,10);
        strcpy(nodeArr[i],tmp);      
    }
}

結果如下


參考資料
[1]  Turbo C 簡介

2011-07-13

Turbo C -參數 main(int argc, char *argv[])

這幾天幫人重整老東西,用 Turbo C 2.0 寫的,就順手把它整理上來放,現在好像很多學校還是喜歡用這個工具來教學,特別是資料結構之類的課。Turbo C 簡稱 TC,是 Borland 公司的產品,現在好像有開放下載,所以 Google 一查就可以找到載點。

main(int argc, char *argv[])

這是甚麼呢?這是很古早時代在用的東西,當程式執行時,在程式尾端掛幾個參數,這是很常用的手法,那在開發環境中要怎麼寫這種程式及測試呢,以下就是個小範例。


先來看看程式碼

#include <conio.h>
#include <stdio.h>
#include <string.h>

char str1[32];
char str2[32];
char str3[32];

int main(int argc, char *argv[]) {

    int i;
    clrscr();

    printf("\nargc = %d\n",argc);
    for(i=0;i<=3;i++)printf("argv[%d] = %s\n",i,argv[i]);

    strcpy(str1,argv[1]);
    strcpy(str2,argv[2]);
    strcpy(str3,argv[3]);

    printf("\n");
    printf("str1 = %s\n",str1);
    printf("str2 = %s\n",str2);
    printf("str3 = %s\n",str3);
  
    return(0);
}

執行結果


傳入參數在 Turbo C 中的設定


說明

上圖紅色所框的部分就是宣告引入參數
int argc 這個是傳入的參數個數,是整數值
char *argv[]  這個是參數值,是C字串格式,如果要用數字的話,可以使用 atoi() 來轉數字。

例如
count=atoi(argv[0]);    /* 字串轉數字 */

參數部分說明,本例是測試 3 個參數,

d2340.354
opennum
e2340.354

但是 argc 卻會顯示 4 個,因為 argv[] 第一個都固定放程式的執行路徑,所以變成4個了,如圖一可知,參數有四個。

要如何取出參數呢,我們知道參數是C字串,不能直接指定給變數 str1、str2、str2,而是要透過函數 strcpy() 取出。

char str1[32];
char str2[32];
char str3[32];
....

    strcpy(str1,argv[1]);
    strcpy(str2,argv[2]);
    strcpy(str3,argv[3]);

這樣就行了。 ^^

[註]C字串:就是字元陣列,在最尾端擺入 '\0' 當作字串結束標記
char mystr = {'a','b','c','d','e','f','g','\0'}
mystr = "abcdefg";
古早時候是沒有 String 的。