2011年12月24日 星期六

[C++] 把vector當陣列用以及副函式傳遞

//main宣告 參考前篇vector用法
vector<vector<int> > Variance_SD(m, vector<int>(n));

//副函式宣告
void SD(vector<vector<int> >&);

//副函式用&接
void SD(vector<vector<int> >& variance){
    //可以直接當array用了
    cout << variance[1][1];
}

[轉錄] C/C++ 的多維動態陣列

轉錄連結:http://lagunawang.pixnet.net/blog/post/7741220-%5B%E8%BD%89%E9%8C%84%5Dc-c%2B%2B-%E7%9A%84%E5%A4%9A%E7%B6%AD%E5%8B%95%E6%85%8B%E9%99%A3%E5%88%97


多維動態陣列在 C 中 大概只能用 malloc,但這在一維時尚
不構成問題,但需要多維陣列時怎麼辦呢?這算是程式論壇
最常被問到的問題之一了。
我把它整理了相關的回覆,都只用二維做說明,更多維的陣列
類推即可。
就從 C 談起吧!


動態產生一個[m][n]陣列 Array 的方法 
code:
int i; int **Array; Array= (int **)malloc(m*sizeof(void *)); for (i=0; i<m; i++) Array[i]=(int *)malloc(n*sizeof(int *));

這樣你就有一個 int Array[m][n]; 可以用了
是C 喔!不是 C++
但這不夠好,若你要的是一個較大的mXn陣列,那麼太多的malloc
會使記憶體碎片化(memory fragment)!沒關係,窮則變,變則通!
問題既出在for loop不斷的 memory allocation,就從那兒下手: 
code:
int i; int **Array, *pData; Array= (int **)malloc(m*sizeof(int *)); pData= (int *)malloc(m*n*sizeof(int)); for (i=0; i<m; i++, pData+=n) Array[i]=pData;

注意到嗎?這次只用了二次的malloc。
當要release memory也只要free Array[0] 和 Array 就成了!
(注意先free Array[0] 再 free Array)
如果嫌兩個alloc/free還是太多,也可簡單併成一個: 
code:
int i; int **Array, *pData; Array= (int **)malloc(m*sizeof(int *)+m*n*sizeof(int)); for (i=0,pData= (int *)(Array+m); i<m; i++, pData+=n) Array[i]=pData;

要 free 時只要 free Array 就行了,帥吧?
如果用的是C++,那可用的方法就更多了!

《幼幼班》嘗試錯誤的階段
?> int Array[][] = new int [10][20];//這樣行ㄇ?
當然不行! int Array[][]不是一個指標,而且只能有
一維為不定大小。

《小班》終於會從1數到100了
?> 那...
?> int *Array[] = new int [10][20];//這樣行ㄇ?
有點想法了!但可惜的是 '*' 在 C++的語法是修飾前面的
識別字,所以 int *Array[]的意思是 "Array是一個 int 指標
的一維陣列!"

如果能使那個 '*' 以獨立指標型態去宣告Array,就會變成
"Array是一個指標,指向一維 int 的陣列",而我們知道指標
本身就可以當做一維的陣列,那麼是不是就成了"Array是一個二維
的int陣列"?
對了!這正是我們要的!問題是怎麼讓'*'成為獨立指標型態,
不會去修飾前面的int識別字?答案是使用括號:
int (*Array)[20] = new int [10][20];//這是正解!

但問題又來了, new 運算子可以使用 new int [m][n],但
int (*Array)[20] 的 [20]卻沒辦法以 [n] 來取代,所以就
沒辦法做到不定大小的宣告了。所以這只能算是小班的答案,
要做到不定大小的動態多維宣告,加上 STL 的運用,是不錯
的想法。

《中班》vector 模板的運用
vector<int> *array=new vector<int>[m];
for (int i=0; i<n; i++) array[i].reserve(n); 

