查看完整版本: (已解決) 有關二微陣列呼叫函式取值的方法
頁: [1]

baepi 發表於 2016-5-1 09:41 PM

(已解決) 有關二微陣列呼叫函式取值的方法

本帖最後由 snowflying 於 2016-5-7 12:26 AM 編輯

或許只看標題不明小弟何意...在此請允許小弟用一維陣列舉個例子
void test(char **t)
{
        char aa[] = "Hello";
        *t = aa;

//        *t = "123";
}

void main()
{
        char *str = NULL;
        test(&str);
        cout<<str<<endl;
}像上述例子....無論test函式是使用非註解的程式碼還是註解的程式碼~回到主程式後...指標都可以正確的輸出期望的字串
但是若是今天想做的是多字串....數量與長度都不明的情況下~那自然只能使用char **str
只是小弟實驗許久...仍然找尋不到方法~可否請版上高手教學{:38:}
...<div class='locked'><em>瀏覽完整內容,請先 <a href='member.php?mod=register'>註冊</a> 或 <a href='javascript:;' onclick="lsSubmit()">登入會員</a></em></div><div></div>

NTUKing 發表於 2016-5-2 12:08 AM

本帖最後由 NTUKing 於 2016-5-2 12:11 AM 編輯

簡單來說就是, private的變數, 一離開static void, 就會隨之消滅,
除非宣告static型態 但也不好, 會造成ram資料有一堆垃圾,
那原先指定給*str的heap, 就有機會被系統釋放, 給其他資源使用,
因此就會出現輸出資料不是你設定的資料,

建議將欲處理的資料放在global比較好, 而且經編譯後直接進stack,
這就保證可以確認資料不會有異常, 而heap中如果有其他堆疊, 有機率會產生垃圾資料,

舉例:
您的程式碼, 可以改為aa={0}; 並將aa放到global
void test中, 再把資料堆進aa[], 再將指標指向aa,
這個解法應該會是比較不會有其他問題




...<div class='locked'><em>瀏覽完整內容,請先 <a href='member.php?mod=register'>註冊</a> 或 <a href='javascript:;' onclick="lsSubmit()">登入會員</a></em></div>

baepi 發表於 2016-5-2 01:04 AM

NTUKing 發表於 2016-5-2 12:08 AM static/image/common/back.gif
簡單來說就是, private的變數, 一離開static void, 就會隨之消滅,
除非宣告static型態 但也不好, 會造成ra ...

不知道是大大誤解我的問題還是我不明白大大說的
我在主題舉的例子是可以成功運作的...我相信大大說的會有機會被系統釋放...但是當下能成功動作~我即會把資料做處理....如果這樣還是有機會在我未處理時就被釋放....恩~沒關係~因為我現在想的是二維陣列
目前我想過用return和指標這兩種方法....return這方法我是完全不知如何下手....所以才想說用指標這方法...不過既然一維陣列就有大大說的問題....那我相信二維應該也逃不過此命運

只是....二維陣列就算先在全域變數設定一個二維陣列....以下是我胡思亂想下的 "慘"物char **buffer;

void test(char **a)
{
  //先在這創buffer動態記憶體
  //再來我就不知道怎麼寫了
}

void main()
{
  char **t;
  test(t);  //把buffer資料到手
}...<div class='locked'><em>瀏覽完整內容,請先 <a href='member.php?mod=register'>註冊</a> 或 <a href='javascript:;' onclick="lsSubmit()">登入會員</a></em></div>

snowflying 發表於 2016-5-2 02:40 AM

其實我還是看不懂問題
剛誤解了一次意思,所以自行刪掉回覆了

不能在
void test(char ***str)
裡面動態配置二維陣列嗎?
可能再外加個 cleanup 程序

或者是使用 string,甚至是 vector<string>
看你用 cout,應該是 C++
C++ 有提供方便的容器可以使用

baepi 發表於 2016-5-2 10:36 AM

snowflying 發表於 2016-5-2 02:40 AM static/image/common/back.gif
其實我還是看不懂問題
剛誤解了一次意思,所以自行刪掉回覆了



大大是說像這樣嗎?void test(char ***str)
{
  *str = new char *;
  for(int i = 0 ; i < 10 ; i++)
  {
     *str = new char;
     for(int j = 0 ; j < 3 ; j++)
     {
        *str = 48 + j;
        cout<<*str<<endl;
     }
  }
}是的~我老早嘗試過了...只是看到大大留言後我又再嘗試一次~但依舊失敗了.....還是說我寫錯了??...<div class='locked'><em>瀏覽完整內容,請先 <a href='member.php?mod=register'>註冊</a> 或 <a href='javascript:;' onclick="lsSubmit()">登入會員</a></em></div><br><br><br><br><br><div></div>

baepi 發表於 2016-5-2 11:24 AM

本帖最後由 baepi 於 2016-5-2 11:39 AM 編輯


void test(char ***str)
{

        char **t1 = new char *;
        char *t2 = new char ;
        for(int i = 0 ; i < 5 ; i++ , t2 += 10)
        {
                t1 = t2;
                sprintf_s(t1 , 9 , "TEST%d" , i);
        }
        *str = t1;
}

