数组 [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 <stdio.h>

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;
}

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


二维数组的取值技巧总结

演示代码:value_array_double.c

/* value_array_double.c */
#include <stdio.h>

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;
}

运行结果:

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

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

表现形式含义
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 <stdio.h>

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;
}

|数组指针遍历二维数组

演示代码:arrayDouble_arrayPointer.c

/* arrayDouble_arrayPointer.c */
#include <stdio.h>

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;
}

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


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

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

分析:

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

演示代码: deal.c

/* deal.c 2022.12.7 20:12 */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h> /* 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;
}

运行结果:

card


拓展:函数指针数组

演示代码:fun_pointer_array.c

/* fun_poniter_array.c 2022.6.18 17:52 */
#include <stdio.h>
#include <stdlib.h>

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;
}

∗ \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」
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值