You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

数组元素随机交换栈溢出问题:为何仅能加小于3的数?

关于数组随机交换时索引越界的问题解析

嘿,我来帮你拆解这个问题的根源~

首先,你写的应该是Fisher-Yates洗牌算法的实现,原本的int j = rand() % (i+1);是这个算法的正确写法——它保证处理第i个元素时(假设数组索引从0开始),j的取值范围是0到i,完全在数组的有效索引范围内,不会出问题。

为什么换成i+3及更大值会触发栈溢出?

问题核心是数组索引越界:
当你把i+1换成i+3时,j的取值范围变成了0到i+2。假设你的数组长度是n,数组的有效索引是0到n-1。当循环执行到最后几个元素时(比如i = n-1,也就是数组的最后一个元素),i+2 = (n-1)+2 = n+1,这时候rand()有可能生成n或n+1这样的数值,而array[n]、array[n+1]已经超出了数组分配的内存区域。

数组通常在栈上分配内存,越界访问会覆盖栈上的关键数据(比如函数返回地址、栈帧保护信息),现代编译器(比如GCC)默认开启的栈保护机制(-fstack-protector)一旦检测到栈数据被非法修改,就会触发*** stack smashing detected ***的错误并终止程序。

为什么换成i或i+2有时能运行?

这其实只是“运气好”,本质上依然是错误的:

  • 换成i时,j的范围是0到i-1,不会超出数组有效索引(i最大为n-1,i-1就是n-2,在合法范围内),所以不会触发栈溢出,但这会破坏洗牌的均匀性——每个元素被交换到当前位置的概率不再相等,洗牌结果存在偏差。
  • 换成i+2时,虽然存在越界可能,但rand()不一定每次都会生成超过n-1的数值。如果某次运行中j始终在合法索引范围内,程序就能正常输出;但只要有一次j越界,就会触发错误,属于“偶发故障”。

举个具体例子

假设你的数组是int arr[5];(长度为5,有效索引0-4):

  • 当i=4(处理最后一个元素):
    • 原写法i+1=5,j范围0-4,完全合法;
    • 换成i+3=7,j可能取5、6,此时访问arr[5]、arr[6]属于非法内存访问,直接触发栈保护机制。

总结

  • 核心问题是索引越界访问非法内存,使用i+3及更大值时,循环后期必然会出现超出数组范围的j值;
  • i和i+2的写法要么逻辑错误,要么存在潜在越界风险,都不是正确实现;
  • 要保证程序正确且安全,还是要使用原本的rand() % (i+1),确保j始终落在数组的合法索引范围内。

内容的提问来源于stack exchange,提问作者VH97

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 08:12:46