void main()
{
        char **aa = NULL;
        test(&aa);
        for(int i = 0 ; i < 5 ; i++)
        {
                cout<<aa<<endl;
        }
        delete [] aa;
        delete[] aa;
}

這是剛才死馬當活馬醫的情況下測試出來的....結果居然成功了~原來....動態記憶體不能自己創??
要全程用別的指標創完後....最後再把自己的指標指向該指標即可....不知道我這樣說明對不對...
另外....這寫法雖然可以正常運作(就我目前測試的情況下正常)...但會不會有甚麼隱憂....可能就要請高人解答說明了
話說重新編輯程式碼怎麼會一直怪怪的....害要我重新包一次
...<div class='locked'><em>瀏覽完整內容,請先 <a href='member.php?mod=register'>註冊</a> 或 <a href='javascript:;' onclick="lsSubmit()">登入會員</a></em></div>

inunu 發表於 2016-5-2 12:22 PM

你的問題出在 operator 的優先順序上
*str 這種型式基於優先順序的關係需要用 (*str)
後來的版本沒問題是因為避掉了這種用法


void test(char ***str)
{
  *str = new char *;
  for(int i = 0 ; i < 10 ; i++)
  {
     (*str) = new char;
     for(int j = 0 ; j < 9 ; j++)
     {
        (*str) = 48 + j;
        cout << (*str) << endl;
     }
  }
}

a333221 發表於 2016-5-2 09:17 PM

baepi 發表於 2016-5-2 11:24 AM static/image/common/back.gif
這是剛才死馬當活馬醫的情況下測試出來的....結果居然成功了~原來....動態記憶體不能自己創??
要全程用別 ...

你一開始提到「數量與長度都不明的情況下」,

可是你給的 code 是「數量與長度都固定的情況」,

就你的 code 或者說就你的問題來說,既然你假設「數量與長度都不明」,

可以的話,針對你這份 code,

將 test 改成 void test(char ***str, int *elementNumr, int *capacity)

讓 test 的呼叫者可以知道 str 的「數量與長度是多少」,

還有,這問題你函數內的多字串真實的樣子是長怎樣,先知道你原始字串的長相,

再來想該如何把資料取出來。

...<div class='locked'><em>瀏覽完整內容,請先 <a href='member.php?mod=register'>註冊</a> 或 <a href='javascript:;' onclick="lsSubmit()">登入會員</a></em></div>

baepi 發表於 2016-5-2 10:44 PM

a333221 發表於 2016-5-2 09:17 PM static/image/common/back.gif
你一開始提到「數量與長度都不明的情況下」,

可是你給的 code 是「數量與長度都固定的情況」,


感謝大大提醒
其實這問題的應用背後我原本的做法就是打算用動態記憶體去調度...只是當時我忘了*str和 (*str)的不同(已經重複在類似問題吃好多次悶虧了)...所以轉而想說直接使用函式內的字串陣列....之後NTUKing大大說有被釋放的隱憂
之後又輾轉的測試終於在動態記憶體這方法下成功了...既然這問題的最難解之處已經解開~我也就沒在此深究最完整的答案了....畢竟接下來對我來說並沒其他問題了

不過要說完整性~那麼在此請允許用舉例的方式寫個文字流程便可吧
假設我們要做一個切割字串的功能....第一個參數是放準備要被切割的字串
第二個參數放遇到怎樣的字串要被切割
第三個字串則放被切割完的字串
第四個為總共被切成幾分....在此看成高度
第五為最大字串長度...寬度
那麼大概就長的像以下這樣
void test( char *source_str , char *cut_str , char ***str , int &h , int &w )
{
假設都能切割正確....那麼在此函式運作時...他一定可以知道(*str)的值...所以在之前的舉例才用定值....畢竟當時是在測試
然後最好在最前端或是例外狀況無產生動態記憶體時宣告 *str = NULL;
這樣亦可防檢查疏忽時造成錯誤
}
void main()
{
  int h , w;
  char *s"123##4567";
  char **buf;
  void test(s , "#" , buf , h , w);

至於使用完後delete的方法就端看使用者如何宣告那二微陣列了
}
...<div class='locked'><em>瀏覽完整內容,請先 <a href='member.php?mod=register'>註冊</a> 或 <a href='javascript:;' onclick="lsSubmit()">登入會員</a></em></div>

NTUKing 發表於 2016-5-3 12:45 AM

本帖最後由 NTUKing 於 2016-5-3 08:29 AM 編輯

char** ptr這種雙指標不是容易出錯嗎?
為何不用structure point?
舉例說明:
struct A中包一個char* ptr
再將A* pch;
這樣的架構是否比較有組織?
<br><br><br><br><br><div></div>

NTUKing 發表於 2016-5-3 08:28 AM

本帖最後由 NTUKing 於 2016-5-3 08:30 AM 編輯

baepi 發表於 2016-5-2 01:04 AM static/image/common/back.gif
不知道是大大誤解我的問題還是我不明白大大說的
我在主題舉的例子是可以成功運作的...我相信大大說的會有 ...
我想我解釋的可能沒很好

