将二维数组实现的C语言房间移动程序拆分函数时遇错求助
解决你的C语言二维数组移动程序的函数拆分问题
首先,咱们先搞定你遇到的编译错误和核心逻辑问题,再一步步拆解C语言中数组与函数协作的关键知识点:
1. 编译错误的直接原因:参数声明与数组传递不规范
你看到的subscripted value is neither array nor pointer nor vector错误,主要来自这两个问题:
- 你的
runter函数参数没有声明类型(比如roomxy、y这些参数),现代C语言要求必须显式指定参数类型,编译器根本不知道roomxy是数组,自然无法用下标访问。 - 二维数组作为函数参数时,不能只写
int roomxy[][],必须指定第二维的大小(比如int roomxy[4][4]),或者用指向一维数组的指针int (*roomxy)[4]——因为C语言中二维数组传参时会退化为指向其第一行的指针,编译器需要知道每行的元素个数才能计算内存偏移。
2. 核心逻辑错误:数组不能被赋值,函数返回值混乱
你在main里写的room = runter(room, ypos, xpos, i);完全不符合C语言规则:
- 数组名
room是常量指针,不能被赋值(就像你不能写int a[5]; a = b;一样)。 - 你的
runter函数一会儿返回index(步数修正值),一会儿返回数组元素值,返回值的意义完全混乱,违背了函数单一职责的设计原则。
3. 修正后的完整代码示例
我帮你重构了代码,修复了所有错误,同时用函数拆分了各个移动逻辑,还添加了typedef的使用示例:
#include <stdio.h> // 用typedef简化二维数组类型声明,后续可以直接用Room代替int[4][4] typedef int Room[4][4]; void instruction(void) { printf("Move: W=up, D=right, S=down, A=left and apply with RETURN.\n"); } void wall(void) { printf("##### You are in front of a wall. Please move somewhere else! #####\n"); } // 向下移动函数:传入房间数组、坐标指针(要修改主函数里的坐标,必须传指针)、当前步数索引 int moveDown(Room room, int *ypos, int *xpos, int index) { room[*ypos][*xpos] = 0; // 清除当前位置 (*ypos)++; // 尝试向下移动 // 检查是否越界 if (*ypos > 3 || *ypos < 0) { (*ypos)--; // 越界则回退 wall(); return index - 1; // 步数减一,因为这次移动无效 } room[*ypos][*xpos] = 1; // 标记新位置 return index; // 移动有效,返回原步数 } // 向上移动函数 int moveUp(Room room, int *ypos, int *xpos, int index) { room[*ypos][*xpos] = 0; (*ypos)--; if (*ypos > 3 || *ypos < 0) { (*ypos)++; wall(); return index - 1; } room[*ypos][*xpos] = 1; return index; } // 向右移动函数 int moveRight(Room room, int *ypos, int *xpos, int index) { room[*ypos][*xpos] = 0; (*xpos)++; if (*xpos > 3 || *xpos < 0) { (*xpos)--; wall(); return index - 1; } room[*ypos][*xpos] = 1; return index; } // 向左移动函数 int moveLeft(Room room, int *ypos, int *xpos, int index) { room[*ypos][*xpos] = 0; (*xpos)--; if (*xpos > 3 || *xpos < 0) { (*xpos)++; wall(); return index - 1; } room[*ypos][*xpos] = 1; return index; } // 打印房间状态的复用函数 void printRoom(Room room) { printf("Your Position:\n"); for(int j=0; j<4; j++) { for(int k=0; k<4; k++) { printf("%d ", room[j][k]); } printf("\n"); } } // 标准main函数写法(C语言标准要求返回int) int main(void) { char c[2]; int steps; int i; Room room = {0}; // 用typedef简化数组声明 int ypos = 0; int xpos = 0; room[ypos][xpos] = 1; // 初始化起点 // 打印初始房间状态 printRoom(room); printf("How many steps do you want to make? (Number from 1 to 50.)\n"); scanf("%d", &steps); if (steps > 0 && steps < 51) { for (i=1; i<=steps; ) { instruction(); scanf("%1s", c); // 限制输入长度,避免数组溢出 switch(c[0]) { case 'S': case 's': i = moveDown(room, &ypos, &xpos, i); break; case 'W': case 'w': i = moveUp(room, &ypos, &xpos, i); break; case 'D': case 'd': i = moveRight(room, &ypos, &xpos, i); break; case 'A': case 'a': i = moveLeft(room, &ypos, &xpos, i); break; default: printf("##### ERROR: Only type in W, D, S or A! #####\n"); i--; break; } printRoom(room); } } else { printf("##### Please enter number from 1 to 50! #####\n"); } return 0; }
4. 关键知识点解释
(1)C语言数组与函数的协作规则
- 一维数组传参时,会退化为指向第一个元素的指针,比如
void func(int arr[])等价于void func(int *arr)。 - 二维数组传参必须指定第二维大小,比如
void func(int arr[4][4]),或者用指向一维数组的指针void func(int (*arr)[4]),编译器需要这个信息来计算元素的内存位置。 - 如果要在函数里修改主函数的变量(比如ypos、xpos),必须传递变量的指针,否则只是传递值的副本,函数内的修改不会影响主函数。
(2)typedef的用法
我用typedef int Room[4][4];给int[4][4]这个二维数组类型起了别名Room,这样以后声明房间数组时,直接写Room room;就可以了,不用重复写int room[4][4];。如果以后要把房间改成5x5,只需要修改typedef的定义,所有用到Room的地方都会自动更新,非常方便。
5. 其他小问题修复
- 把非标准的
void main()改成了符合C标准的int main(void)。 - 修复了W方向移动时重复调用
wall()和错误修改ypos的逻辑。 - 用
scanf("%1s", c)限制输入长度,避免char[2]数组溢出。 - 把打印房间的逻辑抽成独立函数,减少代码重复。
内容的提问来源于stack exchange,提问作者J.W.
相关产品推荐
相关产品推荐

