ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 725|回复: 12

[求助] 递归程序求助_ParamArray参数内含嵌套数组

[复制链接]

TA的精华主题

TA的得分主题

发表于 2023-8-9 16:25 | 显示全部楼层 |阅读模式
以下程序用于判断单元格批注是否包含所有的信息片段,
测试当运行到递归语句时,提示运行时错误 28: 堆栈空间不足。
程序如何修改,还望高手帮助,不胜感激!
  1. Function HasTheseCmts(TheCell As Range, ParamArray CmtArr() As Variant) As Boolean
  2.    '判断单元格批注是否包含所有的信息片段
  3.     Dim Item As Variant
  4.     Set TheCell = TheCell(1)
  5.     HasTheseCmts = False
  6.     If Not TheCell.Comment Is Nothing Then
  7.         For Each Item In CmtArr
  8.             If IsArray(Item) Then
  9.                 HasTheseCmts = HasTheseCmts(TheCell, Item) '运行时错误 28: 堆栈空间不足
  10.             Else
  11.                 If InStr(1, TheCell.Comment.Text, Item, vbTextCompare) > 0 Then
  12.                     HasTheseCmts = True
  13.                 Else
  14.                     HasTheseCmts = False
  15.                     Exit For
  16.                 End If
  17.             End If
  18.         Next
  19.     End If
  20. End Function
复制代码
  1. Sub HasTheseCmtsTest() 'B3单元格批注:"PrnMark_DblTable_Table_Fst_Bgn"
  2.     MsgBox HasTheseCmts([B3], "DblTable", "Table", "Fst", "Bgn")
  3.     MsgBox HasTheseCmts([B3], Array("DblTable", "Table", "Fst", "Bgn"))
  4.     MsgBox HasTheseCmts([B3], Array("DblTable", "Table"), Array("Fst", "Bgn"))
  5.     MsgBox HasTheseCmts([B3], "DblTable", Array("Table"), Array("Fst", "Bgn"))
  6. End Sub
复制代码


递归程序求助_ParamArray参数内含嵌套数组.zip

15.53 KB, 下载次数: 5

TA的精华主题

TA的得分主题

发表于 2023-8-9 19:18 | 显示全部楼层
进入无限递归把内存消耗光了

_ParamArray参数内含嵌套数组.zip

15.43 KB, 下载次数: 9

评分

1

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2023-8-9 21:08 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
lsarydos 发表于 2023-8-9 19:18
进入无限递归把内存消耗光了

测试完美,厉害,高手!
请问为什么加上这一句 If IsArray(CmtArr(0)) And UBound(CmtArr) = 0 Then Data = CmtArr(0) Else Data = CmtArr 就不报错了?

TA的精华主题

TA的得分主题

 楼主| 发表于 2023-8-11 07:07 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
求助ChatGPT,解释如下:
这段代码中的 If 语句用于判断传递给函数的参数 CmtArr 是否为一个数组,并且数组的元素个数是否为1。如果满足这两个条件,则将 CmtArr(0) 赋值给变量 Data;否则,将整个 CmtArr 赋值给 Data。
首先,IsArray(CmtArr(0)) 判断 CmtArr(0) 是否为一个数组。这是因为在 VBA 中,可以将一个数组作为参数传递给函数。如果 CmtArr(0) 是一个数组,则表示传递给函数的参数 CmtArr 实际上是一个包含一个数组的数组。例如,CmtArr 可能是 Array(Array("a", "b", "c"))。
接下来,UBound(CmtArr) 返回数组 CmtArr 的上界索引。如果 CmtArr 是一个一维数组且只有一个元素,则 UBound(CmtArr) 的值为 0。这是因为数组的索引从 0 开始计数。
因此,IsArray(CmtArr(0)) And UBound(CmtArr) = 0 的判断条件表示传递给函数的参数 CmtArr 是一个包含一个数组的数组,并且这个数组只有一个元素。
如果满足这个条件,那么 CmtArr(0) 就是我们想要的数组,将其赋值给变量 Data。否则,将整个 CmtArr 赋值给 Data。
这样做的目的是为了确保在递归调用 HasTheseCmts 函数时,传递给它的参数 CmtArr 始终是一个一维数组。如果不进行这个判断,而直接将整个 CmtArr 传递给递归调用,会导致递归调用的堆栈空间不断增长,最终导致运行时错误 28:堆栈空间不足。
通过将 CmtArr 转换为只包含一个元素的数组,可以确保每次递归调用时,传递给函数的参数 CmtArr 都是一个一维数组,从而避免堆栈溢出的问题。

