C语言结构体传参输出乱码及VSCode调试方法咨询
问题说明
- C语言课程作业故障:选择
Visualizar platos del dia选项时程序输出乱码,无法显示通过cargar函数录入的菜品内容 - 运行环境:Manjaro系统 + Visual Studio Code
- 附加需求:需要VS Code下C语言程序的调试操作指引
故障原因
核心问题是C语言函数默认使用值传递逻辑:你在main函数中定义struct platos plato变量后,直接将该结构体作为参数传入cargar、vis、emit函数时,函数内部接收到的是原结构体的独立临时拷贝。cargar函数中所有读取输入写入结构体的操作,修改的都是这个临时副本,函数执行完毕后临时副本会被直接销毁,main函数中的原始plato变量从未被写入有效数据,内存中留存的是未初始化的栈空间随机值,输出时就会显示乱码。
代码中还存在3处可优化的隐患:
- 使用了已被C标准正式废弃移除的
gets()函数,该函数不校验输入长度,极易触发缓冲区溢出 - 使用了glibc专属的非标准函数
__fpurge(stdin),跨编译器、跨平台兼容性极差 cargar函数中录入第三个饮品的提示文本错误,重复显示Ingrese bebida 2
修复方案
将三个功能函数的参数改为传结构体指针,通过内存地址直接修改main函数中的原始结构体变量,同时替换不安全的输入逻辑:
- 修改函数声明,需要写入内容的
cargar用普通结构体指针,只读展示的vis、emit用const修饰的结构体指针:
void cargar(struct platos *a); void vis(const struct platos *a); void emit(const struct platos *a);
- 修改main函数中的调用逻辑,传入结构体的内存地址:
switch(a){ case 1: cargar(&plato); break; case 2: vis(&plato); break; case 3: emit(&plato); break; case 4: b++; break; }
- 修改三个函数的实现,指针访问结构体成员使用
->运算符,替换不安全的输入方法:
- 删除所有
__fpurge(stdin)调用,在每次scanf读取完菜单选项后,用如下逻辑清空输入缓冲区残留的换行符:
int tmp; while((tmp = getchar()) != '\n' && tmp != EOF);
- 将所有
gets()调用替换为更安全的fgets(),以读取开胃菜为例:
printf("Ingrese aperitivo\n"); fgets(a->aperitivo, sizeof(a->aperitivo), stdin); // 去掉fgets读入的末尾换行符 a->aperitivo[strcspn(a->aperitivo, "\n")] = '\0';
- 修正
cargar函数中第三个饮品的提示文本为Ingrese bebida 3 - 函数内所有原
a.成员名的写法,统一替换为a->成员名
Manjaro环境下VS Code调试C程序步骤
- 先安装基础编译调试依赖,终端执行命令:
sudo pacman -S base-devel gdb,完成gcc编译链、gdb调试器的安装 - 打开VS Code,安装微软官方提供的C/C++扩展
- 打开存放代码的文件夹,点击左侧边栏「运行和调试」按钮,选择「创建launch.json文件」,依次选择
C++(GDB/LLDB)、gcc生成默认配置 - 调整生成的配置文件:将
program字段值设为${fileDirname}/${fileBasenameNoExtension},确认编译任务preLaunchTask关联的gcc编译参数包含-g(该参数会让编译出的程序携带调试信息,是调试的必要条件) - 调试操作:在需要暂停观察的代码行号左侧点击,打上红色断点,按F5即可启动调试。调试时左侧面板可实时查看所有变量的当前值,顶部控制栏可实现单步执行、步入函数、步出函数、继续运行等操作,可以逐行观察
cargar执行过程中结构体成员的写入情况,快速定位逻辑问题。
内容的提问来源于stack exchange,提问作者Thaiel Anaya
相关产品推荐
相关产品推荐

