如何在c/c++中,做一个可以接收任意二维数组的函数接口,并在函数中能以下标的形式引用元素

本文主要是介绍如何在c/c++中,做一个可以接收任意二维数组的函数接口,并在函数中能以下标的形式引用元素,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

       前一段时间,在用GTK+2.0做一个贪吃蛇的小游戏,有这样一个想法,游戏的每一关不仅障碍物要增多,而且地图也要变大,也就是程序中二维数组要变化。这样就有了一个需求,要做一个可以接收任意的二维数组的函数接口,并且在函数中要做到用数组下标的方式引用数组元素,如a[3][2](强调用这种方式引用元素,原因见后).
       但在c/c++中要传递一个二维数组,那么函数的形参中必须要指定第二维的维数,如void fun(int a[][3]);或是void fun(int (*a)[3]),其实也就是必须要告诉编译器块指针的偏移因子是多少,如(a+1)实际为(a+1*偏移因子),我就想那把二维数组的首地址赋给一个指向一维数组的指针,然后再自己控制偏移量不就好了,的确这样是可行的,但是引用元素的时候又不能以下标的形式来引用,如果这样的话前面写好的算法或针对特定二维数组的函数转变成可以处理任意二维数组的函数的话,则要改的东西可就太多了,为了能偷懒,超希望依然能用像a[2][3]这样的下标法来引用元素了,这样就只需稍微改一下接口就行了。
       经过几天的思考,我终于想到了一种简单方便的方法,虽然没什么大不了,只能算是个小技巧吧,分享给大家。(估计这种小把戏,大家要见笑了,亏我还好意思拿出来)
       我想到了指针数组如 int *a[2]; 它和一个二维数组在引用时根本不能区分开来,像a[1][2],你并不能推断出a是二维数组名,还是一个指针数组。所以我想到了把一个二维数组转化成一个指针数组。
/* achieving a common array transform as a point array */
int ** deal_array(void *array, int row, int col)
{
 int **p, *object;
 object=(int *)array;
 if(p=(int **)malloc(row * sizeof(int **)))
 {
  int i;
  for(i=0;i<row;i++)
   p[i]=object+col*i;
  
  return p;
 }
 else
 {
  printf("no memory!/n");
  exit(1);
 }
}
       其中通过一个void *array的“通用指针”(它太强大了)负责把任意二维数组接收进来,进来后再强制转化为一个指向一维数组的指针,在根据row和col组装成一个指针数组,函数返回这个指针。有了它,确实方便多了。

       这样就可以在不用怎么修改原来针对特定二维数组所写的函数,而使他变为可以针对任意二维数组的函数。多亏了void *这个“通用指针”了,虽然一般书上都叫他“空类型指针”,但我还是觉得叫他“通用指针”更好。  
       如将一个原来输出3*3二维数组元素的函数稍作修改就变成了可以输出任意二维数组的函数了:
/* display any dimension array */
void display_array(void *array, int row, int col)
{
 int **object_array, i, j;
 object_array=deal_array(array, row, col);
 for(i=0;i<row;i++)
 {
  for(j=0;j<col;j++)
   printf("%5d ", object_array[i][j]);
  printf("/n");
 }
 printf("/n");
 free(object_array);
}


       再如: 以前只能求3*3方阵的对角线之和的函数,稍加修改就可以变成可以求任意方阵的对角线之和的函数了。
int sum(void *array, int row, int col)
{
 int **object=NULL, i, j=0, sum=0;
 object=deal_array(array, row, col);
 for(i=0;i<row;i++)
 {
  if(j==col-1-j)
   sum+=object[i][j];
  else
   sum+=object[i][j]+object[i][col-1-j];
  j++;
 }  
 return sum; 

}
在主程序中可以测试下:
int main()
{
 int a[5][5]={1,2,3,4,5,123,53,53,32,10,32,4,5,6,7,5,3,4,6,4,5,3,4,5}, b[4][4]={2,3,4,42,656,34,5,6,7,4,12,43,56,7,4};
 display_array(a,5,5);
 display_array(b,4,4);
 printf("the sum: %d/n", sum(a, 5, 5));
 printf("the sum: %d/n", sum(b, 4, 4));
 return 0;
}

