首页 > 解决方案 > 使用文件指针执行 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;
}

抱歉,如果我没有提供足够的信息或者我没有很好地表达我的问题。这是我第一次在堆栈溢出中提出问题。非常感谢所有试图帮助我解决这个问题的人:)

标签: c

解决方案


如果没有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”。


推荐阅读