主頁 > .NET開發 > 在二維陣列上使用函式

在二維陣列上使用函式

2022-01-09 06:44:44 .NET開發

我撰寫了代碼,允許我通過傳遞陣列的元素來修改函式內的一維陣列的元素:

  • 我列印原始陣列
  • 我將陣列的每個元素傳遞給函式
  • 在函式中,我將值 50 添加到陣列的每個元素
  • 然后我呼叫該函式,并列印出來以篩選修改后的元素值(即每個元素的值 50)

我已經能夠為一維陣列執行此操作,陣列中的示例值為(10,20,30),修改后列印的值為(60,70,80)。

我希望做的是使該代碼適用于二維陣列,您將在下面看到我這樣做的嘗試。這段代碼側重于 int 的使用,但一旦我了解了如何實作這一點,我希望也能適應二維字串的使用。

使用以下代碼:

我的目標是

  1. 列印以篩選原始二維陣列
  2. 將二維陣列的每個元素傳遞給函式
  3. 在函式內將值 50 添加到陣列的每個元素
  4. 然后呼叫該函式,將修改后的元素值列印到螢屏上(預期結果顯示在螢屏60、61等)。到目前為止,我已經能夠將原始二維陣列列印到螢屏上。這是我認為我搞砸的功能,并希望得到任何建議。謝謝你。
#include <stdio.h>
#include <string.h>

#define M 4
#define N 2

int function(int **arr);

int main() {
    int i, a;
    int arr[N][M] = {10, 11, 12, 13, 14, 15, 16, 17};

    // the int array first

    for(i = 0; i < N; i  ) {
        for(size_t j = 0; j < M; j  ) {
            // Accessing each variable
            printf("value of arr[%d] is %d\n", i, arr[i][j]);
        }
    }

    printf("\n    ***values after modification***\n");

    a = function(&arr[i][0]);

    // int array print results
    for(int i = 0; i < N; i  ) {
        for(size_t j = 0; j < M; j  ) {
            printf("value of arr %d\n", arr[i][j]);
        }
    }

    return 0;
}

int function(int **arr) {
    int i;
    int j;

    for(int i = 0; i < 3; i  ) {
        for(size_t j = 0; j < 5; j  ) {
            arr[i][j] = arr[i][j]   50;
        }
    }
}

對于愚蠢的錯誤,我提前道歉我對 C 很陌生。提前謝謝你。

uj5u.com熱心網友回復:

  • 該函式int function(int **arr)不回傳一個intso make it void
  • 當你呼叫它時a = function(&arr[i][0]);,你不會a在賦值后使用我建議您a完全從程式中洗掉,因為它沒有在任何地方使用。
  • 對函式 的呼叫function(&arr[i][0]);應該是function(arr);
  • 函式簽名需要包括除最外層之外的所有維度:
    void function(int arr[][M])
    
  • 在函式內部,您使用3and5而不是Nand M這會越界訪問陣列。
  • 在 中function您在函式開頭宣告iandj未使用。洗掉它們。
  • arr[i][j] = arr[i][j] 50; 最好寫成 arr[i][j] = 50;
  • 初始化多維陣列時,使用大括號使代碼更容易閱讀:
    int arr[N][M] = {{10, 11, 12, 13}, {14, 15, 16, 17}};
    
  • main你混合intsize_t索引變數。我建議你滿足于一種型別。
  • 洗掉未使用的頭檔案 ( string.h)

例子:

#include <stdio.h>

#define N 2
#define M 4

void function(int arr[][M]) {
    for(int i = 0; i < N; i  ) {
        for(size_t j = 0; j < M; j  ) {
            arr[i][j]  = 50;
        }
    }
}

int main() {
    int arr[N][M] = {{10, 11, 12, 13}, {14, 15, 16, 17}};

    for(size_t i = 0; i < N; i  ) {
        for(size_t j = 0; j < M; j  ) {
            printf("value of arr[%zu][%zu] is %d\n", i, j, arr[i][j]);
        }
    }

    printf("\n    ***values after modification***\n");

    function(arr);

    // int array print results
    for(size_t i = 0; i < N; i  ) {
        for(size_t j = 0; j < M; j  ) {
            printf("value of arr[%zu][%zu] is %d\n", i, j, arr[i][j]);
        }
    }
}

由于您多次列印陣列,您還可以添加一個函式來這樣做,而不必在main以下代碼中重復該代碼

void print(int arr[][M]) {
    for(size_t i = 0; i < N; i  ) {
        for(size_t j = 0; j < M; j  ) {
            printf("value of arr[%zu][%zu] is %d\n", i, j, arr[i][j]);
        }
    }
}

uj5u.com熱心網友回復:

