ผ่านอาร์เรย์ 2D ไปยังฟังก์ชัน C ++


324

ฉันมีฟังก์ชั่นที่ฉันต้องการใช้เป็นตัวแปรอาร์เรย์ขนาดสองมิติ

จนถึงตอนนี้ฉันมีสิ่งนี้:

void myFunction(double** myArray){
     myArray[x][y] = 5;
     etc...
}

และฉันได้ประกาศอาร์เรย์ที่อื่นในรหัสของฉัน:

double anArray[10][10];

อย่างไรก็ตามการโทรmyFunction(anArray)ทำให้ฉันมีข้อผิดพลาด

ฉันไม่ต้องการที่จะคัดลอกอาร์เรย์เมื่อฉันผ่านมันใน. การเปลี่ยนแปลงใด ๆ ที่เกิดขึ้นในควรจะปรับเปลี่ยนสถานะของmyFunction anArrayหากฉันเข้าใจอย่างถูกต้องฉันเพียงต้องการส่งผ่านเป็นอาร์กิวเมนต์ตัวชี้ไปยังอาร์เรย์ 2 มิติ ฟังก์ชั่นต้องยอมรับอาร์เรย์ที่มีขนาดต่างกันด้วย ตัวอย่างเช่น, [10][10]และ[5][5]. ฉันจะทำสิ่งนี้ได้อย่างไร


1
ไม่สามารถแปลงพารามิเตอร์ 3 จาก 'double [10] [10]' เป็น 'double **'
RogerDarwin

3
ยอมรับคำตอบที่แสดงให้เห็นเพียง 2 เทคนิค [ของ(2)และ(3)จะเหมือนกัน] แต่มีอยู่4 วิธีที่ไม่ซ้ำกันของการส่งผ่านอาร์เรย์ 2 มิติให้เป็นฟังก์ชั่น
legends2k

พูดอย่างเคร่งครัดใช่พวกเขาไม่ใช่อาร์เรย์ 2 มิติ แต่การประชุมนี้ (แม้ว่าจะนำไปสู่ ​​UB) ของการมีอาร์เรย์ของตัวชี้แต่ละชี้ไปที่ (1D) อาร์เรย์ดูเหมือนจะแพร่หลาย :( มีอาร์เรย์ 1D แบนของ mxn ความยาวพร้อมกับฟังก์ชั่นผู้ช่วย / คลาสเพื่อเลียนแบบอาเรย์ 2 มิตินั้นอาจจะดีกว่า
ตำนาน 2k

ง่ายที่สุดfunc(int* mat, int r, int c){ for(int i=0; i<r; i++) for(int j=0; j<c; j++) printf("%d ", *(mat+i*c+j)); } - เรียกมันว่า -int mat[3][5]; func(mat[0], 3, 5);
Minhas Kamal

คำตอบ:


413

มีสามวิธีในการส่งผ่านอาร์เรย์ 2D ไปยังฟังก์ชัน:

  1. พารามิเตอร์คืออาร์เรย์ 2 มิติ

    int array[10][10];
    void passFunc(int a[][10])
    {
        // ...
    }
    passFunc(array);
  2. พารามิเตอร์คืออาร์เรย์ที่มีพอยน์เตอร์

    int *array[10];
    for(int i = 0; i < 10; i++)
        array[i] = new int[10];
    void passFunc(int *a[10]) //Array containing pointers
    {
        // ...
    }
    passFunc(array);
  3. พารามิเตอร์คือตัวชี้ไปยังตัวชี้

    int **array;
    array = new int *[10];
    for(int i = 0; i <10; i++)
        array[i] = new int[10];
    void passFunc(int **a)
    {
        // ...
    }
    passFunc(array);

4
@Overflowh คุณจะได้รับองค์ประกอบของarrayด้วยarray[i][j]:)
shengy

14
สำหรับกรณีที่ 1 int (*a)[10]พารามิเตอร์ที่สามารถประกาศให้เป็น
Zachary

9
สำหรับกรณีที่ 2 int **พารามิเตอร์สามารถประกาศให้เป็น
Zachary

