C语言学习笔记20260701-环形数组移动与随机数生成
C语言学习笔记20260701-环形数组移动与随机数生成1. 项目背景本题是一个经典的模拟算法问题。我们需要模拟一个角色旺仔哥哥在一个由NNN个小朋友组成的圆圈中移动的过程。输入一组代表步数的数字序列、移动次数MMM、移动方向0为逆时针1为顺时针输出最终停留位置的小朋友编号1~N难点处理圆环的边界溢出取模运算以及负数索引的处理2. 核心知识点解析2.1 环形移动的数学模型在计算机中数组是线性的0 到 N-1而题目是环形的。我们需要利用**取模运算%**来实现转圈的效果。假设当前下标为cur步数为step数组长度为sz顺时针移动下标增加直接相加并取模cur(curstep)%sz;逆时针移动下标减小C语言中负数取模可能得到负数例如-1 % 5结果为-1这会导致数组越界。必须加上一个周期sz再取模将其转化为正数索引// 标准公式(当前 - 步数 总长) % 总长cur(cur-step%szsz)%sz;2.2 常见陷阱与避坑指南**sizeof**** 的误区**sizeof(arr)返回的是字节数。对于int arr[10]结果是 40假设 int 占 4 字节正确获取元素个数int sz sizeof(arr) / sizeof(arr[0]);状态保持在for循环模拟移动时千万不要在循环内部重置当前位置cur必须在循环外初始化并在循环内不断更新代表上一步结束时的位置随机数种子使用srand((unsigned int)time(NULL))确保每次运行程序生成的随机序列不同3. 完整修正代码#define_CRT_SECURE_NO_WARNINGS#includestdio.h#includestdlib.h// rand, srand#includetime.h// time/** * brief 计算旺仔哥哥最终停留的位置 * param arr 小朋友衣服上的数字数组 * param sz 数组长度小朋友人数 * param m 移动次数 * param dir 移动方向 (0: 逆时针, 1: 顺时针) * return 最终停留的小朋友编号 (1 ~ sz) */intstopAtWho(intarr[],intsz,intm,intdir){// 初始站在第1个小朋友旁边对应数组下标 0intcur0;for(inti0;im;i){// 1. 获取当前站立位置的数字作为本次移动的步数intsteparr[cur];// 2. 根据方向计算新位置if(dir1){// 顺时针下标增加// 注意step 可能很大先 % sz 优化性能可选cur(curstep)%sz;}else{// 逆时针下标减小// 核心技巧 sz 防止负数取模出错cur(cur-(step%sz)sz)%sz;}}// 题目要求返回编号1开始数组下标是0开始所以 1returncur1;}intmain(){intarr[10]{0};// --- 1. 随机生成数据 ---srand((unsignedint)time(NULL));printf(生成的随机数字序列: );for(inti0;i10;i){// 生成 1~100 之间的随机数arr[i]rand()%1001;printf(%d ,arr[i]);}printf(\n);// --- 2. 获取用户输入 ---intm0,n0;// 计算数组实际元素个数而不是字节数intszsizeof(arr)/sizeof(arr[0]);printf(请输入移动次数 m 和方向 n (0逆/1顺): );if(scanf(%d %d,m,n)!2){printf(输入格式错误\n);return1;}// --- 3. 调用函数并输出结果 ---// 将方向参数 n 传入函数intresultstopAtWho(arr,sz,m,n);printf(旺仔哥哥最后停在第 %d 号小朋友旁边\n,result);return0;}4. 学习总结通过这个练习我们掌握了三个重要的编程技能环形缓冲区思想利用取模运算将线性数组首尾相接防御性编程在处理减法取模时习惯性加上模数 sz以防止负数溢出调试思维学会区分循环计数器i和业务状态变量cur这是新手最容易犯的逻辑错误之一5. 常见问题解答Q1: 为什么需要(step % sz)而不是直接用stepA: 当步数step大于数组长度sz时step % sz可以避免不必要的完整循环提高效率。例如在长度为5的数组中走7步等价于走2步。Q2: 为什么逆时针移动要加szA: C语言中负数取模的结果可能是负数如-2 % 5 -2而数组下标不能为负。通过 sz将结果调整到[0, sz-1]范围内。Q3: 如何验证代码正确性A: 可以用简单的测试用例手动验证数组[2,1,4,5,2,3]m3顺时针初始位置1号下标0第1步走2步 → 3号下标2第2步走4步 → 1号下标0第3步走2步 → 3号下标2结果3号小朋友