C(和 C )中的二維陣列實際上是一維陣列,其元素是一維陣列。索引運算子 [] 具有從左到右的語意,因此對于一個型別arr[N][M],首先評估第一個索引(具有 N 個元素)。結果運算式,例如arr[0]中的第一個元素arr,是一個具有 M 個元素的一維陣列。當然,該陣列可以再次被索引,例如arr[0][1],導致第一個子陣列中的第二個 int 。

C 語言的一個怪癖是,如果使用陣列作為函式引數,函式看到的是指向第一個元素的指標。用作引數的陣列“衰減”,或者如標準所說,以這種方式“調整”。這與二維陣列沒有什么不同,只是二維陣列的元素本身就是陣列。因此,接收函式得到的是一個指向int arr[M].

考慮:如果你想傳遞一個簡單的整數陣列,比如說intArr[3],給一個函式,函式看到的是一個指向第一個元素的指標。這樣的函式宣告可能看起來像void f(int *intPtr),對于這個例子,簡單地用f(intArr). 另一種撰寫方式是void f(int intPtr[]). 它的含義完全相同:引數是指向 int 的指標,而不是陣列。它指向一連串整數中的第一個(甚至可能是唯一一個)元素。

二維陣列的邏輯完全相同——除了所討論的元素具有“M 個整數陣列”型別,例如int subArr[M]. 這種型別的指標引數可以用兩種方式撰寫,就像簡單的 int 陣列一樣:作為指標,void f(int (*subArrPtr)[M])或者以陣串列示法,頂層元素的數量未知,比如void f(int arr[][M]). 與簡單的 int 陣列一樣,這兩個引數符號完全等效且可互換。兩者實際上都宣告了一個指標,(*subArrPtr)[M]可以這么說,更切中要害(呃),但可能更晦澀難懂。

有趣的括號的原因(*subArrPtr)是我們必須首先取消參考指標才能獲得實際的陣列,然后才索引它。如果沒有括號,索引運算子[]將具有優先權。您可以在此表中查找優先級[]在第 1 組中具有最高優先級,而取消參考運算子*(不是乘法!)在第 2 組中。如果沒有括號,我們將首先索引,然后才取消參考陣列元素(因此必須是指標),也就是說,我們將宣告一個指標陣列而不是指向陣列的指標。

因此,您的函式的兩個可能的、可互換的簽名是

void function( int (*arrArg)[M] ); // pointer notation
void function( int arrArg[][M]  ); // "array" notation (but actually a pointer)

整個程式,也糾正了 Ted 提到的問題,并且沒有列印原始值(畢竟我們知道它們),如下所示。我還調整了二維陣列的初始化,以便子陣列變得可見。C 對初始化結構和陣列非常寬松;它只是讓您撰寫連續的值并隨時間填充嵌套子物件的元素。但我認為顯示結構有助于理解代碼并揭示錯誤,例如子陣列中的元素數量錯誤。我以一種方式宣告了該函式,并以另一種方式定義了它,以表明函式簽名是等效的。我還更改了定義和函式的名稱以賦予它們更多含義。

#include<stdio.h>

#define NUM_ELEMS_SUBARRAY 4
#define NUM_ELEMS_ARRAY 2

/// @arrArg Is a pointer to the first in a row of one-dimensional
/// arrays with NUM_ELEMS_SUBARRAY ints each.
void add50ToElems(int arrArg[][NUM_ELEMS_SUBARRAY]);

int main()
{
    // Show the nested structure of the 2-dimensional array.
    int arr[NUM_ELEMS_ARRAY][NUM_ELEMS_SUBARRAY] = 
    { 
        {10, 11, 12, 13}, 
        {14, 15, 16, 17} 
    };
                    
    // Modify the array             
    add50ToElems(arr);

    // print results
    for (int i = 0; i < NUM_ELEMS_ARRAY; i  ) {
        for (int j = 0; j < NUM_ELEMS_SUBARRAY; j  )
        {
            printf("value of arr[%d][%d]: %d\n", i, j, arr[i][j]);
        }
    }

    return 0;
}

// Equivalent to declaration above
void add50ToElems(int (*arrArg)[NUM_ELEMS_SUBARRAY])
{
    for (int i = 0; i < NUM_ELEMS_ARRAY; i  )
    {
        for (size_t j = 0; j < NUM_ELEMS_SUBARRAY; j  )
        {
            //arrArg[i][j] = arrArg[i][j]   50;
            arrArg[i][j]  = 50;  // more idiomatic
        }
    }
}

為什么將二維陣列傳遞給期望指標的函式是錯誤的?讓我們考慮一下什么void f(int *p)意思。它接收一個指向 int 的指標,該指標通常是陣列的開頭,即在記憶體中一個接一個地放置的一系列 int 的開頭。例如