1
@ แซค: ถูกต้องมีแค่สองกรณีจริงๆ หนึ่งเป็นตัวชี้ไปชี้และความเป็นอยู่อื่น ๆ ชี้เดียวให้กับอาร์เรย์จำนวนเต็มของขนาด n int (*a) [10]คือ
legends2k

3
กรณีที่ 2 และ 3 ไม่ใช่อาร์เรย์ 2 มิติดังนั้นคำตอบนี้ทำให้เข้าใจผิด ดูนี่สิ
Lundin

178

ขนาดคงที่

1. ผ่านการอ้างอิง

template <size_t rows, size_t cols>
void process_2d_array_template(int (&array)[rows][cols])
{
    std::cout << __func__ << std::endl;
    for (size_t i = 0; i < rows; ++i)
    {
        std::cout << i << ": ";
        for (size_t j = 0; j < cols; ++j)
            std::cout << array[i][j] << '\t';
        std::cout << std::endl;
    }
}

ใน C ++ ผ่านอาร์เรย์โดยการอ้างอิงโดยไม่สูญเสียข้อมูลมิติน่าจะปลอดภัยที่สุดเนื่องจากผู้ใช้ไม่จำเป็นต้องกังวลเกี่ยวกับผู้เรียกที่ส่งมิติที่ไม่ถูกต้อง อย่างไรก็ตามสิ่งนี้ไม่สามารถทำได้ด้วยอาเรย์ (freestore) แบบไดนามิก ใช้งานได้สำหรับอาร์เรย์อัตโนมัติ ( โดยปกติคือสแต็ก - ลิฟวิ่ง) เท่านั้นเช่นมิติข้อมูลที่ควรทราบ ณ เวลารวบรวม

2. ผ่านตัวชี้

void process_2d_array_pointer(int (*array)[5][10])
{
    std::cout << __func__ << std::endl;
    for (size_t i = 0; i < 5; ++i)
    {
        std::cout << i << ": ";
        for (size_t j = 0; j < 10; ++j)
            std::cout << (*array)[i][j] << '\t';
        std::cout << std::endl;
    }    
}

เทียบเท่า C ของวิธีการก่อนหน้านี้จะผ่านอาร์เรย์โดยตัวชี้ สิ่งนี้ไม่ควรสับสนกับการผ่านประเภทตัวชี้ที่ลดลงของอาร์เรย์(3)ซึ่งเป็นวิธีการทั่วไปที่เป็นที่นิยมแม้ว่าจะปลอดภัยน้อยกว่าอันนี้ แต่มีความยืดหยุ่นมากกว่า เช่นเดียวกับ(1)ใช้วิธีนี้เมื่อมิติทั้งหมดของอาเรย์ได้รับการแก้ไขและรู้ ณ เวลารวบรวม ทราบว่าเมื่อเรียกใช้ฟังก์ชันที่อยู่ของอาเรย์ควรจะผ่านไปและไม่ได้อยู่ขององค์ประกอบแรกจากการสลายตัวprocess_2d_array_pointer(&a)process_2d_array_pointer(a)

ขนาดตัวแปร

สิ่งเหล่านี้สืบทอดมาจาก C แต่มีความปลอดภัยน้อยกว่าคอมไพเลอร์ไม่มีวิธีการตรวจสอบรับประกันว่าผู้โทรผ่านมิติที่ต้องการ ฟังก์ชั่นจะแสดงเฉพาะสิ่งที่ผู้โทรผ่านเป็นมิติ เหล่านี้มีความยืดหยุ่นมากกว่าข้างต้นเนื่องจากอาร์เรย์ที่มีความยาวต่างกันสามารถส่งผ่านไปยังพวกมันได้อย่างคงเส้นคงวา

โปรดจำไว้ว่าไม่มีสิ่งเช่นการส่งอาร์เรย์โดยตรงไปยังฟังก์ชันใน C [ในขณะที่ใน C ++ พวกเขาสามารถส่งผ่านเป็นการอ้างอิง(1) ]; (2)กำลังส่งตัวชี้ไปยังอาร์เรย์และไม่ใช่อาร์เรย์เอง เสมอผ่านอาร์เรย์เป็นคือจะกลายเป็นตัวชี้การดำเนินการคัดลอกซึ่งจะอำนวยความสะดวกโดยธรรมชาติอาร์เรย์ของเข้าสลายตัวชี้