这篇关于如何在c/c++中,做一个可以接收任意二维数组的函数接口,并在函数中能以下标的形式引用元素的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/703429

相关文章

C++统计函数执行时间的最佳实践

《C++统计函数执行时间的最佳实践》在软件开发过程中,性能分析是优化程序的重要环节,了解函数的执行时间分布对于识别性能瓶颈至关重要,本文将分享一个C++函数执行时间统计工具,希望对大家有所帮助... 目录前言工具特性核心设计1. 数据结构设计2. 单例模式管理器3. RAII自动计时使用方法基本用法高级用法

mybatis-plus如何根据任意字段saveOrUpdateBatch

《mybatis-plus如何根据任意字段saveOrUpdateBatch》MyBatisPlussaveOrUpdateBatch默认按主键判断操作类型,若需按其他唯一字段(如agentId、pe... 目录使用场景方法源码方法改造首先在service层定义接口service层接口实现总结使用场景my

SpringBoot实现不同接口指定上传文件大小的具体步骤

《SpringBoot实现不同接口指定上传文件大小的具体步骤》:本文主要介绍在SpringBoot中通过自定义注解、AOP拦截和配置文件实现不同接口上传文件大小限制的方法,强调需设置全局阈值远大于... 目录一  springboot实现不同接口指定文件大小1.1 思路说明1.2 工程启动说明二 具体实施2

JavaScript中比较两个数组是否有相同元素(交集)的三种常用方法

《JavaScript中比较两个数组是否有相同元素(交集)的三种常用方法》:本文主要介绍JavaScript中比较两个数组是否有相同元素(交集)的三种常用方法,每种方法结合实例代码给大家介绍的非常... 目录引言:为什么"相等"判断如此重要?方法1:使用some()+includes()(适合小数组)方法2

HTTP 与 SpringBoot 参数提交与接收协议方式

《HTTP与SpringBoot参数提交与接收协议方式》HTTP参数提交方式包括URL查询、表单、JSON/XML、路径变量、头部、Cookie、GraphQL、WebSocket和SSE,依据... 目录HTTP 协议支持多种参数提交方式,主要取决于请求方法(Method)和内容类型(Content-Ty

SpringBoot请求参数传递与接收示例详解

《SpringBoot请求参数传递与接收示例详解》本文给大家介绍SpringBoot请求参数传递与接收示例详解,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋... 目录I. 基础参数传递i.查询参数(Query Parameters)ii.路径参数(Path Va

GO语言中函数命名返回值的使用

《GO语言中函数命名返回值的使用》在Go语言中,函数可以为其返回值指定名称,这被称为命名返回值或命名返回参数,这种特性可以使代码更清晰,特别是在返回多个值时,感兴趣的可以了解一下... 目录基本语法函数命名返回特点代码示例命名特点基本语法func functionName(parameters) (nam

深入解析C++ 中std::map内存管理

《深入解析C++中std::map内存管理》文章详解C++std::map内存管理,指出clear()仅删除元素可能不释放底层内存,建议用swap()与空map交换以彻底释放,针对指针类型需手动de... 目录1️、基本清空std::map2️、使用 swap 彻底释放内存3️、map 中存储指针类型的对象

Python Counter 函数使用案例

《PythonCounter函数使用案例》Counter是collections模块中的一个类,专门用于对可迭代对象中的元素进行计数,接下来通过本文给大家介绍PythonCounter函数使用案例... 目录一、Counter函数概述二、基本使用案例(一)列表元素计数(二)字符串字符计数(三)元组计数三、C

C++ STL-string类底层实现过程

《C++STL-string类底层实现过程》本文实现了一个简易的string类,涵盖动态数组存储、深拷贝机制、迭代器支持、容量调整、字符串修改、运算符重载等功能,模拟标准string核心特性,重点强... 目录实现框架一、默认成员函数1.默认构造函数2.构造函数3.拷贝构造函数(重点)4.赋值运算符重载函数