promotion image of download ymail app
Promoted

新手疑問 DEV C++ 函數與矩陣的問題

想請問可否讓函數的傳回型別是一個矩陣

像是

int[] abc(){~}

我這樣寫不行 是要用其他寫法嗎?

如果不行的話 要如何讓函數宣告一個公用的矩陣?

像是

void abc(){

int def[5];}

然後讓其他地方也能用到def[]

我有試過public 不過好像沒有這個字 那要如何解決呢?

總之就是要經由一個函數 製造出一個矩陣 使其他地方使用

這樣要如何寫呢?

4 Answers

Rating
  • 卸貨
    Lv 5
    6 years ago
    Favorite Answer

    C 函式如何傳回陣列,似乎是很多中學者會思考到的問題(初學者因該還碰不到)。

    對於這樣的問題,以下整理六個 C 函式如何傳回陣列的方式,其中包含一些不可行但很直覺的方法:

    1. 直接傳回局部陣列,例如:

    int* func(...)

    {

    int arr[3];

    ...

    return arr;

    }

    這個做法是很多中學者第一個想到的方法,但陷阱在於 arr 離開函式後就失效了。可是基於 C 語言追求效率的關係,失效的變數內容沒必要不會被複寫,於是有些時候這個方法恰巧沒問題,就會讓可憐的中學者相信這是可以用的,直到有一天他遇到莫名其妙的程式異常為止…

    2. 傳回局部的靜態陣列,例如:

    int* func(...)

    {

    static int arr[3];

    ...

    return arr;

    }

    有鑑於第1種做法的最大問題是函式內變入離開函式就失效,於是第二種做法就是指派一個不會失效的陣列。這種做法可以正常運作,實際上也有應用,不過很不被推荐在一般的狀況下使用他。這種做法最大的問題是所有使用這函式的地方接收到的其實是同一個變數,彼此會互相干擾,比方說:

    char* foo(int)

    {

    static char res[12];

    snprintf(res, sizeof(res), "input is %d", int);

    return res;

    }

    int main(void)

    {

    char *str3 = foo(3);

    char *str5 = foo(5);

    char *str7 = foo(7);

    printf(str3);

    printf(str5);

    printf(str7);

    return 0;

    }

    看出來上面程式的問題了嗎?各個看似沒有關聯的變數其實是互相干擾的,這些問題在多執行緒的應用上會更為明顯。

    3. 全域變數

    這種做法和第二種做法原理上是一模一樣的,事實上函式靜態變數就是全域變數,只是編譯器幫你過慮了可見性的部份。範例

    int arr[3];

    void func(...){.../*modifying global arr*/...}

    這種利用全域變數交換資料的做法不知位什麼中華人超愛用的,然而實際上這樣的做法比使用靜態變數更不被建議使用。

    這種做法最大的問題在於程式追蹤困難。當我們看到一個函式被呼叫,我怎麼知道他到底參考了哪先資料?又到底去改了哪些資料?我必須要不斷深入他的程式碼才能理解。要知道實際上的程式碼不會只有一個 arr、不會只有一個函式、程式碼更不會只有十行。以我在業見的經驗,全域變數是我們程式人最討厭看到的前己名,偏偏很多人又討厭看全域變數又喜歡寫全域變數。

    然而全域變數/靜態變數也不是完全不可取,這種做法被推荐使用,也是唯一被推荐使用的時機只有一個,就是當你要傳回的東西是個「常數」的時候,例如:

    const char* get_month_name(int month)

    {

    switch( month )

    {

    case 1: return "January";

    case 2: return "February";

    ....

    default: return "Unknown";

    }

    }

    4. 動態建立陣列

    實際上真正建議被使用的一種做法就是動態建立一個陣列傳回去,像是:

    char* foo(int)

    {

    char *res = malloc(100);

    snprintf(res, 100, "input is %d", int);

    return res;

    }

    事實上這種做法經常被使用,特別在 C++ 這種有類別物件管理機制的程式語言下更好用(不過要包在 class 裡,其實和後面的方法比較像)。沒有變數干擾的問題,也沒有長度限制的問題;缺點就是動態建立的緩衝區需要在不使用的時候呼叫 free 去釋放他,加重了使用者的負擔。實際上很多使用者往往搞不清楚傳回來的東西是不是需要被釋放(因為從函式宣告上不容易看出,若再加上文件寫不全的話…)。

    5. 資料結構包裝

    C 函式雖然不能從傳回值傳回陣列,但可以傳回一個結構,於是把陣列包在結構裡又成為一種很實用的做法,例如:

    struct name_t

    {

    char str[100];

    };

    name_t get_name_from_id(int id){...}

    這樣的做法很直覺方便,也省去了記憶體管理上的問題。缺點就是有些效率上的落失(C 程式人很重視效率的),以及若缺乏良好的程式規劃的話,你會擁有一堆分不清何用的 structure。

    2014-09-29 12:42:33 補充:

    6. 經由函式參數傳入傳出陣列

    雖然函式參數只能用來傳入,但若我們傳入一個記憶體位址(也就是指標),函式就可以照者這個地址去修改某一段資料,比方說:

    void memory_copy(uint8_t *dest, const uint8_t *src, size_t size)

    {

    size_t i;

    for(i=0; i

    2014-09-29 12:43:13 補充:

    6. 經由函式參數傳入傳出陣列

    雖然函式參數只能用來傳入,但若我們傳入一個記憶體位址(也就是指標),函式就可以照者這個地址去修改某一段資料,比方說:

    void memory_copy(uint8_t *dest, const uint8_t *src, size_t size)

    {

    size_t i;

    for(i=0; i < size; ++i) dest[i] = src[i];

    }

    這種做法的好處是函式不用去管記憶體管理的問題,把相關的問題丟給使用者去處理;而使用者一看到函式宣告也會明白自己應該要傳入一個可用的陣列。

    缺點就是函式的參數變多了,

    2014-09-29 12:43:44 補充:

    一般需要傳入陣列指標、及一個用來標示陣列大小的整數、甚至還有一個用來傳回函式寫了多少資料到陣列裡的整數。另一個缺點就是,若缺乏良好的引導或說明的話,使用者往往不知要先建立一個多大的空間才好。

    以上整理了六種方法,其中 靜態/全域 除常數以外不被推荐,只有後三種是實際上常用的,事實上最後一種做法被大量應用在各種底層函式庫和標準函式庫,比如說 memcpy, strncpy 等等。

    • Commenter avatarLogin to reply the answers
  • Anonymous
    6 years ago

    這里很不錯999shopping。com老婆很喜歡

    哵卑刑

    • Commenter avatarLogin to reply the answers
  • 阿平
    Lv 4
    6 years ago

    你可以用malloc配置記憶體,然後回傳指標。

    http://openhome.cc/Gossip/CGossip/MallocFree.html

    • Commenter avatarLogin to reply the answers
  • ㄚ旺
    Lv 5
    6 years ago

    全域變數嗎?有點看不懂你問的問題.

    若是使用函數.可以在宣告前面加上靜態宣告

    static int v[5];

    • Commenter avatarLogin to reply the answers
Still have questions? Get your answers by asking now.