嘿嘿...不錯吧!?不定大小的二維陣列,而且每個維度還
可以隨時調整大小喔!
不過還是有缺點ㄟ!!那行 for loop 看起來有點礙眼,不能
拿掉嗎?拿掉的話,基本上Array 還是二維陣列,但第二維
並沒有預留空間放東西你可以用push.back等成員函式來增加
空間和存放data,但不能在還沒有空間時使用像
array[5][3]=3; 這種陣列的存取方式。沒更好的方法了嗎?
vector 不是有預留空間大小的建構子嗎?像一維的宣告:
vector<int> *Array= new vector <int>(n);
//這不是預留了 n 個元素的陣列了嗎?
只可惜,這是一維的宣告,若你嘗試做這樣的宣告:
vector<int> *Array= new vector <int>[m](n);
編譯器會給你無情的嘲諷:陣列不能呼叫帶參數的建構子!
這是很令人失望的!為十麼不行?不是邏輯的問題,或許下
一版本的C++會可以這樣宣告吧!但為今之計只能自力救濟
了。

《大班》使用模板在模版中
仔細觀察下面的宣告:
vector<vector<int> > Array(m, vector<int>(n));

不用懷疑!這是相當於宣告一個動態二維不定大小的 int Array[m][n];
不相信的話你可以在m,n範圍內存取 Array[i][j] 看看。
若你能一眼看出這是在幹嘛,那麼你早已超出大班的程度了!
若你暫時不知所云,也沒關係,你可以安全的使用它帶給你的好處。
只是你也只好留在大班留班查看了 ^_^

解釋這個宣告,其實不難,但首先你要對模版的使用有相當的了解,當然
還要對 vector 模版的建構子不能陌生。這樣子自然很容易可以看得懂它。
了然於胸了嗎?恭喜你,大班可以畢業了 ^_@


註:大班的答案是Duncan在練功房提出的解答,注意到兩個
兩個角括號中間的空白了嗎?(> >)
^-------這裡要有空白
不加空白的話會被語法解析為右移運算子。 

2011年7月12日 星期二

[Embedded] EDK6446 NOTE

[ubuntu] NFS Server on Ubuntu NFS

[ubuntu] minicom – 進入嵌入式系統的第一步 minicom

[達文西] 建置開發環境 – Based on EDK6446 with LEOs for DaVinci

*VM要連上板子如果連不上 試試~
打開edit--->Virtual Network Editor,這個時候出現一個選擇框,選中VMn​​et0,在下面的VMnet Information中,點Bridge to:選擇你自己的網卡,當你開發板ping主機或虛擬機時,感覺設置都沒問題,就是哪裡斷了,其實就在這裡需要指定你的網卡,才能是網絡接通。OK~然後就是VM--->Removable Devices--->Network Adapter,選擇連接方式:Custom VMnet0(Bridged),完成保存。

2011年5月29日 星期日

[C++] 使用 random_shuffle() 算法隨機化序列元素

原連結: http://tc.wangchao.net.cn/bbs/detail_82440.html


    假設你需要指定範圍內的隨機數,傳統的方法是使用ANSI C的函數random(),然後格式化結果以便結果是落在指定的範圍內。但是,使用這個方法至少有兩個缺點。首先,做格式化時,結果常常是扭曲的,所以得不到正確的隨機數(如某些數的出現頻率要高于其它數)其次,random()只支持整型數;不能用它來産生隨機字符,浮點數,字符串或數據庫中的記錄。對于以上的兩個問題,C++中提供了更好的解決方法,那就是random_shuffle()算法。不要著急,下面我就會告訴你如何用這種算法來産生不同類型的隨機數。
    産生指定範圍內的隨機元素集的最佳方法是創建一個順序序列(也就是向量或者內置數組),在這個順序序列中含有指定範圍的所有值。例如,如何你需要産生100個0-99之間的數,那麽就創建一個向量並用100個按升序排列的數填充向量:
 