3. การผ่าน (ค่า) ตัวชี้ไปยังชนิดที่มีการผุ

// int array[][10] is just fancy notation for the same thing
void process_2d_array(int (*array)[10], size_t rows)
{
    std::cout << __func__ << std::endl;
    for (size_t i = 0; i < rows; ++i)
    {
        std::cout << i << ": ";
        for (size_t j = 0; j < 10; ++j)
            std::cout << array[i][j] << '\t';
        std::cout << std::endl;
    }
}

แม้ว่าint array[][10]จะได้รับอนุญาตฉันไม่แนะนำมันเหนือไวยากรณ์ข้างต้นเนื่องจากไวยากรณ์ข้างต้นทำให้ชัดเจนว่าตัวระบุarrayเป็นตัวชี้เดียวกับอาร์เรย์จำนวนเต็ม 10 ตัวในขณะที่ไวยากรณ์นี้ดูเหมือนว่าเป็นอาร์เรย์ 2 มิติ แต่เป็นตัวชี้เดียวกันกับ อาร์เรย์ของจำนวนเต็ม 10 จำนวน ที่นี่เรารู้จำนวนองค์ประกอบในแถวเดียว (เช่นขนาดคอลัมน์ 10 ที่นี่) แต่ไม่ทราบจำนวนแถวและจะถูกส่งผ่านเป็นอาร์กิวเมนต์ ในกรณีนี้มีความปลอดภัยเนื่องจากคอมไพเลอร์สามารถตั้งค่าสถานะเมื่อตัวชี้ไปยังอาร์เรย์ที่มีมิติที่สองไม่เท่ากับ 10 ถูกส่งผ่าน มิติแรกคือส่วนต่าง ๆ และสามารถละเว้นได้ ดูที่นี่สำหรับเหตุผลที่ว่าทำไมจึงอนุญาตให้ละเว้นเฉพาะมิติแรกเท่านั้น

4. ผ่านตัวชี้ไปยังตัวชี้

// int *array[10] is just fancy notation for the same thing
void process_pointer_2_pointer(int **array, size_t rows, size_t cols)
{
    std::cout << __func__ << std::endl;
    for (size_t i = 0; i < rows; ++i)
    {
        std::cout << i << ": ";
        for (size_t j = 0; j < cols; ++j)
            std::cout << array[i][j] << '\t';
        std::cout << std::endl;
    }
}

อีกครั้งมีไวยากรณ์ทางเลือกของการที่เป็นเช่นเดียวกับint *array[10] int **arrayในไวยากรณ์นี้จะถูกละเว้นในขณะที่มันสูญสลายลงไปในตัวชี้จึงกลายเป็น[10] int **arrayอาจเป็นเพียงคิวสำหรับผู้โทรที่อาเรย์ที่ผ่านควรมีอย่างน้อย 10 คอลัมน์แม้จะต้องมีการนับจำนวนแถว ในกรณีใด ๆ คอมไพเลอร์ไม่ได้ตั้งค่าสถานะสำหรับการละเมิดความยาว / ขนาดใด ๆ (มันจะตรวจสอบเฉพาะประเภทที่ส่งผ่านเป็นตัวชี้ไปยังตัวชี้) ดังนั้นจึงต้องมีทั้งแถวและคอลัมน์นับเป็นพารามิเตอร์ทำให้รู้สึกที่นี่