TA的精华主题

TA的得分主题

 楼主| 发表于 2023-8-11 07:11 | 显示全部楼层
至于为什么这样做就可以确保在递归调用 HasTheseCmts 函数时,传递给它的参数 CmtArr 始终是一个一维数组?为什么如果不进行这个判断,而直接将整个 CmtArr 传递给递归调用,就会导致递归调用的堆栈空间不断增长?ChatGPT再解释如下:
当递归调用次数过多时,会导致堆栈空间的消耗过大,超过了系统所分配给程序的堆栈空间大小,就会发生堆栈溢出的错误。
在这段代码中,如果不进行判断直接将整个 CmtArr 传递给递归调用,就会导致递归调用的堆栈空间不断增长的原因是:
1. 假设 CmtArr 是一个包含多个数组的数组,例如 CmtArr = Array(Array("a", "b", "c"), Array("d", "e", "f"))。
2. 在第一次递归调用时,将整个 CmtArr 传递给函数,即 HasTheseCmts(TheCell, CmtArr)。
3. 在递归调用中,函数会遍历 CmtArr 中的每个元素,如果元素是数组,则继续递归调用 HasTheseCmts 函数。
4. 在第二次递归调用时,将第一个数组 Array("a", "b", "c") 作为参数传递给函数,即 HasTheseCmts(TheCell, Array("a", "b", "c"))。
5. 在第三次递归调用时,将第一个数组的第一个元素 "a" 作为参数传递给函数,即 HasTheseCmts(TheCell, "a")。
6. 在第四次递归调用时,将第一个数组的第一个元素的第一个字符 "a" 作为参数传递给函数,即 HasTheseCmts(TheCell, "a")。
7. 由于函数没有终止条件,递归调用会一直进行下去,导致堆栈空间不断增长,最终发生堆栈溢出的错误。
通过进行判断并将 CmtArr 转换为只包含一个元素的数组,可以避免上述情况的发生。这样做可以确保在递归调用 HasTheseCmts 函数时,传递给它的参数 CmtArr 始终是一个一维数组,而不是一个包含多个数组的数组。这样,递归调用就只会在一个维度上进行,不会无限扩展,从而避免了堆栈空间不断增长的问题。

TA的精华主题

TA的得分主题

 楼主| 发表于 2023-8-11 07:17 | 显示全部楼层
为了验证ChatGPT对数组维度的理解是否和我一样,我让它按照自己的意思,举例说明怎样才是一维数组,怎样才是二维、三维数组,它的回答如下:
当我们谈论一维、二维、三维数组时,我们实际上是在描述数组的维度。
一维数组是最简单的数组形式,它只有一个维度。它可以被视为一个线性列表,其中每个元素都可以通过一个索引来访问。例如,[1, 2, 3, 4, 5] 是一个一维数组,其中每个元素都可以通过索引来访问,例如 arr[0] 是 1,arr[1] 是 2,以此类推。
二维数组是一个具有两个维度的数组。它可以被视为一个表格或矩阵,其中每个元素都可以通过两个索引来访问。例如,[[1, 2, 3], [4, 5, 6], [7, 8, 9]] 是一个二维数组,其中每个元素都可以通过两个索引来访问,例如 arr[0][0] 是 1,arr[1][2] 是 6,以此类推。
三维数组是一个具有三个维度的数组。它可以被视为一个立体结构,其中每个元素都可以通过三个索引来访问。例如,[[[1, 2], [3, 4]], [[5, 6], [7, 8]]] 是一个三维数组,其中每个元素都可以通过三个索引来访问,例如 arr[0][1][0] 是 3,arr[1][0][1] 是 6,以此类推。
在这段代码中,为了确保递归调用的参数 CmtArr 始终是一个一维数组,我们进行了判断和转换。如果 CmtArr 是一个二维或多维数组,我们将其转换为只包含一个元素的一维数组,以便递归调用只在一个维度上进行。

