Struct Array напечатал последний элемент

#arrays #c #struct

#массивы #c #структура

Вопрос:

Я хотел напечатать все введенные элементы во входных данных. Но в коде был напечатан самый последний введенный код. Я ожидал, что программа будет печатать каждый ввод, введенный в массивы 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", amp;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 
 

Спасибо всем! Очень признателен

Комментарии:

1. #define MAX 1 и struct Number data[MAX]; ограничивает вас 1 элементом в вашем массиве… Вам действительно следует использовать отдельный счетчик для отслеживания количества фактически введенных имен. Таким образом, если введено меньше MAX , вы не пытаетесь отобразить MAX элементы.

Ответ №1:

Простой ответ на ваши вопросы заключается в том, что вы определили #define MAX 1 , поэтому в вашем массиве struct есть только 1 элемент struct Number data[MAX]; , что означает, что вы можете прочитать только одно имя.

Помимо этого у вас есть ряд областей, в которых у вас возникают проблемы. Принимая пользовательский ввод, вы не сможете сделать это правильно, если не проверите возврат функции ввода, чтобы определить, был ли ввод успешным или неудачным. У вас возникнет проблема с чтением имен, 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 donenn"
                " 1) Read datan"
                " 2) Show Datann"
                "Choice: ", stdout);
 

Когда вам нужно определить, какую ветвь использовать на основе нескольких входных значений, рассмотрите возможность использования switch() оператора вместо длинной цепочки if ... else if ... else . Он функционирует так же, но обеспечивает более структурированный подход, например

         /* use a switch to control */
        switch (option) {
            case 1:     read (data, amp;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 amp; blank line */
            break;
        p[strcspn (p, "n")] = 0;                       /* trim 'n' from end of name */
        
        (*nelem)  ;                                     /* increment name count */
    }
}
 

(примечание: когда вы закончите вводить имена, просто нажмите Enterна пустую строку — еще одно преимущество использования fgets() для ввода. Также обратите внимание на использование strcspn() для обрезки 'n' включенного by fgets() с конца каждого имени. Это самый простой и надежный подход.)

Ваша 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:  %sn", 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:  %sn", 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 amp; 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 donenn"
                " 1) Read datan"
                " 2) Show Datann"
                "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", amp;option) != 1) {
            fputs ("  error: invalid integer input.n", stderr);
            continue;
        }
        
        /* use a switch to control */
        switch (option) {
            case 1:     read (data, amp;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" выйти из цикла, чтобы он отображался только один раз — он был намеренно повторен, чтобы напомнить пользователю, как завершить данные или пункты меню)

Просмотрите все и дайте мне знать, если у вас возникнут дополнительные вопросы.