หมายเหตุ: (4) เป็นตัวเลือกที่ปลอดภัยที่สุดเนื่องจากแทบจะไม่มีการตรวจสอบประเภทใด ๆ และไม่สะดวกที่สุด เราไม่สามารถผ่านอาร์เรย์ 2 มิติไปยังฟังก์ชันนี้ได้อย่างถูกกฎหมาย C-FAQ ประณามการแก้ปัญหาตามปกติของการทำint x[5][10]; process_pointer_2_pointer((int**)&x[0][0], 5, 10);เพราะอาจนำไปสู่พฤติกรรมที่ไม่ได้กำหนดเนื่องจากการแบนอาร์เรย์ วิธีที่ถูกต้องในการส่งอาเรย์ในวิธีนี้นำเราไปสู่ส่วนที่ไม่สะดวกนั่นคือเราต้องการอาเรย์ (ตัวแทน) เพิ่มเติมของพอยน์เตอร์โดยแต่ละองค์ประกอบจะชี้ไปยังแถวตามลำดับของอาเรย์ที่ถูกส่งผ่านจริง ตัวแทนนี้จะถูกส่งผ่านไปยังฟังก์ชั่น (ดูด้านล่าง); ทั้งหมดนี้เพื่อให้ได้งานที่เหมือนกันกับวิธีการข้างต้นซึ่งปลอดภัยกว่าสะอาดกว่าและเร็วกว่า

นี่คือโปรแกรมควบคุมเพื่อทดสอบฟังก์ชั่นด้านบน:

#include <iostream>

// copy above functions here

int main()
{
    int a[5][10] = { { } };
    process_2d_array_template(a);
    process_2d_array_pointer(&a);    // <-- notice the unusual usage of addressof (&) operator on an array
    process_2d_array(a, 5);
    // works since a's first dimension decays into a pointer thereby becoming int (*)[10]

    int *b[5];  // surrogate
    for (size_t i = 0; i < 5; ++i)
    {
        b[i] = a[i];
    }
    // another popular way to define b: here the 2D arrays dims may be non-const, runtime var
    // int **b = new int*[5];
    // for (size_t i = 0; i < 5; ++i) b[i] = new int[10];
    process_pointer_2_pointer(b, 5, 10);
    // process_2d_array(b, 5);
    // doesn't work since b's first dimension decays into a pointer thereby becoming int**
}

สิ่งที่เกี่ยวกับการส่งผ่านอาร์เรย์ที่จัดสรรแบบไดนามิกไปยังฟังก์ชันใน C ++ ในมาตรฐาน C11 สามารถทำได้สำหรับอาร์เรย์ที่ได้รับการจัดสรรแบบคงที่และแบบไดนามิกเช่น fn (int col, แถว int, int array [col] [แถว]): stackoverflow.com/questions/16004668/ …ฉันได้ตั้งคำถามกับปัญหานี้แล้ว : stackoverflow.com/questions/27457076/…
42n4

@ 42n4 Case 4 ครอบคลุม (สำหรับ C ++ ด้วย) สำหรับอาร์เรย์จัดสรรเพียงเส้นที่อยู่ภายในวงที่จะเปลี่ยนจากการที่จะพูดว่าb[i] = a[i]; b[i] = new int[10];หนึ่งอาจทำการbจัดสรรแบบไดนามิกint **b = int *[5];และมันจะยังคงทำงานตามที่เป็นอยู่
ตำนาน 2k

1
การกำหนดที่อยู่array[i][j]ทำงานในฟังก์ชันใน4)อย่างไร เพราะมันได้รับ ptr ถึง ptr และไม่ทราบค่าของมิติสุดท้ายซึ่งจำเป็นต้องทำการเลื่อนเพื่อแก้ไขที่อยู่ที่ถูกต้อง?
user1234567

2
array[i][j]เป็นเพียงเช่นคณิตศาสตร์ชี้ไปยังค่าของตัวชี้arrayก็ต้องการเพิ่มiและ dereference ผลตามที่int*ซึ่งมันจะเพิ่มjและ dereference ว่าสถานที่, intการอ่าน ดังนั้นไม่จำเป็นต้องรู้มิติใด ๆ สำหรับสิ่งนี้ แต่นั่นคือประเด็นทั้งหมด! คอมไพเลอร์ใช้คำของโปรแกรมเมอร์ด้วยความศรัทธาและหากโปรแกรมเมอร์ไม่ถูกต้องพฤติกรรมที่ไม่ได้กำหนดก็จะตามมา นี่คือเหตุผลที่ฉันกล่าวถึงกรณีที่ 4 เป็นตัวเลือกที่ปลอดภัยที่สุด
legends2k

ในกรณีเช่นนี้โครงสร้างอาจให้บริการคุณได้ดี
Xofo

40

