• 数组 [3]|二维数组(C语言)


    文章转载请注明出处,加上原文链接,谢谢!



    什么是二维数组?

    E.g. int array[2][3]={{1,2,3},{4,5,6}}

    示例数组是一个初始化的 二维数组。定义一个 二维数组和一个普通的一维数组类似,同样包含三要素: 数据类型数组名数组大小。大部分人会说两者的区别在于第三要素 —— 数组大小方面多了一个方括号“[]”,使得二维数组能自由的定义 行数列数 的数量多少。但在笔者看来,矩阵(Matrix)—— 这一数学概念可以完美的阐述两者的区别:

    一维数组(int array[]) —— A 1 × n A_{1 \times n} A1×n
    二维数组(int array[][]) —— A m × n A_{m \times n} Am×n

    二维数组和一维数组的表述形式虽然不同,但两个数组在计算机内存里的存储方式是一致的,即 所有数据都是按顺序存储在连续的内存空间内

    array_double

    二维数组的使用有诸多细节,这里博主再补充一点:参数传递。运用二维数组进行函数传递参数时 行数可以不用填写,但列数必须填写。

    演示代码:array_double_print.c

    /* array_double_print.c */
    #include 
    
    void printArrayDouble(int array[][3])
    {
            int i, j;
            for(i = 0; i < 2; i++){
                    for(j = 0; j < 3; j++){
                            printf("%d ", array[i][j]);
                    }
                    putchar('\n');
            }
    }
    
    int main()
    {
            int array[2][3] = {{1,2,3}, {4,5,6}};
            printArrayDouble(array);
            return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    点击此处,阅读笔者关于“一维数组”的博文。


    二维数组的取值技巧总结

    演示代码:value_array_double.c

    /* value_array_double.c */
    #include 
    
    int main()
    {
            int a[2][3] = {{1,2,3},{4,5,6}};
            int i,j;
    
            printf("a[2][3]: \n");
            for(i = 0; i < 2; i++){
                    for(j = 0; j < 3; j++){
                            printf("%d ", a[i][j]);
                    }
                    putchar('\n');
            }
            putchar('\n');
    
            printf("a[0][0]     : %d\n", a[0][0]);
            printf("*(*(a+0))   : %d\n", *(*(a+0)));
            printf("**a         : %d\n", **a);
            printf("p of a[0][0]: %p\n", a);
            printf("a[1][1]     : %d\n", a[1][1]);
            printf("*(a[1]+1)   : %d\n", *(a[1]+1));
            printf("*(*(a+1)+1)): %d\n", *(*(a+1)+1));
            printf("p of a[1][2]: %p\n", *(a+2));
            printf("a[1][0]     : %d\n", a[1][0]);
            printf("a[0]+1      : %d\n", *(*(a+1)));
            printf("p of a[1][0]: %p\n", a+1);
            return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    运行结果:

    a[0][0]     : 1
    *(*(a+0))   : 1
    **a         : 1
    p of a[0][0]: 0x7ffcbd065d40
    a[1][1]     : 5
    *(a[1]+1)   : 5
    *(*(a+1)+1)): 5
    p of a[1][2]: 0x7ffcbd065d58
    a[1][0]     : 4
    a[0]+1      : 4
    p of a[1][0]: 0x7ffcbd065d4c
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    二维数组取值形式与含义总结:

    表现形式含义
    a二维数组名,指向一维数组a[0],即第零行首地址。
    a[0] , ∗ \ast (a+0), ∗ \ast a第零行第零列元素首地址。
    a[0][0], ∗ \ast ( ∗ \ast (a+0)), ∗ ∗ \ast\ast a第零行第零列元素的数值。
    a+1,&a[1]第一行首地址。
    a[1], ∗ \ast (a+1)第一行第零列元素a[1][0]元素的地址。
    a[1]+2, ∗ \ast (a+1)+2,&a[1][2]第一行第二列元素a[1][2]的地址。
    ∗ \ast (a[1]+2), ∗ \ast ( ∗ \ast (a+1)+2,a[1][2]第一行第二列元素a[1][2]的值。

    ∗ \ast 注意:二维数组元素的取值方式相比一维数组虽然略有繁琐,但以数学形式理解无非都是存储数据的矩阵而已。配合以上代码理解将事半功倍。


    二维数组的遍历

    |运用指针遍历二维数组

    指针遍历的代码:double_array_pointer.c

    /* double_array.c */
    #include 
    
    int main()
    {
            int array[2][3] = {{1,2,3},{456}};
            int i, j;
            int *p = NULL;
            p = &array[0][0];
    
            for(i = 0; i < 3; i++){
                    for(j = 0; j < 3; j++){
                            printf("%d ", *p++);
                    }
                    putchar('\n');
            }
            return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    数组指针遍历二维数组

    演示代码:arrayDouble_arrayPointer.c

    /* arrayDouble_arrayPointer.c */
    #include 
    
    int main()
    {
    	int i,j;
    	int array[2][3] = {{1,2,3},{4,5,6}};
    	int (*p)[3] = NULL;
    	p = array;
    
    	printf("for循环遍历:\n");
    	for(i = 0; i < 2; i++){
    		for(j = 0; j < 3; j++){
    			printf("%d ", array[i][j]);
    		}
    		putchar('\n');
    	}
    	
    	putchar('\n');	
    	
    	printf("数组指针遍历:\n");
    	for(i = 0; i < 2; i++){
    		for(j = 0; j < 3; j++){
    			//printf("%d ", p[i][j]);
    			printf("%d ", *(*(p+i)+j));
    		}
    		putchar('\n');
    	}
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    ∗ \ast 注:对于优先级混乱的读者,只需牢牢记住三个字符的优先级为 () > [] > ∗ \ast ,从大到小逐次递减。


    二维数组的典型场景:两次(多次)抽取纸牌

    问题:如何从一副扑克牌中随机抽取纸牌?如何避免两次(多次抽取时)抽到同一张牌呢?

    分析:

    1. 随机抽取纸牌。使用 srand() 函数初始化随机数生成器,利用时间戳 time() 函数避免程序在运行时发同样的牌;
    2. 限定范围。使用 rand() 函数产生随机数,使用运算符 % 让 rand() 函数的返回值缩限制在 花色等级 范围内;
    3. 以名为 in_hand() 的二维数组记录选择过的纸牌,避免在抽两次或者两次以上抽取时拿到同样的纸牌;
    4. 设置两个字符数组(一个用纸纸牌的等级,一个用于纸牌的花色),利用等级与花色对数组取下标。这两个数组在程序执行期间不会发生改变,将它们声明为 const 。

    演示代码: deal.c

    /* deal.c 2022.12.7 20:12 */
    #include 
    #include 
    #include 
    #include  /* C99 */
    
    #define NUM_SUITS 4
    #define NUM_RANKS 13
    
    int main(){
            bool in_hand[NUM_SUITS][NUM_RANKS] = {false};
            int num_cards, rank, suit;
    
            const char rank_code[] = {'2','3','4','5','6','7','8','9','t','j','q','k','a'};
            //club(♣️),diamond(♦️),heart(♥️),spade(♠️).
            const char suit_code[] = {'c','d','h','s'}; 
    
            srand((unsigned)time(NULL));
    
            printf("Enter number of cards in hand: ");
            scanf("%d", &num_cards);
    
            printf("Your hand:");
            while(num_cards > 0){
                    suit = rand() % NUM_SUITS;
                    rank = rand() % NUM_RANKS;
                    if(!in_hand[suit][rank]){
                            in_hand[suit][rank] = true;
                            num_cards--;
                            printf(" %c%c", rank_code[rank], suit_code[suit]);
                    }
            }
            putchar('\n');
    
            return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    运行结果:

    card


    拓展:函数指针数组

    演示代码:fun_pointer_array.c

    /* fun_poniter_array.c 2022.6.18 17:52 */
    #include 
    #include 
    
    int getMax(int data1, int data2)
    {
            return data1 > data2 ? data1:data2;
    }
    
    int getMin(int data1, int data2)
    {
            return data1 < data2 ? data1:data2;
    }
    
    int getSum(int data1, int data2)
    {
            return data1 + data2;
    }
    
    int main()
    {
            int a = 10, b = 20;
            int ret;
    
            int (*pfunc[3])(int /*data1*/, int /*data2*/) = {getMax, getMin, getSum};
    
            for(int i=0; i<3; i++){
                    ret = (*pfunc[i])(a, b);
                    printf("ret = %d\n", ret);
            }
            return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    ∗ \ast 注:该段代码来自陈立臣教师新版C语言教学视频。


    参考资料

    • 陈立臣老师新版C语言教学视频。
    • 书籍《C语言程序设计现代方法》P119-122。

    文章更新记录

    • 文章整体框架搭好。「2022.11.2 11:27」
    • “什么是二维数组?”一节完成。「2022.11.2 16:40」
    • “二维数组的取值技巧总结”一节完成。「2022.11.3 10:30」
    • 第一节“参数传递”补充完毕。「2022.11.3 16:23」
    • “函数指针数组”一节更新完毕。「2022.11.3 16:56」
    • 修改了三处:一、value_array_double.c 代码错误改正,二、技巧总结列表一处错误改正,三、所有“ ∗ \ast 注意”文字加粗并且大小 size=1 。「2022.11.5. 9:46」
    • 多增加新的一节内容“二维数组的典型场景:两次(多次)抽取纸牌”。「2022.12.7 21:01」
    • 增加了一张二维数组元素存储的图片,《C程序语言设计现代方法》P119。「2022.12.7 21:07」
  • 相关阅读:
    Docker基本使用
    穿越火线几次体验良好的游戏优化方案
    2014华为Java笔试题+数据库题
    伺服阀放大器控制器放大板
    java 8 stream API
    一文揭开,测试外包公司的真 相
    API(八)cosocket常用SDK
    23种设计模式之责任链模式
    qt.qpa.plugin: Could not load the Qt platform plugin “xcb“
    [Pandas] Pandas数据结构
  • 原文地址:https://blog.csdn.net/weixin_46959681/article/details/126707138