c - 使用文件指针执行 C hangman 程序时出现分段错误
问题描述
我使用 C 编程语言制作了一个刽子手程序。它编译(gcc)没有错误,但是当我尝试执行程序(./a.out)时,它给了我分段错误。我相信这是由于使用了文件指针,因为在添加文件指针之前,它工作得非常好。添加文件指针以跟踪分数后,它一直给我分段错误。它编译(gcc)没有错误,但是当我尝试执行程序(./a.out)时,它给了我分段错误。我需要知道究竟是什么导致了分段错误。
这是我的代码的文件指针部分
// if the hero(word) was guessed correctly
if (count == strlen(words[r])) {
print_screen(words[r], answered, typed, state);
printf("Congratulation! You have guessed the hero %s correctly!\n", words[r]);
score++;
score_out_fp = fopen("ow_hangman_saved_score.data", "w"); // write
fprintf(score_out_fp, "%d", score);
fclose(score_out_fp);
sleep(3);
break;
}
// if over the threshold, break out of the loop(game over)
if (state >= 7) {
print_screen(words[r], answered, typed, state);
printf("Game over...\n");
score--;
score_out_fp = fopen("ow_hangman_saved_score.data", "w"); // write
fprintf(score_out_fp, "%d", score);
fclose(score_out_fp);
sleep(3);
break;
}
如果它不是由使用文件指针引起的,这是整个代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <termios.h>
#include <unistd.h>
char *words[32] = { "dva",
"orisa",
"reinhardt",
"roadhog",
"sigma",
"winston",
"wreckingball",
"zarya",
"ashe",
"bastion",
"doomfist",
"echo",
"genji",
"hanzo",
"junkrat",
"mccree",
"mei",
"pharah",
"reaper",
"soldier",
"sombra",
"symmetra",
"torbjorn",
"tracer",
"widowmaker",
"ana",
"baptiste",
"brigitte",
"lucio",
"mercy",
"moira",
"zenyatta"};
void hangman_state(int state)
{
if (state == 1) {
printf(" \n");
printf(" \n");
printf(" \n");
printf(" nothing \n");
printf(" happened\n");
printf(" \n");
printf(" yet... \n");
printf(" \n");
printf(" \n");
printf("6 guesses left\n");
}
else if (state == 2) {
printf(" 00 \n");
printf(" 0 0 \n");
printf(" 00 \n");
printf(" \n");
printf(" \n");
printf(" \n");
printf(" \n");
printf(" \n");
printf(" \n");
printf("5 guesses left\n");
}
else if (state == 3) {
printf(" 00 \n");
printf(" 0 0 \n");
printf(" 00 \n");
printf(" 00 \n");
printf(" 00 \n");
printf(" 00 \n");
printf(" \n");
printf(" \n");
printf(" \n");
printf("4 guesses left\n");
}
else if (state == 4) {
printf(" 00 \n");
printf(" 0 0 \n");
printf(" 00 \n");
printf(" 000 \n");
printf(" 0 00 \n");
printf(" 0 00 \n");
printf(" \n");
printf(" \n");
printf(" \n");
printf("3 guesses left\n");
}
else if (state == 5) {
printf(" 00 \n");
printf(" 0 0 \n");
printf(" 00 \n");
printf(" 0000 \n");
printf(" 0 00 0 \n");
printf(" 0 00 0 \n");
printf(" \n");
printf(" \n");
printf(" \n");
printf("2 guesses left\n");
}
else if (state == 6) {
printf(" 00 \n");
printf(" 0 0 \n");
printf(" 00 \n");
printf(" 0000 \n");
printf(" 0 00 0 \n");
printf(" 0 00 0 \n");
printf(" 0 \n");
printf(" 0 \n");
printf(" 00 \n");
printf("Final attempt\n");
}
else if (state == 7) {
printf(" 00 \n");
printf(" 0 0 \n");
printf(" 00 \n");
printf(" 0000 \n");
printf(" 0 00 0 \n");
printf(" 0 00 0 \n");
printf(" 00 \n");
printf(" 0 0 \n");
printf(" 00 00 \n");
printf("You died...\n");
}
}
// answered and typed can be replaced as int; char is used to save memory
void print_screen(char *word, char *answered, char *typed, int state)
{
system("clear");
for (int i = 0; i < strlen(word); i++) {
if (answered[i]) {
printf(" %c ", word[i]);
}
else {
printf(" _ ");
}
}
printf("\n\n");
for (int i = 0; i < 26; i++) {
if (typed[i]) {
printf(" _ ");
}
else {
printf(" %c ", 'A' + i);
}
}
printf("\n\n");
printf("-------------------------------------------------------------------------\n");
hangman_state(state);
}
void input_ch(char *key, char *word, char *answered, char *typed, int state)
{
struct termios ot, nt;
tcgetattr(STDIN_FILENO, &ot);
nt = ot;
nt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &nt);
retry:
print_screen(word, answered, typed, state);
*key = getchar();
if (*key < 'a' || *key > 'z') {
printf("Type an alphabetical character\n");
sleep(1);
goto retry;
}
if (typed[*key - 'a']) {
printf("The character has been guessed already\n");
sleep(1);
goto retry;
}
typed[*key - 'a'] = 1;
tcsetattr(STDIN_FILENO, TCSANOW, &ot);
}
int main(void) {
int r;
srand(time(0));
int state = 1;
FILE *score_in_fp = NULL; // 0
FILE *score_out_fp = NULL;
int score;
// file pointer
// "r" for read, "w" for write
score_in_fp = fopen("ow_hangman_saved_score.data", "r"); // read
// Ex) fscanf(file_pointer_variable, "string", &string);
fscanf(score_in_fp, "%d", &score);
fclose(score_in_fp);
printf("Current score: %d\n", score);
sleep(3);
// score_out_fp = fopen("ow_hangman_score.txt", "w"); // write
// fprintf(score_out_fp, "The score is %d", &score);
// fclose(score_out_fp);
while(1) {
r = rand() %32;
// guessing a character
char guess = 0;
char answered[strlen(words[r])];
char typed[26] = {0,};
memset(answered, 0x0, strlen(words[r]));
state = 1;
while(1) {
input_ch(&guess, words[r], answered, typed, state);
int hit = 0;
for (int i = 0; i < strlen(words[r]); i++) {
if (words[r][i] == guess) {
answered[i] = 1;
hit = 1;
}
}
if (!hit) {
state++;
}
int count = 0;
for (int i = 0; i < strlen(words[r]); i++) {
if (answered[i]) {
count++;
}
}
// if the hero(word) was guessed correctly
if (count == strlen(words[r])) {
print_screen(words[r], answered, typed, state);
printf("Congratulation! You have guessed the hero %s correctly!\n", words[r]);
score++;
score_out_fp = fopen("ow_hangman_saved_score.data", "w"); // write
fprintf(score_out_fp, "%d", score);
fclose(score_out_fp);
sleep(3);
break;
}
// if over the threshold, break out of the loop
if (state >= 7) {
print_screen(words[r], answered, typed, state);
printf("Game over...\n");
score--;
score_out_fp = fopen("ow_hangman_saved_score.data", "w"); // write
fprintf(score_out_fp, "%d", score);
fclose(score_out_fp);
sleep(3);
break;
}
}
}
return 0;
}
抱歉,如果我没有提供足够的信息或者我没有很好地表达我的问题。这是我第一次在堆栈溢出中提出问题。非常感谢所有试图帮助我解决这个问题的人:)
解决方案
如果没有ow_hangman_saved_score.data
当前目录中的文件,程序将崩溃,fscanf(score_in_fp, "%d", &score);
因为先前的fopen()
失败为 NULL:
score_in_fp = fopen("ow_hangman_saved_score.data", "r");
if(!score_in_fp) {
// handle error
}
您应该检查错误,但如果您想在丢失时创建一个新文件,您也可以使用“a”而不是“r”。
推荐阅读
- angular - 我是角垫形式的新手,请建议我哪个最好
或 html 引导表单字段 - c# - 如何使用 Azure AD 对同一应用程序的多个实例进行身份验证
- jquery - Bootstrap 4模式事件未触发
- json - 遍历 JSON 数据
- c# - 如何仅获取任务管理器的“应用程序”部分中的进程以及如何获取当前打开的进程?(C#)
- postgresql - 如何检查数组索引元素是否存在
- reactjs - 使用 reactjs 上传多个文件
- reactjs - 如何将 thunk 动作转换为 saga
- java - 使用 java 和 html 进行本地存储
- c# - C# .NET WinForms。Visual Studio 无法识别子文件夹中的命名空间