การดัดแปลงคำแนะนำแรกของ shengy คุณสามารถใช้เทมเพลตเพื่อทำให้ฟังก์ชั่นยอมรับตัวแปรอาเรย์หลายมิติ (แทนที่จะเก็บอาเรย์ของพอยน์เตอร์ที่ต้องจัดการและลบ):

template <size_t size_x, size_t size_y>
void func(double (&arr)[size_x][size_y])
{
    printf("%p\n", &arr);
}

int main()
{
    double a1[10][10];
    double a2[5][5];

    printf("%p\n%p\n\n", &a1, &a2);
    func(a1);
    func(a2);

    return 0;
}

คำสั่งการพิมพ์อยู่ที่นั่นเพื่อแสดงว่าอาร์เรย์กำลังถูกส่งผ่านโดยการอ้างอิง (โดยการแสดงที่อยู่ของตัวแปร)


2
คุณควรใช้%pสำหรับการพิมพ์ตัวชี้และจากนั้นคุณต้องส่งไปยังvoid *มิฉะนั้นprintf()จะเรียกใช้พฤติกรรมที่ไม่ได้กำหนด นอกจากนี้คุณไม่ควรใช้ AddressOf ( &ผู้ดำเนินการ) เมื่อเรียกฟังก์ชั่นตั้งแต่ฟังก์ชั่นคาดหวังว่าข้อโต้แย้งของพิมพ์double (*)[size_y]ในขณะที่คุณกำลังจะผ่านพวกเขาและdouble (*)[10][10] double (*)[5][5]

หากคุณใช้แม่แบบที่สร้างทั้งสองมิติเนื่องจากอาร์กิวเมนต์ของแม่แบบนั้นเหมาะสมกว่าและดีกว่าเนื่องจากการเข้าถึงตัวชี้ระดับต่ำอาจหลีกเลี่ยงได้อย่างสมบูรณ์
legends2k

3
ใช้งานได้ก็ต่อเมื่อทราบขนาดของอาเรย์ในเวลารวบรวม
jeb_is_a_mess

@Georg Code ด้านบนตอบเป็นสิ่งที่ฉันแนะนำ มันทำงานได้ใน GCC 6.3 - สาธิตออนไลน์ คุณลืมที่จะทำให้พารามิเตอร์อ้างอิงหรือไม่?
ตำนาน 2k

21

แปลกใจที่ไม่มีใครพูดถึงเรื่องนี้ แต่คุณสามารถสร้างเทมเพลตกับสิ่งที่สนับสนุน 2D [] [] ได้

template <typename TwoD>
void myFunction(TwoD& myArray){
     myArray[x][y] = 5;
     etc...
}

// call with
double anArray[10][10];
myFunction(anArray);

มันทำงานร่วมกับโครงสร้างข้อมูลแบบ "array-like" แบบ 2D ใด ๆ เช่นstd::vector<std::vector<T>>หรือประเภทที่ผู้ใช้กำหนดเองเพื่อเพิ่มการใช้รหัสซ้ำให้ได้มากที่สุด


1
นี่ควรเป็นคำตอบที่ถูกต้อง มันแก้ปัญหาทั้งหมดที่กล่าวถึงและบางส่วนที่ไม่ได้กล่าวถึงที่นี่ ความปลอดภัยประเภท, ความเข้ากันไม่ได้ของเวลาการคอมไพล์ของอาร์เรย์, ไม่ใช้ตัวชี้คณิตศาสตร์, ไม่ใช้การหล่อประเภท, ไม่มีการคัดลอกข้อมูล ใช้งานได้กับ C และ C ++
OpalApps

มันใช้ได้กับ C ++; C ไม่รองรับเทมเพลต การทำมันใน C จะต้องมีมาโคร
Gunnar

20

คุณสามารถสร้างเทมเพลตฟังก์ชันดังนี้:

template<int R, int C>
void myFunction(double (&myArray)[R][C])
{
    myArray[x][y] = 5;
    etc...
}

จากนั้นคุณมีขนาดทั้งสองผ่าน R และ C ฟังก์ชั่นที่แตกต่างกันจะถูกสร้างขึ้นสำหรับแต่ละขนาดอาเรย์ดังนั้นหากฟังก์ชั่นของคุณมีขนาดใหญ่และคุณเรียกมันด้วยขนาดของอาเรย์ที่แตกต่างกัน คุณสามารถใช้มันเป็นเสื้อคลุมทับฟังก์ชั่นเช่นนี้แม้ว่า:

void myFunction(double * arr, int R, int C)
{
    arr[x * C + y] = 5;
    etc...
}

มันปฏิบัติต่ออาร์เรย์เป็นมิติเดียวและใช้เลขคณิตเพื่อหาค่าออฟเซ็ตของดัชนี ในกรณีนี้คุณจะกำหนดเทมเพลตดังนี้:

template<int C, int R>
void myFunction(double (&myArray)[R][C])
{
    myFunction(*myArray, R, C);
}

2
size_tintเป็นชนิดที่ดีกว่าสำหรับดัชนีอาร์เรย์กว่า
Andrew Tomazos

13

anArray[10][10]ไม่ใช่ตัวชี้ไปยังตัวชี้มันเป็นอันต่อเนื่องกันของหน่วยความจำที่เหมาะสมสำหรับการจัดเก็บ 100 ค่าประเภทคู่ซึ่งคอมไพเลอร์รู้วิธีการที่อยู่เพราะคุณระบุขนาด คุณต้องส่งมันไปยังฟังก์ชั่นเป็นอาร์เรย์ คุณสามารถข้ามขนาดของมิติข้อมูลเริ่มต้นได้ดังนี้:

void f(double p[][10]) {
}

อย่างไรก็ตามสิ่งนี้จะไม่ยอมให้คุณผ่านอาร์เรย์ด้วยมิติสุดท้ายที่นอกเหนือจากสิบ

ทางออกที่ดีที่สุดใน C ++ คือการใช้งานstd::vector<std::vector<double> >: มันเกือบมีประสิทธิภาพและสะดวกยิ่งขึ้น


1
ฉันชอบโซลูชันนี้เนื่องจากไลบรารี std นั้นมีประสิทธิภาพมาก - โดยวิธีที่ฉันชอบ dasblinkenlight ฉันเคยใช้ dasblikenlicht
mozillanerd

เกือบจะมีประสิทธิภาพเท่าไหร่? ช่ายยย. การไล่ตามตัวชี้นั้นมีราคาแพงกว่าการไล่ที่ไม่ใช่ตัวชี้เสมอ
Thomas Eding

8

อาร์เรย์มิติเดียวจะสลายตัวไปยังตัวชี้ชี้ที่ชี้ไปที่องค์ประกอบแรกในอาร์เรย์ ในขณะที่อาร์เรย์ 2D จะชี้ไปที่ตัวชี้ชี้ไปที่แถวแรก ดังนั้นต้นแบบฟังก์ชั่นควรจะเป็น -

void myFunction(double (*myArray) [10]);

ฉันต้องการstd::vectorมากกว่าอาร์เรย์ดิบ


8

คุณสามารถทำอะไรเช่นนี้ ...

#include<iostream>

using namespace std;

//for changing values in 2D array
void myFunc(double *a,int rows,int cols){
    for(int i=0;i<rows;i++){
        for(int j=0;j<cols;j++){
            *(a+ i*rows + j)+=10.0;
        }
    }
}

//for printing 2D array,similar to myFunc
void printArray(double *a,int rows,int cols){
    cout<<"Printing your array...\n";
    for(int i=0;i<rows;i++){
        for(int j=0;j<cols;j++){
            cout<<*(a+ i*rows + j)<<"  ";
        }
    cout<<"\n";
    }
}

int main(){
    //declare and initialize your array
    double a[2][2]={{1.5 , 2.5},{3.5 , 4.5}};

    //the 1st argument is the address of the first row i.e
    //the first 1D array
    //the 2nd argument is the no of rows of your array
    //the 3rd argument is the no of columns of your array
    myFunc(a[0],2,2);

    //same way as myFunc
    printArray(a[0],2,2);

    return 0;
}

ผลลัพธ์ของคุณจะเป็นดังนี้ ...

11.5  12.5
13.5  14.5

