向函数传递指针时触发Segmentation fault的问题排查与修复
咱们来一步步拆解你代码里导致Segmentation fault和逻辑问题的关键点,帮你把程序跑起来:
核心问题与修复步骤
1. 函数参数必须明确声明类型
你的所有函数都用了老式的隐式参数声明(比如int printQuestion(output,filePointer)),这种写法在现代C标准里已经被废弃,编译器无法正确推断参数类型,会埋下内存访问的隐患。必须给每个参数加上明确的类型,比如int printQuestion(char output[], FILE* filePointer)。
2. scanf/fscanf传参错误(直接触发段错误)
这是你遇到段错误的最直接原因:scanf和fscanf要求传入变量的**地址(指针)**来存储读取的值,但你直接传了变量本身。比如:
- 错误写法:
fscanf(filePointer, "%c", actualAnswer1); - 正确写法:
fscanf(filePointer, "%c", &actualAnswer1);
当你直接传变量值时,函数会把这个值当作内存地址去写入,而这个地址几乎肯定是非法的,直接触发段错误。同理,getUserInput里的scanf("%c",userInput);也要改成scanf("%c", &userInput);。
3. 文件指针位置偏移导致逻辑错误
在printQuestion函数里,你用fgets循环读取到了文件末尾,这会让文件指针直接跳到文件结尾。之后调用getactualAnswerX时,fgets会立刻返回NULL,根本读不到你想要的第6-9行内容。解决办法是在读取问题后,用fseek(filePointer, 0, SEEK_SET);把文件指针重置到开头,再去读取答案。
4. getactualAnswerX的逻辑与内存问题
- 函数里的
actualAnswer1-4是局部变量,而且循环逻辑混乱:比如当传入a=6时,循环从i=6开始,但之前的fgets已经读了一行,会跳过你要读取的字符。 - 你在
getactualAnswerX里调用了fclose(filePointer),但主函数里后续可能还要使用这个文件指针,这会导致后续操作访问已经关闭的文件,引发未定义行为。应该把fclose放在主函数的最后,所有文件操作完成后再执行。
5. checkIfPointerIsNull的返回值问题
当文件指针不为空时,这个函数没有明确的返回值,会导致调用者得到随机的返回值,引发未定义行为。需要在函数末尾加上return 0;表示正常。
修复后的完整代码示例
#include <stdio.h> #include <stdlib.h> // 提前声明函数原型,避免隐式声明 int checkIfPointerIsNull(FILE* filePointer); int printQuestion(char output[], FILE* filePointer); char getactualAnswerX(int targetLine, char output[], FILE* filePointer); char getUserInput(const char* word); int main() { const char* fileName = "your_question_file.txt"; // 替换成你的实际文件名 FILE* filePointer = fopen(fileName, "r"); // 检查文件是否打开成功,失败则退出 if (checkIfPointerIsNull(filePointer) != 0) { return 1; } char output[256]; printQuestion(output, filePointer); // 重置文件指针到开头,准备读取答案 fseek(filePointer, 0, SEEK_SET); char actualAnswer1 = getactualAnswerX(6, output, filePointer); char actualAnswer2 = getactualAnswerX(7, output, filePointer); char actualAnswer3 = getactualAnswerX(8, output, filePointer); char actualAnswer4 = getactualAnswerX(9, output, filePointer); char userAnswer = getUserInput("your answer"); // 所有文件操作完成后关闭文件 fclose(filePointer); return 0; } int checkIfPointerIsNull(FILE* filePointer) { if(filePointer == NULL) { printf("Can't load questions\n"); return 1; } return 0; // 正常返回0 } int printQuestion(char output[], FILE* filePointer) { int i, j; j = rand() % 4; // 假设你的getRandomNumber是用rand实现的,若自定义需补充 // 先跳过前j行 fseek(filePointer, 0, SEEK_SET); for(i = 0; i < j; i++) { if(fgets(output, sizeof(output), filePointer) == NULL) break; } // 打印接下来的6行问题 for(i = j; i < j + 6; i++) { if(fgets(output, sizeof(output), filePointer) == NULL) break; printf("%02d: %s", i, output); // 用%s打印字符串,原代码的%c是错误的 } return 0; } char getactualAnswerX(int targetLine, char output[], FILE* filePointer) { int currentLine = 0; char answer = '\0'; // 重置文件指针到开头,定位到目标行 fseek(filePointer, 0, SEEK_SET); while(currentLine < targetLine) { if(fgets(output, sizeof(output), filePointer) == NULL) break; currentLine++; } // 读取目标行的字符 if(currentLine == targetLine) { fscanf(filePointer, "%c", &answer); } return answer; } char getUserInput(const char* word) { char userInput; printf("Input %s: ", word); // 处理输入缓冲区残留的换行符(可选但建议) while(getchar() != '\n'); scanf("%c", &userInput); return userInput; }
内容的提问来源于stack exchange,提问作者z5678
相关产品推荐
相关产品推荐