TA的精华主题

TA的得分主题

发表于 2023-8-11 16:36 | 显示全部楼层
ParamArray  不限参数关键字,所以接收他的变量一定是一个数组CmtArr()  , 即使传入的是一个字符串 "abc" 也需要CmtArr(0) 来取值, 所以当你那个程序 isarray(item)  item是一个数组进行递归的时候  实际数组在CmtArr(0) 中     for each item in CmtArr   每次取出的都是CmtArr(0)中的这个数组  也就是一个死循环,最后结果就是内存消耗光,这种情况只出现在最后一层数组的时候,所以做个判断  如果item是数组 且CmtArr中只有一个结果时  将CmtArr中的数组取出循环即可 , 你原来的递归也没有一个退出条件

评分

1

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2023-8-11 19:23 | 显示全部楼层
lsarydos 发表于 2023-8-11 16:36
ParamArray  不限参数关键字,所以接收他的变量一定是一个数组CmtArr()  , 即使传入的是一个字符串 "abc" 也 ...

谢谢!您的解释对于 ([B3], Array("DblTable", "Table", "Fst", "Bgn")) 这种情况我明白,但对于 ([B3], Array("DblTable", "Table"), Array("Fst", "Bgn")) 这种情况我还是不明白。能不能麻烦您再解释一下,非常感谢!

TA的精华主题

TA的得分主题

发表于 2023-8-11 19:39 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
makelot 发表于 2023-8-11 19:23
谢谢!您的解释对于 (, Array("DblTable", "Table", "Fst", "Bgn")) 这种情况我明白,但对于 (, Array("D ...

([B3], Array("DblTable", "Table"), Array("Fst", "Bgn"))
按你原来没做判断的情况   cmtarr = {Array("DblTable", "Table"), Array("Fst", "Bgn")}  进入递归  cmtarr = {Array("DblTable", "Table")}  cmtarr(0)才是Array("DblTable", "Table")这个数组  没取值的话 item in cmtarr 的这个item 变量永远 = Array("DblTable", "Table")这个数组 所以会无限递归

做了判断的情况: cmtarr = {Array("DblTable", "Table"), Array("Fst", "Bgn")}  判断 cmtarr(0)是数组但下标为1则为假   data = {Array("DblTable", "Table"), Array("Fst", "Bgn")}    item = Array("DblTable", "Table") 进入递归 cmtarr = {Array("DblTable", "Table")} 再次判断是数组下标为0  data = Array("DblTable", "Table") 去掉一层数组  item = "DblTable"

这个是因为ParamArray会把参数自动放入一个数组中引起的,传入一个数组相当于数组又套了一个数组 需要处理一下,不使用这个关键字不会出现这个情况

评分

1

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2023-8-11 20:18 | 显示全部楼层
lsarydos 发表于 2023-8-11 19:39
(, Array("DblTable", "Table"), Array("Fst", "Bgn"))
按你原来没做判断的情况   cmtarr = {Array("Dbl ...

谢谢!抱歉还得问您一次,下面这个程序为什么不用考虑剥皮的情况呢?
  1. Sub Main()
  2.     Dim nestedArray As Variant
  3.     nestedArray = Array(Array(), 1, Array(2, Array(3, 4), 5), Array(6, 7, Array(8, 9, Array(10))))
  4.     ListAllElements nestedArray
  5. End Sub
复制代码
  1. Sub ListAllElements(arrayTmp As Variant)
  2.     Dim Item As Variant
  3.     For Each Item In arrayTmp
  4.         If IsArray(Item) Then
  5.             ListAllElements Item
  6.         Else
  7.             Debug.Print Item;
  8.         End If
  9.     Next Item
  10. End Sub
复制代码
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-11-1 09:27 , Processed in 0.045948 second(s), 10 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表