【问题标题】:Displaying structs显示结构
【发布时间】:2017-12-16 05:25:44
【问题描述】:

该程序旨在根据用户的输入显示视频游戏库存。用户需要使用 num_of_games 确定循环运行多长时间。我们必须使用切换循环来确定类型。它可以编译,但无法正确显示。

#include <stdio.h>
#include <string.h>
#define MAX 16

typedef enum genre_type{ action = 0, rpg = 1, simulation = 2, 
                        strategy = 3, sports = 4} genre_t;

typedef struct{
    char title[MAX];
    int num_sold;
    genre_t genre;
}game_s;
// suppose to use functions and enum list for determining the genre
void get_game_info(game_s *ptr);
void display_inventory(game_s game[], int num_of_games);


int
main(void){

    int i=0, num_of_games;
    int c_game=0;
    game_s game[num_of_games];

    printf("How many games are there in inventory? ");
    scanf("%d", &num_of_games);
    fflush(stdin);
    printf("\n");
    while(c_game < num_of_games){
        printf("\n");
        get_game_info(&game[c_game]);
        c_game++;
    }
    printf("\n");
    display_inventory(game, num_of_games);


    return(0);
}
void get_game_info(game_s *ptr)
{       
        int i, str_len, genre, num_sold;

        printf("Title of game <maximum of 15 characters>: ");
        gets(ptr->title);
        str_len = strlen(ptr->title);
            if(str_len >= 15){
                printf("Title will be truncated\n");
                ptr->title[MAX]= '\0';
            }
        printf("Number sold: ");
        scanf("%d", &ptr->num_sold);
        fflush(stdin);
        printf("Genre (0-action, 1-rpg, 2-simulation, 3-strategy, 4-sports): ");
        scanf("%d", &ptr->genre);
        fflush(stdin);
            if(ptr->genre>4){
                printf("Not a valid genre");
        fflush(stdin);  
}
}
void display_inventory(game_s game[], int num_of_games)
{   
    int i, genre;

    printf("Title\t\t\t\t\t\tQuantity Sold\t\t\t\t\t\tGenre");
    printf("\n=====\t\t\t\t\t\t=============\t\t\t\t\t\t=====\n");
    for(i=0; i < num_of_games; i++){
    switch(genre){
        case action: printf("Action"); break;
        case rpg: printf("RPG"); break;
        case simulation: printf("Simulation"); break;
        case strategy: printf("Strategy"); break;
        case sports: printf("Sports"); break;
        default: puts("Not a choice. Try again"); break;

我认为这是导致大部分问题的原因。我不知道我是否在 game[I].title 和其他人中调用了该结构。 问题出在我认为的结构调用上。如果我使用 game_s[I].title 我得到“预期的表达式之前”错误,如果我使用 game[I].title 它不能正确打印

    printf("%s\t\t\t\t\t\t%d\t\t\t\t\t\t%s", game[i].title, game[i].num_sold, game[i].genre);
    printf("\n");
    }
    }
}

【问题讨论】:

  • fflush(stdin); 为什么?你是从哪里弄来的?
  • geeksforgeeks.org/use-fflushstdin-c 可能会有所启发。 man7.org/linux/man-pages/man3/fflush.3.html 也是。简而言之,fflush() 用于刷新输出。你不能刷新输入;你正在接收它(所以它会在 它被刷新到 你之后)。微软重载它来做其他事情。
  • gets 不好。考虑避开此功能。
  • @DanFarrell,我认为这里的问题远远超出fflush(并不是说这不是问题)
  • @Brauer - 好吧,这对game[num_of_games] 没有好处,是吗?见 How to debug small programs 并与鸭子交谈......真的,它有帮助 :)

标签: c struct


【解决方案1】:

我认为问题出在game_s game[num_of_games];,因为num_of_games 没有启动。

应该是:

printf("How many games are there in inventory? ");
scanf("%d", &num_of_games);
game_s * game_s game = (game_s *) malloc(num_of_games * sizeof(game_s));

