【问题标题】:Struct Array printed the last elementStruct Array 打印最后一个元素
【发布时间】:2020-11-24 17:45:44
【问题描述】:

我想打印输入中所有输入的元素。但是,代码打印了最近输入的代码。我希望程序打印输入到 Struct 数组中的每个输入。我尝试切换到gets和fgets,输出仍然显示相同的结果。因此,我无法弄清楚如何让程序打印所有来自用户的给定输入。

以下是我的代码:

#include <stdio.h>
#include <stdlib.h>
#define MAX 1
struct Number
{
    char name[100];
};
void read(struct Number *data);
void show(struct Number *data);

int main()
{
    int i, j;
    struct Number data[MAX];
    int option; 

printf("Choose 1 to Read data or Choose 2 to Show Data");
do
    { printf(" \nChoose ");
        scanf("%d", &option);

if(option==1)
    {
    read(data);
    }
else if(option==2)
 {
    show(data);
 }
else 
    {
        printf("Error! \n");
    }
}
while(1);
}
    
 

void show(struct Number *data)
{
    int i;
    for (i=0; i<MAX; i++)
    {
        printf("%s \n", data[i].name);
    }
}
void read(struct Number *data)
{
        int j;
    for (j=0; j<MAX; j++)
    {
      printf("Name: ");
        scanf("%s", data[j].name);
    }
}

以下是我的输出:

Choose 1 to Read data or Choose 2 to Show Data 
Choose 1
Name: ted   
 
Choose 1
Name: alex
 
Choose 2
alex 

谢谢大家!非常感谢

【问题讨论】:

  • #define MAX 1struct Number data[MAX]; 将您限制为数组中的 1 个元素...您确实应该使用单独的计数器来跟踪实际输入的名称数量。这样,如果输入的 MAX 少于此值,您就不会尝试显示 MAX 元素。

标签: arrays c struct


【解决方案1】:

您的问题的简单答案是您已定义 #define MAX 1,因此您的结构 struct Number data[MAX]; 数组中只有 1 个元素,这意味着您只能读取一个名称。

