l oop не выполняется правильно - PullRequest
0 голосов
/ 13 марта 2020

У меня есть функция readin (), которая считывает количество имен людей и соответствующие им номера телефонов и возвращает количество введенных имен. Символ «#» используется для обозначения конца пользовательского ввода.

int readin(Employee *emp)
{
    int i=0,j;
    do { // loop statements to be executed no matter what
        printf("Enter name:\n");
        scanf("%s",emp->name); // stores name inside structure array
        j = (strcmp(emp->name,"#") != 0); // returns 1 if name not equals to #

    } while(j);{ // while name is not equals to # , execute code below and loop back 'do'
            printf("Enter tel:\n");
            scanf("%s",emp->telno);

            emp++;
            i++;
    }
    return i;
}

Ожидаемые результаты должны быть:

Enter name:
John
Enter tel:
12345678
Enter name:
#

Полученные результаты:

Enter name:
John
Enter name:
#
Enter tel:

Когда j = 1, то время l oop не запускается, но он возвращается к части do вместо полного выхода из l oop. Когда j = 0, коды в то время как l oop выполняются по некоторым причинам. Пожалуйста, сообщите.

Ответы [ 2 ]

1 голос
/ 13 марта 2020

вы знаете, что именно так во время работы выглядит

do{
 state1;
}
while(statement);

rest of code;

, если оператор верен, он переходит в состояние и повторяет его, а когда оператор неверен, он переходит к остальной части вашего кода.

, который в вашем случае, пока string! = '#', Вы всегда будете вводить do while () l oop, а когда оператор неверен или j==0, вы выходите из do, пока l oop

Я рекомендую это:

int readin(Employee* emp)
{
    int i = 0, j =0;
    while (1)
    {
        printf("Enter name:\n");
        scanf("%s", &emp->name);
        if((strcmp(emp->name, "#") == 0))
                    break;

        printf("Enter tel:\n");
        scanf("%s", &emp->telno);

        emp++;
        i++;
    }

    return i;
}
0 голосов
/ 13 марта 2020

Использование scanf для линейно-ориентированного ввода является неправильным выбором. Рекомендуемый способ чтения строк пользовательского ввода - fgets() или POSIX getline().

Зачем использовать fgets ()?

Короче говоря, он более надежный, он обрабатывает внутренние пробелы, позволяя вам ввести "first last" name или "(409) 555-1212" в качестве telno (scanf() с "%s" не может), и ваша единственная ответственность заключается в проверке возврата, а затем обрезке трейлинга '\n' на входе. Вы проверяете возврат для обработки сгенерированного вручную EOF, где пользователь отменяет ввод, нажимая Ctrl + d на Linux или Ctrl + z на windows. (так же, как вы должны сделать для scanf()). В качестве преимущества вам не нужно вводить '#' для завершения ввода, потому что fgets() читает '\n', когда нажата Enter , что позволяет пользователь просто нажимает Введите в пустой строке name для выхода.

Например, вы можете прочитать и проверить, что строка имени и телефонного номера была введена с чем-то простым как:

#define MAXTEL  32      /* if you need a constant, #define one (or more) */
#define MAXNM   64
#define MAXEMP 128

typedef struct {
    char name[MAXNM],
        telno[MAXTEL];
} employee;

int readin (employee *emp)
{
    int n;

    for (n = 0; n < MAXEMP; n++) {  /* loop continually - protect array bounds */
        fputs ("\nEnter name: ", stdout);   /* prompt */
        /* read/validate, check for Enter alone to exit */
        if (!fgets (emp[n].name, MAXNM, stdin) || *emp[n].name == '\n')
            break;
        emp[n].name[strcspn(emp[n].name, "\n")] = 0;    /* trim trailing \n */

        fputs ("Enter tel : ", stdout);                 /* prompt */
        if (!fgets (emp[n].telno, MAXTEL, stdin))       /* read/validate */
            break;
        emp[n].telno[strcspn(emp[n].telno, "\n")] = 0;  /* trim trailing \n */
    }

    return n;
}

Как насчет использования scanf ()?

Это выполнимо, но ваши обязанности резко возрастут, так как вам нужно будет удалить '\n', который остается в stdin после получения ввода, чтобы гарантировать, что следующий ввод в вашем коде после выхода из функции readin() не завершится с ошибкой. С scanf() (установите до l oop, как вы указали, требуя '#' для завершения ввода), потребуется:

int readin (employee *emp)
{
    int n;

    for (n = 0; n < MAXEMP; n++) {  /* loop continually - protect array bounds */
        int rtn;            /* variable to save the return of scanf */

        fputs ("\nEnter name: ", stdout);       /* prompt */
        rtn = scanf(" %63[^\n]", emp->name);    /* read into tmp saving return */

        if (rtn == EOF) {   /* handle EOF - user presses Ctrl+d (Ctrl+z win) */
            fputs ("(user canceled input)\n", stderr);
            break;
        }
        else if (rtn == 1 && *emp->name == '#') /* good input and '#' -- bail */
            break;

        for (;;) {  /* loop contianually until valid telno entered */

            fputs ("Enter tel : ", stdout);         /* prompt */
            rtn = scanf(" %31[^\n]", emp->telno);   /* read saving return */

            if (rtn == EOF) {       /* handle EOF - ditto */
                fputs ("(user canceled input)\n", stderr);
                break;
            }
            else if (rtn == 1) {    /* good input */
                /* further validate telno here */
                break;
            }
        }   /* empty trailing \n from stdin */
        for (int c = getchar(); c != '\n' && c != EOF; c = getchar()) {}

        emp++;  /* advance pointer */
    }

    return n;   /* return success */
}

И вам все еще нужно ввести '#' для завершения ввод - который не должен быть необходим.

Что бы вы предпочли использовать?

Пример

Использовать любую функцию с :

int main (void) {

    employee e[MAXEMP] = {{ .name = "" }};
    int n = readin (e);

    for (int i = 0; i < n; i++)
        printf ("\nemployee:\n  name  : %s\n  telno : %s\n", 
                e[i].name, e[i].telno);
}

Пример использования / вывода - fgets ()

$ ./bin/empnametelnoarray

Enter name: John Q. Public
Enter tel : 444-1212

Enter name: Sally P. Public
Enter tel : 444-1222

Enter name: Mary Jane
Enter tel : 444-1223

Enter name:

employee:
  name  : John Q. Public
  telno : 444-1212

employee:
  name  : Sally P. Public
  telno : 444-1222

employee:
  name  : Mary Jane
  telno : 444-1223

Пример использования / вывода - scanf ()

$ ./bin/empnametelnoarray

Enter name: John Q. Public
Enter tel : 444-1212

Enter name: Sally P. Public
Enter tel : 444-1222

Enter name: Mary Jane
Enter tel : 444-1223

Enter name: #

employee:
  name  : John Q. Public
  telno : 444-1212

employee:
  name  : Sally P. Public
  telno : 444-1222

employee:
  name  : Mary Jane
  telno : 444-1223

Полный пример показан ниже, просто добавьте -DUSESCANF в строку компиляции (или /D USESCANF для VS), чтобы использовать версию scanf(), по умолчанию используется fgets(). В целом, нет смысла использовать scanf() для чтения двух строк ввода пользователя. Вы гораздо лучше справляетесь, используя линейно-ориентированную функцию ввода для чтения строк ввода от пользователя:

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

#define MAXTEL  32      /* if you need a constant, #define one (or more) */
#define MAXNM   64
#define MAXEMP 128

typedef struct {
    char name[MAXNM],
        telno[MAXTEL];
} employee;

#ifndef USESCANF
int readin (employee *emp)
{
    int n;

    for (n = 0; n < MAXEMP; n++) {  /* loop continually - protect array bounds */
        fputs ("\nEnter name: ", stdout);   /* prompt */
        /* read/validate, check for Enter alone to exit */
        if (!fgets (emp[n].name, MAXNM, stdin) || *emp[n].name == '\n')
            break;
        emp[n].name[strcspn(emp[n].name, "\n")] = 0;    /* trim trailing \n */

        fputs ("Enter tel : ", stdout);                 /* prompt */
        if (!fgets (emp[n].telno, MAXTEL, stdin))       /* read/validate */
            break;
        emp[n].telno[strcspn(emp[n].telno, "\n")] = 0;  /* trim trailing \n */
    }

    return n;
}
#else
int readin (employee *emp)
{
    int n;

    for (n = 0; n < MAXEMP; n++) {  /* loop continually - protect array bounds */
        int rtn;            /* variable to save the return of scanf */

        fputs ("\nEnter name: ", stdout);       /* prompt */
        rtn = scanf(" %63[^\n]", emp->name);    /* read into tmp saving return */

        if (rtn == EOF) {   /* handle EOF - user presses Ctrl+d (Ctrl+z win) */
            fputs ("(user canceled input)\n", stderr);
            break;
        }
        else if (rtn == 1 && *emp->name == '#') /* good input and '#' -- bail */
            break;

        for (;;) {  /* loop contianually until valid telno entered */

            fputs ("Enter tel : ", stdout);         /* prompt */
            rtn = scanf(" %31[^\n]", emp->telno);   /* read saving return */

            if (rtn == EOF) {       /* handle EOF - ditto */
                fputs ("(user canceled input)\n", stderr);
                break;
            }
            else if (rtn == 1) {    /* good input */
                /* further validate telno here */
                break;
            }
        }   /* empty trailing \n from stdin */
        for (int c = getchar(); c != '\n' && c != EOF; c = getchar()) {}

        emp++;  /* advance pointer */
    }

    return n;   /* return success */
}
#endif

int main (void) {

    employee e[MAXEMP] = {{ .name = "" }};
    int n = readin (e);

    for (int i = 0; i < n; i++)
        printf ("\nemployee:\n  name  : %s\n  telno : %s\n", 
                e[i].name, e[i].telno);
}

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

...