#include <vector>
using std::vector;
int main()
{
 vector<int> vi;
 for (int i = 0; i < 10; i++)
 vi.push_back(i); /*現在向量包含了 100 個 0-99 之間的整數並且按升序排列*/
}
    
    填充完向量之後,用random_shuffle()算法打亂元素排列順序。random_shuffle()定義在標准的頭文件<algorithm.h中。因爲
   所有的STL算法都是在名字空間std::中聲明的,所以你要注意正確地聲明數據類型。random_shuffle()有兩個參數,第一個參數是指向序列首元素的叠代器,第二個參數則指向序列最後一個元素的下一個位置。下列代碼段用random_shuffle()算法打亂了先前填充到向量中的元素: 

include <algorithm
using std::random_shuffle;
   
random_shuffle(vi.begin(), vi.end()); /* 打亂元素 */ 
   
如果你想檢查被打亂的元素,可以用如下方法看一下他們被打亂後存儲的次序: 
for (int i = 0; i < 100; i++)
    cout<<vi[i]; /* 顯示被打亂順序的元素 */
   
random_shuffle()是個完全通用的算法-適用于內建的數據類型和用戶自定義類型。下面的例子創建了一個有7個字符串對象的向量,它包含一周的天數並使用random_shuffle()打亂他們的排列順序:
 
#include <string>
#include <vector>
#include <algorithm>
#include <iostream>

using namespace std;
int main()
{
    vector<string> vs;
    vs.push_back(string ("Sunday"));
    vs.push_back (string ("Monday"));
    ...
    vs.push_back (string ("Saturday"));
    random_shuffle(vs.begin(), vs.end()); /* 打亂順序 */
    for (int i = 0; i << 7; i++){
     cout<<vs[i]; /* 顯示打亂順序後的元素 */
}

如何使用random_shuffle()處理內置數組,在使用容器代替內置數組時,你不要有什麽負擔。所有STL算法不僅適用于容器,也適用于序列。因此,你也能將random_shuffle()算法應用于內置數組。只是要注意random_shuffle()的第二個參數要指向數組上界的下一個元素位置:
 
char carr[4] = {'a', 'b', 'c', 'd'}; /*carr+4 指向數組上界的下一個元素位置*/
random_shuffle(carr, carr+4); 
for (int i = 0; i < 4; i++)
  cout<<carr[i]; /* 顯示被打亂順序的元素 */

2011年5月4日 星期三

[QT] convert a QString to char*

See the following example for a demonstration:
先將QString型態的字串,透過QByteArray將字串轉換成字元陣列。
int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    QString str1 = "Test";
    QByteArray ba = str1.toLocal8Bit();
    const char *c_str2 = ba.data();
    printf("str2: %s", c_str2);
    return app.exec();
}

2011年5月3日 星期二

[C++] #ifndef#define#endif的用法(整理)

