我撰寫了代碼,允許我通過傳遞陣列的元素來修改函式內的一維陣列的元素:
- 我列印原始陣列
- 我將陣列的每個元素傳遞給函式
- 在函式中,我將值 50 添加到陣列的每個元素
- 然后我呼叫該函式,并列印出來以篩選修改后的元素值(即每個元素的值 50)
我已經能夠為一維陣列執行此操作,陣列中的示例值為(10,20,30),修改后列印的值為(60,70,80)。
我希望做的是使該代碼適用于二維陣列,您將在下面看到我這樣做的嘗試。這段代碼側重于 int 的使用,但一旦我了解了如何實作這一點,我希望也能適應二維字串的使用。
使用以下代碼:
我的目標是
- 列印以篩選原始二維陣列
- 將二維陣列的每個元素傳遞給函式
- 在函式內將值 50 添加到陣列的每個元素
- 然后呼叫該函式,將修改后的元素值列印到螢屏上(預期結果顯示在螢屏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 itvoid。 - 當你呼叫它時
a = function(&arr[i][0]);,你不會a在賦值后使用。我建議您a完全從程式中洗掉,因為它沒有在任何地方使用。 - 對函式 的呼叫
function(&arr[i][0]);應該是function(arr); - 函式簽名需要包括除最外層之外的所有維度:
void function(int arr[][M]) - 在函式內部,您使用
3and5而不是NandM。這會越界訪問陣列。 - 在 中
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你混合int和size_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 處的記憶體。
讓我們以討論為什么應該將二維陣列作為指向指標的指標傳遞的想法如此普遍。一個原因是,雖然將二維陣列引數宣告為完全錯誤,但您可以使用 eg 訪問它的第一個(但只有第一個)元素void f(int **arr);int i = **arr。這樣做的原因是第一個解參考為您提供了第一個子陣列,您可以依次應用解參考運算子,產生它的第一個元素。但是,如果將陣列作為引數傳遞給函式,它不會衰減為指向指標的指標,而是如所討論的那樣衰減為指向其第一個元素的指標。
混淆的第二個來源是訪問指標陣列中的元素使用與訪問真正二維陣列中的元素相同的雙索引:pp[pi][i]vs arr[i][j]. . 但是這些運算式生成的代碼完全不同,如果傳遞了錯誤的型別,就會造成災難。順便說一句,您的編譯器會對此發出警告。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/406067.html
標籤:
上一篇:如何將連續的數字放入括號中?