1
เหตุผลเดียวที่ฉันคิดได้ว่าทำไมคนเราถึงต้องทำอาร์เรย์ในกรณีนี้เพราะใคร ๆ ขาดความรู้เกี่ยวกับวิธีการทำงานของพอยน์เตอร์พอยน์เตอร์
Lundin

3
ตัวแปร i ต้องคูณด้วยคอลัมน์ไม่ใช่ตามแถวเว้นแต่คอลัมน์และแถวจะเท่ากันในกรณีนี้
Andrey Chernukha

4

นี่คือตัวอย่างเวกเตอร์ของเมทริกซ์เวกเตอร์

#include <iostream>
#include <vector>
using namespace std;

typedef vector< vector<int> > Matrix;

void print(Matrix& m)
{
   int M=m.size();
   int N=m[0].size();
   for(int i=0; i<M; i++) {
      for(int j=0; j<N; j++)
         cout << m[i][j] << " ";
      cout << endl;
   }
   cout << endl;
}


int main()
{
    Matrix m = { {1,2,3,4},
                 {5,6,7,8},
                 {9,1,2,3} };
    print(m);

    //To initialize a 3 x 4 matrix with 0:
    Matrix n( 3,vector<int>(4,0));
    print(n);
    return 0;
}

เอาท์พุท:

1 2 3 4
5 6 7 8
9 1 2 3

0 0 0 0
0 0 0 0
0 0 0 0

2

เราสามารถใช้หลายวิธีในการส่งผ่านอาร์เรย์ 2 มิติไปยังฟังก์ชัน:

  • การใช้ตัวชี้เดียวเราต้องพิมพ์อาร์เรย์ 2D

    #include<bits/stdc++.h>
    using namespace std;
    
    
    void func(int *arr, int m, int n)
    {
        for (int i=0; i<m; i++)
        {
           for (int j=0; j<n; j++)
           {
              cout<<*((arr+i*n) + j)<<" ";
           }
           cout<<endl;
        }
    }
    
    int main()
    {
        int m = 3, n = 3;
        int arr[m][n] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
        func((int *)arr, m, n);
        return 0;
    }
  • การใช้ตัวชี้คู่ด้วยวิธีนี้เรายังพิมพ์อาร์เรย์ 2d อีกด้วย

    #include<bits/stdc++.h>
    using namespace std;

   void func(int **arr, int row, int col)
   {
      for (int i=0; i<row; i++)
      {
         for(int j=0 ; j<col; j++)
         {
           cout<<arr[i][j]<<" ";
         }
         printf("\n");
      }
   }

  int main()
  {
     int row, colum;
     cin>>row>>colum;
     int** arr = new int*[row];

     for(int i=0; i<row; i++)
     {
        arr[i] = new int[colum];
     }

     for(int i=0; i<row; i++)
     {
         for(int j=0; j<colum; j++)
         {
            cin>>arr[i][j];
         }
     }
     func(arr, row, colum);

     return 0;
   }

1

สิ่งสำคัญอย่างหนึ่งสำหรับการส่งผ่านอาร์เรย์หลายมิติคือ:

  • First array dimension ไม่จำเป็นต้องระบุ
  • Second(any any further)dimension จะต้องระบุ

1. เมื่อมีมิติที่สองเท่านั้นที่ใช้ได้ทั่วโลก (ไม่ว่าจะเป็นแมโครหรือค่าคงที่ทั่วโลก)

`const int N = 3;

`void print(int arr[][N], int m)
{
int i, j;
for (i = 0; i < m; i++)
  for (j = 0; j < N; j++)
    printf("%d ", arr[i][j]);
}`

int main()
{
int arr[][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
print(arr, 3);
return 0;
}`

2. การใช้ตัวชี้เดียว : ในวิธีนี้เราจะต้องพิมพ์อาร์เรย์ 2D เมื่อผ่านไปยังฟังก์ชั่น