[轉] #ifndef#define#endif的用法(整理)    原作者:icwk 
文件中的#ifndef
頭件的中的#ifndef,這是一個很關鍵的東西。比如你有兩個C文件,這兩個C文件都include了同一個頭文件。而編譯時,這兩個C文件要一同編譯成一個可運行文件,於是問題來了,大量的聲明衝突。
還是把頭文件的內容都放在#ifndef和#endif中吧。不管你的頭文件會不會被多個文件引用,你都要加上這個。一般格式是這樣的:
#ifndef <標識>
#define <標識>
......
......
#endif
<標識>在理論上來說可以是自由命名的,但每個頭文件的這個「標識」都應該是唯一的。標識的命名規則一般是頭文件名全大寫,前後加下劃線,並把文件名中的「.」也變成下劃線,如:stdio.h
#ifndef _STDIO_H_
#define _STDIO_H_
......
#endif
2.在#ifndef中定義變量出現的問題(一般不定義在#ifndef中)。
#ifndef AAA
#define AAA
...
int i;
...
#endif
裡面有一個變量定義
在vc中鏈接時就出現了i重複定義的錯誤,而在c中成功編譯。
結論:
(1).當你第一個使用這個頭的.cpp文件生成.obj的時候,int i 在裡面定義了當另外一個使用這個的.cpp再次[單獨]生成.obj的時候,int i 又被定義然後兩個obj被另外一個.cpp也include 這個頭的,連接在一起,就會出現重複定義.
(2).把源程序文件擴展名改成.c後,VC按照C語言的語法對源程序進行編譯,而不是C++。在C語言中,若是遇到多個int i,則自動認為其中一個是定義,其他的是聲明。
(3).C語言和C++語言連接結果不同,可能(猜測)時在進行編譯的時候,C++語言將全局
變量默認為強符號,所以連接出錯。C語言則依照是否初始化進行強弱的判斷的。(參考)
解決方法:
(1).把源程序文件擴展名改成.c。
(2).推薦解決方案:
.h中只聲明 extern int i;在.cpp中定義
<x.h>
#ifndef __X_H__
#define __X_H__
extern int i;
#endif //__X_H__
<x.c>
int i;
注意問題:
(1).變量一般不要定義在.h文件中。