void f(int *p) { for(int i=0; i<3;   i) { printf("%d ", p[i]); }

可以用指向陣列第一個元素的指標呼叫:

static int arr[3];
void g() { f(arr); }

當然,這個最小的例子是不安全的(怎么f知道有三個整數?)但它可以達到目的。

那么這void f(int **p);意味著什么?類似地它是一個指標,指向該第一中的連續指標其在存盤器躺在一個接一個。我們已經知道為什么如果我們傳遞二維陣列的地址會造成災難:那里的物件不是指標,而是所有整數!考慮:

int arr1[2] = { 1,2 }; 
int arr2[2] = { 2,3 }; 
int arr3[2] = { 3,4 }; 

// This array contains addresses which point 
// to the first element in each of the above arrays.
int  *arrOfPtrToStartOfArrays[3] // The array of pointers
        = { arr1, arr2, arr3 }; // arrays decay to pointers
        
int **ptrToArrOfPtrs = arrOfPtrToStartOfArrays;

void f(int **pp)
{
    for(int pi=0; pi<3; pi  ) // iterate the pointers in the array
    {
        int *p = pp[pi]; // pp element is a pointer
        
        // iterate through the ints starting at each address 
        // pointed to by pp[pi]
        for(int i=0; i<2; i  ) // two ints in each arr
        {
            printf("%d ", pp[pi][i]); // show double indexing of array of pointers
            // Since pp[pi] is now p, we can also say:
            printf("%d\n", p[i]); // index int pointer
        }
    }
}

int main()
{
    f(ptrToArrOfPtrs);

}

f遍歷指標陣列。它認為該地址以及后續地址是指標!這就是宣告的int **pp意思。

現在如果我們傳遞一個充滿整數的陣列的地址,f仍然會認為那里的記憶體充滿了指標。int *p = pp[i];上面這樣的運算式將讀取一個整數(例如,1)并認為它是一個地址。p[i]然后在 printf 呼叫中將嘗試訪問地址 1 處的記憶體。

讓我們以討論為什么應該將二維陣列作為指向指標的指標傳遞的想法如此普遍。一個原因是,雖然將二維陣列引數宣告為void f(int **arr);完全錯誤,但您可以使用 eg 訪問它的第一個(但只有第一個)元素int i = **arr這樣做的原因是第一個解參考為您提供了第一個子陣列,您可以依次應用解參考運算子,產生它的第一個元素。但是,如果將陣列作為引數傳遞給函式,它不會衰減為指向指標的指標,而是如所討論的那樣衰減為指向其第一個元素的指標。

混淆的第二個來源是訪問指標陣列中的元素使用與訪問真正二維陣列中的元素相同的雙索引:pp[pi][i]vs arr[i][j]. . 但是這些運算式生成的代碼完全不同,如果傳遞了錯誤的型別,就會造成災難。順便說一句,您的編譯器會對此發出警告。

轉載請註明出處,本文鏈接:https://www.uj5u.com/net/406067.html

標籤:

上一篇:如何將連續的數字放入括號中?

下一篇:如何以我喜歡的方式將int或pid連接到C中的字串

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • WebAPI簡介

    Web體系結構: 有三個核心:資源(resource),URL(統一資源識別符號)和表示 他們的關系是這樣的:一個資源由一個URL進行標識,HTTP客戶端使用URL定位資源,表示是從資源回傳資料,媒體型別是資源回傳的資料格式。 接下來我們說下HTTP. HTTP協議的系統是一種無狀態的方式,使用請求/ ......

    uj5u.com 2020-09-09 22:07:47 more
  • asp.net core 3.1 入口:Program.cs中的Main函式

    本文分析Program.cs 中Main()函式中代碼的運行順序分析asp.net core程式的啟動,重點不是剖析原始碼,而是理清程式開始時執行的順序。到呼叫了哪些實體,哪些法方。asp.net core 3.1 的程式入口在專案Program.cs檔案里,如下。ususing System; us ......

    uj5u.com 2020-09-09 22:07:49 more
  • asp.net網站作為websocket服務端的應用該如何寫

    最近被websocket的一個問題困擾了很久,有一個需求是在web網站中搭建websocket服務。客戶端通過網頁與服務器建立連接,然后服務器根據ip給客戶端網頁發送資訊。 其實,這個需求并不難,只是剛開始對websocket的內容不太了解。上網搜索了一下,有通過asp.net core 實作的、有 ......

    uj5u.com 2020-09-09 22:08:02 more
  • ASP.NET 開源匯入匯出庫Magicodes.IE Docker中使用

    Magicodes.IE在Docker中使用 更新歷史 2019.02.13 【Nuget】版本更新到2.0.2 【匯入】修復單列匯入的Bug,單元測驗“OneColumnImporter_Test”。問題見(https://github.com/dotnetcore/Magicodes.IE/is ......

    uj5u.com 2020-09-09 22:08:05 more
  • 在webform中使用ajax

    如果你用過Asp.net webform, 說明你也算是.NET 開發的老兵了。WEBform應該是2011 2013左右,當時還用visual studio 2005、 visual studio 2008。后來基本都用的是MVC。 如果是新開發的專案,估計沒人會用webform技術。但是有些舊版 ......

    uj5u.com 2020-09-09 22:08:50 more
  • iis添加asp.net網站,訪問提示:由于擴展配置問題而無法提供您請求的

    今天在iis服務器配置asp.net網站,遇到一個問題,記錄一下: 問題:由于擴展配置問題而無法提供您請求的頁面。如果該頁面是腳本,請添加處理程式。如果應下載檔案,請添加 MIME 映射。 WindowServer2012服務器,添加角色安裝完.netframework和iis之后,運行aspx頁面 ......

    uj5u.com 2020-09-09 22:10:00 more
  • WebAPI-處理架構

    帶著問題去思考,大家好! 問題1:HTTP請求和回傳相應的HTTP回應資訊之間發生了什么? 1:首先是最底層,托管層,位于WebAPI和底層HTTP堆疊之間 2:其次是 訊息處理程式管道層,這里比如日志和快取。OWIN的參考是將訊息處理程式管道的一些功能下移到堆疊下端的OWIN中間件了。 3:控制器處理 ......

    uj5u.com 2020-09-09 22:11:13 more
  • 微信門戶開發框架-使用指導說明書

    微信門戶應用管理系統,采用基于 MVC + Bootstrap + Ajax + Enterprise Library的技術路線,界面層采用Boostrap + Metronic組合的前端框架,資料訪問層支持Oracle、SQLServer、MySQL、PostgreSQL等資料庫。框架以MVC5,... ......

    uj5u.com 2020-09-09 22:15:18 more
  • WebAPI-HTTP編程模型

    帶著問題去思考,大家好!它是什么?它包含什么?它能干什么? 訊息 HTTP編程模型的核心就是訊息抽象,表示為:HttPRequestMessage,HttpResponseMessage.用于客戶端和服務端之間交換請求和回應訊息。 HttpMethod類包含了一組靜態屬性: private stat ......

    uj5u.com 2020-09-09 22:15:23 more
  • 部署WebApi隨筆

    一、跨域 NuGet參考Microsoft.AspNet.WebApi.Cors WebApiConfig.cs中配置: // Web API 配置和服務 config.EnableCors(new EnableCorsAttribute("*", "*", "*")); 二、清除默認回傳XML格式 ......

    uj5u.com 2020-09-09 22:15:48 more
最新发布
  • C#多執行緒學習(二) 如何操縱一個執行緒

    <a href="https://www.cnblogs.com/x-zhi/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2943582/20220801082530.png" alt="" /></...

    uj5u.com 2023-04-19 09:17:20 more
  • C#多執行緒學習(二) 如何操縱一個執行緒

    C#多執行緒學習(二) 如何操縱一個執行緒 執行緒學習第一篇:C#多執行緒學習(一) 多執行緒的相關概念 下面我們就動手來創建一個執行緒,使用Thread類創建執行緒時,只需提供執行緒入口即可。(執行緒入口使程式知道該讓這個執行緒干什么事) 在C#中,執行緒入口是通過ThreadStart代理(delegate)來提供的 ......

    uj5u.com 2023-04-19 09:16:49 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    <a href="https://www.cnblogs.com/huangxincheng/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/214741/20200614104537.png" alt="" /&g...

    uj5u.com 2023-04-18 08:39:04 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    一:背景 1. 講故事 前段時間協助訓練營里的一位朋友分析了一個程式卡死的問題,回過頭來看這個案例比較經典,這篇稍微整理一下供后來者少踩坑吧。 二:WinDbg 分析 1. 為什么會卡死 因為是表單程式,理所當然就是看主執行緒此時正在做什么? 可以用 ~0s ; k 看一下便知。 0:000> k # ......

    uj5u.com 2023-04-18 08:33:10 more
  • SignalR, No Connection with that ID,IIS

    <a href="https://www.cnblogs.com/smartstar/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/u36196.jpg" alt="" /></a>...

    uj5u.com 2023-03-30 17:21:52 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:15:33 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:13:31 more
  • C#遍歷指定檔案夾中所有檔案的3種方法

    <a href="https://www.cnblogs.com/xbhp/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/957602/20230310105611.png" alt="" /></a&...

    uj5u.com 2023-03-27 14:46:55 more
  • C#/VB.NET:如何將PDF轉為PDF/A

    <a href="https://www.cnblogs.com/Carina-baby/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2859233/20220427162558.png" alt="" />...

    uj5u.com 2023-03-27 14:46:35 more
  • 武裝你的WEBAPI-OData聚合查詢

    <a href="https://www.cnblogs.com/podolski/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/616093/20140323000327.png" alt="" /><...

    uj5u.com 2023-03-27 14:46:16 more