`void print(int *arr, int m, int n)
{
int i, j;
for (i = 0; i < m; i++)
  for (j = 0; j < n; j++)
    printf("%d ", *((arr+i*n) + j));
 }

`int main()
{
int arr[][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
int m = 3, n = 3;

// We can also use "print(&arr[0][0], m, n);"
print((int *)arr, m, n);
return 0;
}`

0

คุณสามารถใช้สิ่งอำนวยความสะดวกแม่แบบใน C ++ เพื่อทำสิ่งนี้ ฉันทำอะไรเช่นนี้

template<typename T, size_t col>
T process(T a[][col], size_t row) {
...
}

ปัญหาเกี่ยวกับวิธีการนี้คือว่าสำหรับทุกค่าของ col ที่คุณให้คำจำกัดความของฟังก์ชั่นใหม่นั้นถูกสร้างขึ้นโดยใช้แม่แบบ ดังนั้น,

int some_mat[3][3], another_mat[4,5];
process(some_mat, 3);
process(another_mat, 4);

สร้างเท็มเพลตสองครั้งเพื่อสร้างนิยามฟังก์ชัน 2 ฟังก์ชัน (หนึ่งที่ col = 3 และหนึ่งที่ col = 5)


0

หากคุณต้องการที่จะผ่านint a[2][3]ไปvoid func(int** pp)คุณจะต้องทำตามขั้นตอนดังต่อไปนี้เสริม

int a[2][3];
int* p[2] = {a[0],a[1]};
int** pp = p;

func(pp);

ในฐานะที่เป็นคนแรกที่[2]สามารถระบุโดยปริยายมันสามารถง่ายขึ้นต่อไปเป็น

int a[][3];
int* p[] = {a[0],a[1]};
int** pp = p;

func(pp);

0

ในกรณีที่คุณต้องการส่งผ่านอาร์เรย์ 2 มิติแบบไดนามิกไปยังฟังก์ชั่นการใช้ตัวชี้บางตัวอาจทำงานให้คุณได้

void func1(int *arr, int n, int m){
    ...
    int i_j_the_element = arr[i * m + j];  // use the idiom of i * m + j for arr[i][j] 
    ...
}

void func2(){
    ...
    int arr[n][m];
    ...
    func1(&(arr[0][0]), n, m);
}

0

คุณได้รับอนุญาตให้ละเว้นมิติด้านซ้ายสุดดังนั้นคุณจึงมีสองตัวเลือกดังนี้:

void f1(double a[][2][3]) { ... }

void f2(double (*a)[2][3]) { ... }

double a[1][2][3];

f1(a); // ok
f2(a); // ok 

นี่เป็นสิ่งเดียวกันกับพอยน์เตอร์:

// compilation error: cannot convert ‘double (*)[2][3]’ to ‘double***’ 
// double ***p1 = a;

// compilation error: cannot convert ‘double (*)[2][3]’ to ‘double (**)[3]’
// double (**p2)[3] = a;

double (*p3)[2][3] = a; // ok

// compilation error: array of pointers != pointer to array
// double *p4[2][3] = a;

double (*p5)[3] = a[0]; // ok

double *p6 = a[0][1]; // ok

การสลายตัวของอาร์เรย์ N มิติไปยังตัวชี้ไปยังอาร์เรย์มิติ N-1 ได้รับอนุญาตตามมาตรฐาน C ++เนื่องจากคุณสามารถสูญเสียมิติข้อมูลซ้ายสุดและยังคงสามารถเข้าถึงองค์ประกอบอาร์เรย์ได้อย่างถูกต้องด้วยข้อมูลมิติ N-1

รายละเอียดที่นี่

แม้ว่าอาร์เรย์และพอยน์เตอร์จะไม่เหมือนกัน: อาเรย์สามารถสลายตัวเป็นพอยน์เตอร์ได้ แต่พอยน์เตอร์จะไม่แสดงสถานะเกี่ยวกับขนาด / การกำหนดค่าของข้อมูลที่ชี้ไป

A char **คือตัวชี้ไปยังบล็อกหน่วยความจำที่มีพอยน์เตอร์อักขระซึ่งชี้ไปที่บล็อกหน่วยความจำของอักขระ A char [][]คือบล็อกหน่วยความจำเดี่ยวซึ่งมีอักขระ สิ่งนี้มีผลกระทบต่อวิธีที่คอมไพเลอร์แปลรหัสและประสิทธิภาพการทำงานขั้นสุดท้ายจะเป็นอย่างไร

แหล่ง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.