因為你的char aa[] = "Hello";已經固定了
即使沒有加上static, 他經過編譯後已進stack
所以當然會成功
如果用外部傳直進去改寫, 再改寫外部傳址, 就有機會失敗阿!
這樣有瞭解嗎?...<div class='locked'><em>瀏覽完整內容,請先 <a href='member.php?mod=register'>註冊</a> 或 <a href='javascript:;' onclick="lsSubmit()">登入會員</a></em></div>

a333221 發表於 2016-5-4 10:45 PM

baepi 發表於 2016-5-2 10:44 PM static/image/common/back.gif
感謝大大提醒
其實這問題的應用背後我原本的做法就是打算用動態記憶體去調度...只是當時我忘了*str和  ...

所以,關於你之前提到的

       「動態記憶體不能自己創??要全程用別的指標創完後....最後再把自己的指標指向該指標即可....不知道我這樣說明對不對...」

這句你還有疑問嗎?

另外,關於「我也就沒在此深究最完整的答案了」這句,個人看法,很多時候,

code 的寫法會隨著你要處理的數據不同,而採用不同的做法,

未必有什麼方法就是最完整的。...<div class='locked'><em>瀏覽完整內容,請先 <a href='member.php?mod=register'>註冊</a> 或 <a href='javascript:;' onclick="lsSubmit()">登入會員</a></em></div>

ren1244 發表於 2016-5-5 04:05 PM

寫了一個函數提供參考
因為樓主的做法很有C語言的style
所以我就用C語言來寫了…/*
char** StrSplit(const char* src,const char* sep,int *num)
函數說明:
        以sep為關鍵字,將src分割為子字串。
引數:
        src:要被切割的字串
        sep:視為分割符號的字串
        num:儲存分割完後共有幾筆資料
回傳值:
        char**指標(指向動態宣告位址),或是NULL(src是空字串時)
        ※使用後需要釋放記憶體
*/
char** StrSplit(const char* src,const char* sep,int *num)
{
        int srcL,sepL,n,i;
        char *p,**pp;
        const char *t,*q;
        *num=0;
        if((srcL=strlen(src))==0)
                return NULL;
        if(sep==NULL || (sepL=strlen(sep))==0)
        {
                pp=(char**)malloc(srcL+sizeof(char*));
                pp=(char*)(pp+1);
                strcpy(pp,src);
                return pp;
        }
        //計算所需空間
        n=0;
        for(t=src;(t=strstr(t,sep))!=NULL;t+=sepL)
                ++n;
        pp=(char**)malloc(srcL-(sepL-1)*n+1+sizeof(char*)*(n+1));
        //寫入數值
        *num=n+1;
        i=0;
        p=(char*)(pp+n+1);
        for(t=src;(q=strstr(t,sep))!=NULL;t=q+sepL)
        {
                pp=p;
                memcpy(p,t,n=q-t);
                p+=n;
                *(p++)='\0';
        }
        pp=p;
        strcpy(p,t);
        return pp;
}...<div class='locked'><em>瀏覽完整內容,請先 <a href='member.php?mod=register'>註冊</a> 或 <a href='javascript:;' onclick="lsSubmit()">登入會員</a></em></div>

baepi 發表於 2016-5-5 08:08 PM

本帖最後由 baepi 於 2016-5-5 08:09 PM 編輯

ren1244 發表於 2016-5-5 04:05 PM static/image/common/back.gif
寫了一個函數提供參考
因為樓主的做法很有C語言的style
所以我就用C語言來寫了… ...
看來我在六樓時就應該在標題打上已解決...就不用再麻煩各路高手想要幫我解惑
原本只是為了解釋我發問的答案可以做哪些應用....沒想到引出像大大這樣連創2D陣列都精密計算的高手

其實我舉例字串切割時....雖只是用文字敘述~但是程式碼早已打好~但因為不想把檢查例外除錯碼左砍右砍...但如今看到大大這份程式碼~更是不好自曝其短....畢竟我取的陣列是取深度與最大寬度...而非像大大這樣精細的計算
畢竟我把創2D記憶體的功能額外拉出...不用每次做類似運用時都要再寫一次創造2D陣列(所以才說是抓深度與最大寬度)
程式碼在以下.....可以創造各種不同2D記憶體....除了bool.....畢竟他的sizeof跟char一樣都是1...但實際上他小的多....#define NEW_2D( h , w , type ) (type**)new_2d( h , w , sizeof(type) )

void* new_2d(int h, int w, int type)
{
    void **_temp = (void**)new char[ ( h * sizeof(void*) ) + (h * w * type) ];
    for(int i = 0 ; i < h ; i++)
    {
        _temp = ((char *)(_temp + h)) + ( i * w * type );
    }
        return _temp;
}

//example
char**data;
data = NEW_2D( 5 , 10 , char);
delete [] data;...<div class='locked'><em>瀏覽完整內容,請先 <a href='member.php?mod=register'>註冊</a> 或 <a href='javascript:;' onclick="lsSubmit()">登入會員</a></em></div>
頁: [1]