除此之外,您还有许多问题所在。在接受用户输入时,除非您检查输入函数的返回以确定输入是成功还是失败,否则无法正确执行。使用scanf("%s", ... 读取名称时会出现问题,因为"%s" 格式说明符在遇到第一个空格时停止读取。这意味着您将永远无法将 "Siam C." 读取为名称。

而不是使用scanf() 进行用户输入,建议您使用fgets(),这样您每次都会消耗一整行输入。这样,stdin 中剩余的未读内容不取决于scanf() 格式说明符以及是否发生匹配失败。使用fgets() 读取整行,然后您可以使用sscanf() 从该行中提取任何需要的数值。然后在匹配失败的情况下,stdin 中没有任何内容可以中断您的下一次尝试读取。

在显示菜单时,使其在您的代码中可读。除非您将数字转换为输出,否则不需要printf() 一个简单的puts()(或fputs(),如果需要行尾控制)就可以了,例如

    while (1) { /* loop continually */
        /* make your menu readable */
        fputs ("\nPress 'Enter' on a blank line when done\n\n"
                " 1) Read data\n"
                " 2) Show Data\n\n"
                "Choice: ", stdout);

当您必须根据多个输入值确定要采用哪个分支时,请考虑使用switch() 语句而不是if ... else if ... else 的长链。它的功能相同,但提供了更结构化的方法,例如

        /* use a switch to control */
        switch (option) {
            case 1:     read (data, &nelem); break;
            case 2:     show (data, nelem); break;
            default:    fputs ("error: invalid choice.\n", stderr); break;
        }

如上所述,您需要保留一个单独的计数器来跟踪填充的结构数量。将其作为参数传递给您的 show() 函数,以便您知道要显示多少个结构(还要检查它是否为零并显示 "empty-list" 或类似的)。

对于您的 read() 函数,您可以将指针传递给计数器并在您的 read() 函数中更新计数器,以便更新后的计数可以在 main() 中返回,或者您可以返回读取的数字并将其添加到保留在main() 中的计数中。 (无论哪种方式都可以,但传递指针更方便一些)例如,您的 read() 函数可以是:

/* update the number of elements filled through the nelem pointer */
void read (struct Number *data, size_t *nelem)
{
    putchar ('\n');                                     /* newline separator */
    
    while (*nelem < MAX) {                              /* check array not full */
        char *p = data[*nelem].name;                    /* pointer to cut down typing */
        
        fputs ("enter name: ", stdout);                 /* read with fgets() */
        if (!fgets (p, MAX, stdin) || *p == '\n')       /* check return & blank line */
            break;
        p[strcspn (p, "\n")] = 0;                       /* trim '\n' from end of name */
        
        (*nelem)++;                                     /* increment name count */
    }
}

(注意: 输入完姓名后,只需在空白行按 Enter —— 使用fgets() 进行输入的另一个好处。还要注意使用strcspn()fgets() 包含的'\n' 从每个名称的末尾删除。这是最简单、最可靠的方法。)

您的show() 函数可以是:

/* pass the number of filled struct as parameter */
void show (struct Number *data, size_t nelem)
{
    size_t i;
    
    putchar ('\n');                                     /* newline separator */
    
    if (nelem == 0) {                                   /* check if list is empty */
        puts ("  (list-empty)");
        return;
    }
    
    for (i = 0; i < nelem; i++)                         /* output all names */
        printf("  Name:  %s\n", data[i].name);
}

总而言之,您将拥有:

#include <stdio.h>
#include <string.h>

#define MAX 100     /* if you need a constant, #define one (or more) */

struct Number {
    char name[MAX];
};

/* pass the number of filled struct as parameter */
void show (struct Number *data, size_t nelem)
{
    size_t i;
    
    putchar ('\n');                                     /* newline separator */
    
    if (nelem == 0) {                                   /* check if list is empty */
        puts ("  (list-empty)");
        return;
    }
    
    for (i = 0; i < nelem; i++)                         /* output all names */
        printf("  Name:  %s\n", data[i].name);
}

/* update the number of elements filled through the nelem pointer */
void read (struct Number *data, size_t *nelem)
{
    putchar ('\n');                                     /* newline separator */
    
    while (*nelem < MAX) {                              /* check array not full */
        char *p = data[*nelem].name;                    /* pointer to cut down typing */
        
        fputs ("enter name: ", stdout);                 /* read with fgets() */
        if (!fgets (p, MAX, stdin) || *p == '\n')       /* check return & blank line */
            break;
        p[strcspn (p, "\n")] = 0;                       /* trim '\n' from end of name */
        
        (*nelem)++;                                     /* increment name count */
    }
}

int main (void) {
    
    char line[MAX];                     /* buffer to hold line of input */
    struct Number data[MAX] = {{""}};   /* initialize all name to empty-string */
    size_t nelem = 0;                   /* number of filled struct */
    int option;
    
    while (1) { /* loop continually */
        /* make your menu readable */
        fputs ("\nPress 'Enter' on a blank line when done\n\n"
                " 1) Read data\n"
                " 2) Show Data\n\n"
                "Choice: ", stdout);
        
        /* read entire line of input into line, break on EOF or blank line */
        if (fgets (line, MAX, stdin) == NULL || *line == '\n')
            break;
        
        /* parse integer from line */
        if (sscanf (line, "%d", &option) != 1) {
            fputs ("  error: invalid integer input.\n", stderr);
            continue;
        }
        
        /* use a switch to control */
        switch (option) {
            case 1:     read (data, &nelem); break;
            case 2:     show (data, nelem); break;
            default:    fputs ("error: invalid choice.\n", stderr); break;
        }
    }
}

使用/输出示例

现在您可以使用菜单一次添加任意数量的名称、show() 名称、添加更多名称等。最多可达到 MAX 条目数:

$ ./bin/structnumber

Press 'Enter' on a blank line when done

 1) Read data
 2) Show Data

Choice: 2

  (list-empty)

Press 'Enter' on a blank line when done

 1) Read data
 2) Show Data

Choice: 1

enter name: Mickey Mouse
enter name: Minnie Mouse
enter name:

Press 'Enter' on a blank line when done

 1) Read data
 2) Show Data

Choice: 2

  Name:  Mickey Mouse
  Name:  Minnie Mouse

Press 'Enter' on a blank line when done

 1) Read data
 2) Show Data

Choice: 1

enter name: Donald Duck
enter name: Pluto (the dog)
enter name:

Press 'Enter' on a blank line when done

 1) Read data
 2) Show Data

Choice: 2

  Name:  Mickey Mouse
  Name:  Minnie Mouse
  Name:  Donald Duck
  Name:  Pluto (the dog)

Press 'Enter' on a blank line when done

 1) Read data
 2) Show Data

Choice:

现在可以正确处理无效输入:

$ ./bin/structnumber

Press 'Enter' on a blank line when done

 1) Read data
 2) Show Data

Choice: banannas
  error: invalid integer input.

Press 'Enter' on a blank line when done

 1) Read data
 2) Show Data

Choice:

注意:您可以将"Press 'Enter' on a blank line when done" 移出循环,因此它只显示一次——故意重复它以提醒用户如何结束数据或菜单条目)

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-24
    • 1970-01-01
    • 1970-01-01
    • 2022-08-17
    相关资源
    最近更新 更多