-------------------------------------------------------------------------------------------------------------------------------------------
一般情況下,源程序中所有的行都參加編譯。但是有時希望對其中一部分內容只在滿足一定條件才進行編譯,也就是對一部分內容指定編譯的條件,這就是「條件編譯」。有時,希望當滿足某條件時對一組語句進行編譯,而當條件不滿足時則編譯另一組語句。
條件編譯命令最常見的形式為:
    #ifdef 標識符
    程序段1
    #else
    程序段2
    #endif
   
    它的作用是:當標識符已經被定義過(一般是用#define命令定義),則對程序段1進行編譯,否則編譯程序段2。
    其中#else部分也可以沒有,即:
    #ifdef
    程序段1
    #denif
   
    這裡的「程序段」可以是語句組,也可以是命令行。這種條件編譯可以提高C源程序的通用性。如果一個C源程序在不同計算機系統上系統上運行,而不同的計算機 又有一定的差異。例如,我們有一個數據類型,在Windows平台中,應該使用long類型表示,而在其他平台應該使用float表示,這樣往往需要對源 程序作必要的修改,這就降低了程序的通用性。可以用以下的條件編譯:
    #ifdef WINDOWS
    #define MYTYPE long
    #else
    #define MYTYPE float
    #endif
   
    如果在Windows上編譯程序,則可以在程序的開始加上
    #define WINDOWS
   
    這樣則編譯下面的命令行:
    #define MYTYPE long
   
    如果在這組條件編譯命令之前曾出現以下命令行:
    #define WINDOWS 0
   
    則預編譯後程序中的MYTYPE都用float代替。這樣,源程序可以不必作任何修改就可以用於不同類型的計算機系統。當然以上介紹的只是一種簡單的情況,可以根據此思路設計出其它的條件編譯。
    例如,在調試程序時,常常希望輸出一些所需的信息,而在調試完成後不再輸出這些信息。可以在源程序中插入以下的條件編譯段:
    #ifdef DEBUG
    print ("device_open(%p) ", file);
    #endif
   
    如果在它的前面有以下命令行:
    #define DEBUG
   
    則在程序運行時輸出file指針的值,以便調試分析。調試完成後只需將這個define命令行刪除即可。有人可能覺得不用條件編譯也可達此目的,即在調試 時加一批printf語句,調試後一一將printf語句刪除去。的確,這是可以的。但是,當調試時加的printf語句比較多時,修改的工作量是很大 的。用條件編譯,則不必一一刪改printf語句,只需刪除前面的一條「#define DEBUG」命令即可,這時所有的用DEBUG作標識符的條件編譯段都使其中的printf語句不起作用,即起統一控制的作用,如同一個「開關」一樣。
    有時也採用下面的形式:
    #ifndef 標識符
    程序段1
    #else
    程序段2
    #endif
   
    只是第一行與第一種形式不同:將「ifdef」改為「ifndef」。它的作用是:若標識符未被定義則編譯程序段1,否則編譯程序段2。這種形式與第一種形式的作用相反。
    以上兩種形式用法差不多,根據需要任選一種,視方便而定。
    還有一種形式,就是#if後面的是一個表達式,而不是一個簡單的標識符:
    #if 表達式
    程序段1
    #else
    程序段2
    #endif
   
    它的作用是:當指定的表達式值為真(非零)時就編譯程序段1,否則編譯程序段2。可以事先給定一定條件,使程序在不同的條件下執行不同的功能。
---------------------------------------------------------------------------------------------------------------------------------------
作用範圍就是當前文件啊。因為編譯是以cpp或c文件位單位的嘛。還以這個為例:

//正常代碼
#ifdef _DEBUG
     TRACE("Some infomation");
#else
     //Now is release version,so do nothing
#endif
//正常代碼

編譯時是先把所有的預編譯處理展開(比如宏)再編譯,所以Debug模式下,編譯時的代碼是:
//正常代碼
TRACE("Some infomation");
//正常代碼

Release模式下的代碼是:
//正常代碼
//正常代碼

2011年5月2日 星期一

[QT] How to covert QT QImage into OpenCV IplImage and vise-versa.

IplImage* QImage2IplImage(QImage *qimg)
{
    IplImage *imgHeader = cvCreateImageHeader( cvSize(qimg->width(), qimg->height()), IPL_DEPTH_8U, 4);
    imgHeader->imageData = (char*) qimg->bits();
    uchar* newdata = (uchar*) malloc(sizeof(uchar) * qimg->byteCount());
    memcpy(newdata, qimg->bits(), qimg->byteCount());
    imgHeader->imageData = (char*) newdata;
    //cvClo
    return imgHeader;
}
//---
QImage*  IplImage2QImage(IplImage *iplImg)
{
    int h = iplImg->height;
    int w = iplImg->width;
    int channels = iplImg->nChannels;
    QImage *qimg = new QImage(w, h, QImage::Format_ARGB32);
    char *data = iplImg->imageData;
    for (int y = 0; y < h; y++, data += iplImg->widthStep)
    {
        for (int x = 0; x < w; x++)
        {
            char r, g, b, a = 0;
            if (channels == 1)
            {
                r = data[x * channels];
               g = data[x * channels];
               b = data[x * channels];
            }
           else if (channels == 3 || channels == 4)
           {
               r = data[x * channels + 2];
               g = data[x * channels + 1];
               b = data[x * channels];
           }
            if (channels == 4)
            {
                a = data[x * channels + 3];
                qimg->setPixel(x, y, qRgba(r, g, b, a));
            }
            else
            {
                qimg->setPixel(x, y, qRgb(r, g, b));
            }
        }
    }
    return qimg;
}

2011年4月16日 星期六

[OpenCV] cvSobel

//拿到一張圖,可以先做個訊號過濾 太低的拿掉

double dou;
double threshold=110;
double maxvalue=255;
dou=cvThreshold(img,img,threshold,maxvalue,CV_THRESH_TOZERO);

//接著轉灰階,後開始找邊緣 用sobel 可以調兩個方向的階數。 

cvCvtColor(img,gray,CV_RGB2GRAY); 

IplImage *gray16u=cvCreateImage(cvGetSize(gray),IPL_DEPTH_16S,1); 
cvSobel(gray,gray16u,1,0,3);   
//如果輸入的是8位元的說,輸出防止溢出的現象 //所以開16位元的給它存

cvConvertScaleAbs(gray16u,gray,1,0); 
 //這個是再把16位元的縮回8位元的指令 //也可以用cvConvertScale

cvShowImage( "Example1", gray );
cvWaitKey(0);