【讨论】:

    【解决方案2】:

    你的努力值得称赞。您提供代码并善意地尝试理解为什么事情不起作用,但不幸的是,您的代码充满了错误。其中最重要的一点是您几乎立即调用 Undefined Behavior,尝试使用未初始化的 num_of_games 声明 VLA。从那时起,无论您在代码中做了什么,无论您是实际处理了某些东西还是 SegFaulted,都只是掷骰子。

    display_inventory 中缺少输出(无论内存中实际存在什么)是由于将printf 语句放置在switch 语句的主体中。当您从switch 中选择break 时,您不仅会跳到default 的下方,还可以完全跳出switch。所以即使你的其余代码是正确的,你也永远不会产生输出。

    fflush(stdin) 是错误的,它会在除windoze 之外的所有对象上调用未定义的行为。它只为世界其他地方的 seekable 流定义——不要使用它。相反,您可以定义一个简单的函数来清空stdin,然后根据需要调用它。

    编译时,请始终在启用编译器警告的情况下进行编译,并且不要接受代码,直到它在没有警告的情况下干净地编译。要启用警告,请将 -Wall -Wextra 添加到您的 gcc 编译字符串中。 (添加-pedantic 以获得其他几个警告)。对于 VS(windoze 上的cl.exe),添加/Wall。对于clang,添加-Weverything。阅读并理解每个警告。他们将识别任何问题,以及它们发生的确切线路。您可以通过聆听编译器告诉您的内容来尽可能多地了解编码。

    您的代码中的错误数量过多,无法逐项列出并说明每一点,因此我在下面包含了 cmets inline 来解决这些错误。

    #include <stdio.h>
    #include <stdlib.h>     /* for EXIT_FAILURE */
    #include <string.h>
    
    #define MAX 16
    
    typedef enum genre_type { 
        action = 0, 
        rpg = 1, 
        simulation = 2,
        strategy = 3, 
        sports = 4
    } genre_t;
    
    typedef struct {
        char title[MAX];
        int num_sold;
        genre_t genre;
    } game_s;
    
    // suppose to use functions and enum list for determining the genre
    void get_game_info (game_s *ptr);
    void display_inventory (game_s *game, int num_of_games);
    void fflush_stdin();
    
    int main (void) {
    
        int num_of_games,
            c_game = 0,
            scnfrtn;        /* scanf return - must always check EOF */
    
        printf ("How many games are there in inventory? ");
        for (;;) {  /* loop until valid input or EOF (user cancels) */
            if ((scnfrtn = scanf ("%d", &num_of_games)) == 1) {
                fflush_stdin(); /* manually empty stdin */
                break;
            }
            else if (scnfrtn == EOF) {  /* user cancels? */
                fprintf (stderr, "user canceled input.\n");
                exit (EXIT_FAILURE);
            }
            /* handle error */
            fprintf (stderr, "error: invalid input.\n");
            fflush_stdin();
        }
        putchar ('\n');             /* don't printf a single-char */
    
        /* declare VLA only AFTER num_of_games has a value */
        game_s game[num_of_games];
        memset (game, 0, sizeof game);  /* optional, zero VLA */
    
        while (c_game < num_of_games) {
            putchar ('\n');
            get_game_info (&game[c_game]);
            c_game++;
        }
        putchar ('\n');
    
        display_inventory (game, num_of_games);
    
        return 0;
    }
    
    void get_game_info (game_s *ptr)
    {
        int scnfrtn;        /* scanf return - must always check EOF */
        size_t len = 0;     /* strlen return is size_t */
    
        printf ("Title of game <maximum of 15 characters>: ");
        fgets (ptr->title, MAX, stdin); /* NEVER, NEVER, NEVER use gets */
        len = strlen (ptr->title);
        if (len && ptr->title[len-1] == '\n')   /* check for trailing \n */
            ptr->title[--len] = '\0';    /* overwrite with nul-character */
        else    /* warn of truncation */
            fprintf (stderr, "error: title too long, truncated.\n");
    
        for (;;) {  /* loop until valid input or EOF (user cancels) */
            printf ("Number sold: ");
            if ((scnfrtn = scanf ("%d", &ptr->num_sold)) == 1) {
                fflush_stdin();
                break;
            }
            else if (scnfrtn == EOF) {
                fprintf (stderr, "user canceled input.\n");
                exit (EXIT_FAILURE);
            }
            fprintf (stderr, "error: invalid input.\n");
            fflush_stdin();
        }
    
        for (;;) {  /* loop until valid input or EOF (user cancels) */
            printf ("Genre (0-action, 1-rpg, 2-simulation, "
                    "3-strategy, 4-sports): ");
            if ((scnfrtn = scanf ("%d", (int*)&ptr->genre)) == 1) {
                fflush_stdin();
                break;        
            }
            else if (scnfrtn == EOF) {
                fprintf (stderr, "user canceled input.\n");
                exit (EXIT_FAILURE);
            }
            else if (ptr->genre > 4)    /* additional check for genre */
                fprintf (stderr, "error: invalid genre.\n");
            else
                fprintf (stderr, "error: invalid input.\n");
    
            fflush_stdin();
        }
    }
    
    void display_inventory (game_s *game, int num_of_games)
    {
        int i;
    
        printf ("%11s%-24s %-24s %s\n========================="
                "==============================================\n", 
                " ", "Title","Quantity Sold", "Genre");
        for (i = 0; i < num_of_games; i++) {
            switch (game[i].genre) {
                case action:
                    printf ("%-11s", "Action");
                    break;
                case rpg:
                    printf ("%-11s", "RPG");
                    break;
                case simulation:
                    printf ("%-11s", "Simulation");
                    break;
                case strategy:
                    printf ("%-11s", "Strategy");
                    break;
                case sports:
                    printf ("%-11s", "Sports");
                    break;
                default:
                    puts ("Not a choice. Try again");
                    break;
            }
            printf ("%-24s %-24u %d\n", game[i].title,
                    game[i].num_sold, game[i].genre);
        }
    }
    
    void fflush_stdin()
    {
        for (int c = getchar(); c != '\n' && c != EOF; c = getchar()) {}
    }
    

    注意:使用printf 修饰符的最小字段来控制间距,而不是一堆tabs混在一起)

    使用/输出示例

    $ ./bin/gamegenre
    How many games are there in inventory? 3
    
    
    Title of game <maximum of 15 characters>: first title
    Number sold: 12
    Genre (0-action, 1-rpg, 2-simulation, 3-strategy, 4-sports): 2
    
    Title of game <maximum of 15 characters>: second title
    Number sold: 13
    Genre (0-action, 1-rpg, 2-simulation, 3-strategy, 4-sports): 1
    
    Title of game <maximum of 15 characters>: third title
    Number sold: 14
    Genre (0-action, 1-rpg, 2-simulation, 3-strategy, 4-sports): 3
    
               Title                    Quantity Sold            Genre
    =======================================================================
    Simulation first title              12                       2
    RPG        second title             13                       1
    Strategy   third title              14                       3
    

    注意:我不知道你打算把你的genre描述放在哪里,所以它们只是在上面每一行的开头输出)

    查看一下,如果您还有其他问题,请告诉我。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-11-04
      • 2011-04-09
      • 2015-03-09
      • 1970-01-01
      • 1970-01-01
      • 2015-11-28
      • 2017-04-18
      • 2012-09-19
      相关资源
      最近更新 更多