Создание цикла for, который редактирует список в структуре данных - PullRequest
0 голосов
/ 08 марта 2019

Код, который я пытаюсь написать, должен принимать данные от пользователя и помещать их в структуру данных, которая прекрасно работает. Что-то идет не так, когда я пытаюсь удалить запись (if (choice == 2). Все, что нужно сделать, это взять эту запись и сделать ее пустой, но мне не понравилась идея пустого пространства. Цикл for, который Я попытался сделать так, чтобы взять верхнюю запись и переместить все вниз на одну, но для этого нужно взять первую запись и скопировать ее во вторую, оставив остальных в покое. Любая помощь в том, как взять данные и просто удалить запись в переместите их вниз, было бы здорово.

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

typedef struct  book  {     //This is the data structure
    char personName[15];
    char personLname[15];
    char phoneNumber[15];
    char null[4];
} Book;

static int loopValue;// this is going to loop the program forever until the 
    //loop is broke
main()
{

    int index = 0;
    int choice;
    Book *ptrBook = (Book*)malloc(sizeof(Book));
    int i,j;
    int stopValue = 1;

    while(stopValue=0)
    {
        printf("\t\tPhone Book Application\n");
        printf("\t1. Add Contact\t\t2. Remove Contact\n");
        printf("\t3. Show Contacts\t10. Exit\n");
        printf("\tChoice: ");
        scanf("%i",&choice);
        printf("\n\n");

        if(choice == 1)     // this is the add person, it takes the print if 
                /and puts it into the data structure
    {
        ptrBook = (Book*)realloc(ptrBook, sizeof(Book)*(index + 1));
        printf("What is the FIRST name: ");
        scanf("%s",ptrBook[index].personName);
        printf("What is the LAST name: ");
        scanf("%s",ptrBook[index].personLname);
        printf("What is the number: ");
        scanf("%s",ptrBook[index].phoneNumber);
        printf("\nAdded to the Phone Book.\n");
        printf("\nName: %s %s\n",ptrBook[index].personName, 
ptrBook[index].personLname);
        printf("Phone Number: %s",ptrBook[index].phoneNumber);
        index++;
    }
    else if (choice == 2)       // this removes people from the data 
                         //structure
    {
        loopValue == 0;
        printf("Who would you like to remove?\n\n");
        for(i=0;i<index;i++)        // this loops prints out the names to 
                               //choose from
        {

     printf("%i. %s %s\n",i+1,ptrBook[i].personName,ptrBook[i].personLname);
        }
        printf("Who would you like to remove? ");
        scanf("%i",choice);
        for(i=choice;i<0;i--)  //THIS IS WHAT NEED HELP WITH PLZ
        {                       //
            strcpy(ptrBook[i-2].personName,ptrBook[i-1].personName);    //
            strcpy(ptrBook[i-2].personLname,ptrBook[i-1].personLname);  //
            strcpy(ptrBook[i-2].phoneNumber,ptrBook[i-1].phoneNumber);  //
        }                   `//
        printf("\n");
        scanf("%i",&choice);
    }
    if(choice == 3)     // this loops to print out all the values in the 
                  //data structure
    {
        for(i=0;i<index;i++)
        {
            printf("%s %s\n",ptrBook[i].personName,ptrBook[i].personLname);
            printf("%i. %s\n\n\n",index,ptrBook[i].phoneNumber);
        }
    }
    else if(choice == 4)
    {
        //make code to sort names
    }
    else if(choice == 5)
    {
        //find a phone number for a given name
    }
    else if(choice == 6)
    {
        //random person for you to call
    }
    else if(choice== 7)
    {
        //delete everyone
    }
    else if(choice == 8)        // this exits the program by changing the 
                      //loop variable to something that makes the loop false
    {
        printf("Exiting");
        stopValue = 0;
    }
}
}

Ответы [ 2 ]

0 голосов
/ 08 марта 2019

Есть так много маленьких проблем с вашим кодом, что трудно понять, с чего начать.Вероятно, наиболее вопиющим является сбой проверки возврата scanf и ваша ошибка очищать stdin любых посторонних символов после каждого ввода, оставляя вашу программу просто в ожидании ввода бесконечного цикла при первом ошибочном нажатии клавиши.Вы не можете использовать спецификатор преобразования "%s" для чтения имен (многие из них состоят из двух частей), и вы перестанете читать на первом пробеле, а оставшаяся часть имени будет принята как следующий ввод.То же самое относится к чтению телефонного номера (который может вызвать бесконечный цикл, если есть пробел и пунктуация).

, что приводит к большей рекомендации использовать fgets вместо scanf для всех строк.ориентированный ввод (например, принятие пользовательского ввода).Вы можете использовать sscanf для анализа целочисленных значений из входных данных, и вы избежите целого ряда ловушек, присущих новым программистам на С, принимающим ввод с scanf.Не экономьте на размере буфера.Например, #define MAXC 1024, а затем char buf[MAXC]; будет достаточно для большинства вводимых пользователем данных.

Далее, при создании меню рассмотрите возможность использования switch () { case 1: ...; break; case 2: ...; break } вместо длинной цепочки if (...) {...} else if (...) {...}, etc....Он обеспечивает более читаемый код;

В ваш код внесено много, гораздо больше исправлений, которые объясняются в комментариях ниже, например,

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

#define NULLSZ    4     /* if you need a constant #define one (or more) */
#define MAXNMNUM 15

typedef struct book {
    char personName[MAXNMNUM];  /* use constants for array sizes */
    char personLname[MAXNMNUM];
    char phoneNumber[MAXNMNUM];
    char null[NULLSZ];  /* no clue what this is for */
} Book;

/* helper function to empty extraneous characters from stdin */
void empty_stdin (void)
{
    int c = getchar();

    while (c != EOF && c != '\n')
        c = getchar();
}

int main (void) /* See http://port70.net/~nsz/c/c11/n1570.html#5.1.2.2.1p1 */
{
    int index = 0;
    Book *ptrBook = malloc (sizeof *ptrBook);  /* do NOT cast malloc return */

    for (;;) {      /* loop continually */
        int rtn,    /* return for scanf */
            choice = 0;
        /* you only need a single fputs - not muliple printf calls
         * there is no conversion taking place, so printf not neeeded.
         */
        fputs ( "\nPhone Book Application\n\n"
                " 1. Add Contact       2. Remove Contact\n"
                " 3. Show Contacts ... 8. Exit\n"
                "\nChoice: ", stdout);
        rtn = scanf ("%d", &choice);    /* ALWAYS VALIDATE EVERY INPUT */
        if (rtn == EOF) {   /* check if user canceled input with Ctrl+d */
            fputs ("(user canceled input)\n", stderr);
            break;
        }
        else if (rtn < 1) { /* check for matching or input failure */
            fputs ("error: invalid integer input.\n", stderr);
            empty_stdin();  /* always empty stdin before next input */
            continue;
        }
        empty_stdin();  /* ditto */

        if (choice == 1) {  /* add book */
            char *p;
            /* don't realloc every addition - very inefficient.
             * don't realloc the pointer itself, use a temp pointer
             * or you create memory leak on failure.
             */
            void *tmp = realloc (ptrBook, sizeof *ptrBook * (index + 1));
            if (!tmp) {
                perror ("realloc-ptrBook");
                break;
            }
            ptrBook = tmp;  /* assign new block to ptrBook */

            fputs ("What is the FIRST name: ", stdout);
            /* don't read line-oriented input with scanf, use fgets
             * if (scanf ("%s", ptrBook[index].personName) != 1) {
             */
            if (!fgets (ptrBook[index].personName, MAXNMNUM, stdin)) {
                fputs ("(user canceled input.)\n", stderr);
                break;
            }
            p = ptrBook[index].personName;  /* set convenience pointer */
            p[strcspn (p, "\r\n")] = 0;     /* trim '\n' from end of str */

            fputs ("What is the LAST name: ", stdout);
            if (!fgets (ptrBook[index].personLname, MAXNMNUM, stdin)) {
                fputs ("(user canceled input.)\n", stderr);
                break;
            }
            p = ptrBook[index].personLname; /* set convenience pointer */
            p[strcspn (p, "\r\n")] = 0;     /* trim '\n' from end of str */

            fputs ("What is the number: ", stdout);
            if (!fgets (ptrBook[index].phoneNumber, MAXNMNUM, stdin)) {
                fputs ("(user canceled input.)\n", stderr);
                break;
            }
            p = ptrBook[index].phoneNumber; /* set convenience pointer */
            p[strcspn (p, "\r\n")] = 0;     /* trim '\n' from end of str */

            printf ("\nAdded to the Phone Book.\n"
                    "\nName: %s %s\nPhone Number: %s\n", 
                    ptrBook[index].personName,
                    ptrBook[index].personLname, 
                    ptrBook[index].phoneNumber);

            index++;    /* increment index */
        }
        else if (choice == 2) {     /* remove entry */
            putchar ('\n');
            for (int i = 0; i < index; i++) {
                printf (" %d. %s %s\n", i + 1, ptrBook[i].personName,
                        ptrBook[i].personLname);
            }

            fputs ("\nWho would you like to remove? ", stdout);
            rtn = scanf ("%d", &choice);
            if (rtn == EOF) {
                fputs ("(user canceled input)\n", stdout);
                break;
            }
            else if (rtn < 1) {
                fputs ("error: invalid integer input.\n", stderr);
                empty_stdin();
                continue;
            }
            else if (choice - 1 < 0 || index - 1 < choice - 1) {
                fputs ("error: out of range of valid indexes.\n", stderr);
                empty_stdin();
                continue;
            }
            /* remvove entry with memmove copying over removed entry */
            memmove (ptrBook + choice - 1, ptrBook + choice,
                    (index - choice) * sizeof *ptrBook);
            index -= 1; /* decrement index */
            /* realloc to remove entry */
            void *tmp = realloc (ptrBook, index * sizeof *ptrBook);
            if (!tmp) {
                perror ("realloc-index");
                break;
            }
            ptrBook = tmp;
        }
        if (choice == 3) {  /* output the entries */
            putchar ('\n');
            for (int i = 0; i < index; i++) {
                printf ("%s %s\n%d. %s\n\n", ptrBook[i].personName,
                        ptrBook[i].personLname, i + 1, 
                        ptrBook[i].phoneNumber);
            }
        } else if (choice == 4) {
            //make code to sort names
        } else if (choice == 5) {
            //find a phone number for a given name
        } else if (choice == 6) {
            //random person for you to call
        } else if (choice == 7) {
            //delete everyone
        } else if (choice == 8) {
            printf ("Exiting\n");
            break;
        }
    }
}

( примечание: использование p в качестве временного указателя просто для удобства и удобочитаемости, а не для того, чтобы печатать, например, полный ptrBook[index].personLname снова и снова, в результате чего команда strcspn занимает несколько строк)

Кроме того, рассмотрите возможность удаления null из вашей структуры (не знаю, для чего это нужно) и рассмотрите возможность добавления index или nentries в качестве члена, чтобы число записей всегда было частью самой структуры (что делает вещи намного более удобнымипри передаче или возврате структуры (или указателя на нее) в / из других функций)

Ниже обратите внимание, как программа теперь может восстанавливаться после неверного ввода.Попробуйте тот же самый ввод с вашим кодом в меню, например, "I don't know" и посмотрите, что произойдет ...

Пример Использование / Вывод

$ ./bin/book_remove

Phone Book Application

 1. Add Contact       2. Remove Contact
 3. Show Contacts ... 8. Exit

Choice: I don't know
error: invalid integer input.

Phone Book Application

 1. Add Contact       2. Remove Contact
 3. Show Contacts ... 8. Exit

Choice: 1
What is the FIRST name: Mark
What is the LAST name: Twain
What is the number: (444) 555-1212

Added to the Phone Book.

Name: Mark Twain
Phone Number: (444) 555-1212

Phone Book Application

 1. Add Contact       2. Remove Contact
 3. Show Contacts ... 8. Exit

Choice: 1
What is the FIRST name: Samuel
What is the LAST name: Clements
What is the number: (444) 555-1213

Added to the Phone Book.

Name: Samuel Clements
Phone Number: (444) 555-1213

Phone Book Application

 1. Add Contact       2. Remove Contact
 3. Show Contacts ... 8. Exit

Choice: 1
What is the FIRST name: Won Hung
What is the LAST name: Lo
What is the number: (444) 555-1214

Added to the Phone Book.

Name: Won Hung Lo
Phone Number: (444) 555-1214

Phone Book Application

 1. Add Contact       2. Remove Contact
 3. Show Contacts ... 8. Exit

Choice: 1
What is the FIRST name: Fred
What is the LAST name: Flintstone
What is the number: (444) 555-1215

Added to the Phone Book.

Name: Fred Flintstone
Phone Number: (444) 555-1215

Phone Book Application

 1. Add Contact       2. Remove Contact
 3. Show Contacts ... 8. Exit

Choice: 3

Mark Twain
1. (444) 555-1212

Samuel Clements
2. (444) 555-1213

Won Hung Lo
3. (444) 555-1214

Fred Flintstone
4. (444) 555-1215


Phone Book Application

 1. Add Contact       2. Remove Contact
 3. Show Contacts ... 8. Exit

Choice: 2

 1. Mark Twain
 2. Samuel Clements
 3. Won Hung Lo
 4. Fred Flintstone

Who would you like to remove? 2

Phone Book Application

 1. Add Contact       2. Remove Contact
 3. Show Contacts ... 8. Exit

Choice: 3

Mark Twain
1. (444) 555-1212

Won Hung Lo
2. (444) 555-1214

Fred Flintstone
3. (444) 555-1215


Phone Book Application

 1. Add Contact       2. Remove Contact
 3. Show Contacts ... 8. Exit

Choice: 8
Exiting

Посмотрите на вещии убедитесь, что вы понимаете, что и почему были внесены изменения.Если нет, то просто попросите дальнейших разъяснений.

0 голосов
/ 08 марта 2019

Ваш код имеет много проблем. В будущем, пожалуйста, убедитесь, что ваш код действительно тщательно очищен, прежде чем отправлять вопрос. Я потратил время, чтобы привести в порядок многое из этого, потому что я ненавижу себя, поэтому я надеюсь, что вы оцените. Сначала список ошибок:

1 и 2) Ваше условие в цикле while - это задание: пожалуйста, включите предупреждения на вашем компиляторе, потому что они будут ловить подобные вещи. Это также ошибочно с вашей инициализацией stopValue.

3) loopValue используется в коде непоследовательно и не является тем, что контролирует ваш цикл while.

4) Внутри if (choice == 2), loopValue == 0 означает сравнение с 0, а не с установкой на 0. Это не влияет на вашу программу, но вы дважды допустили ошибку =, ==. Это действительно базовые вещи, с которыми вам абсолютно необходимо справиться.

5) В том же разделе if ваш scanf, в котором вы установили choice, не имел & перед выбором, что означает, что переменная фактически не будет установлена ​​в значение, введенное в.

6) В том же разделе, последние printf и scanf, вероятно, не должны быть там? В любом случае они вводят ввод в неинтуитивную остановку, что делает программу бесполезной для тех, у кого нет исходного кода.

7) if (choice == 3) не был другим, если.

8) Опция выхода - 8 в исходном коде, но в меню указано, что это 10.

После всего этого вот код (со множеством вещей, которые не имеют никакого отношения к проблеме, которую вы пытались устранить)

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

typedef struct book {     //This is the data structure
    char personName[15];
    char personLname[15];
    char phoneNumber[15];
    char null[4];
} Book;

static int loopValue;
int main(void) {
    int index = 0;
    int choice;
    Book *ptrBook = (Book*) malloc(sizeof(Book));
    int i, j;
    int stopValue = 0; // was 1

    while (stopValue == 0) { // was =
        printf("\t\tPhone Book Application\n");
        printf("\t1. Add Contact\t\t2. Remove Contact\n");
        printf("\t3. Show Contacts\t8. Exit\n");
        printf("\tChoice: ");
        scanf("%i", &choice);
        printf("\n\n");

        if (choice == 1) {
            ptrBook = (Book*) realloc(ptrBook, sizeof(Book)*(index + 1));
            printf("What is the FIRST name: ");
            scanf("%s",ptrBook[index].personName);
            printf("What is the LAST name: ");
            scanf("%s",ptrBook[index].personLname);
            printf("What is the number: ");
            scanf("%s",ptrBook[index].phoneNumber);
            printf("\nAdded to the Phone Book.\n");
            printf("\nName: %s %s\n",ptrBook[index].personName,
            ptrBook[index].personLname);
            printf("Phone Number: %s",ptrBook[index].phoneNumber);
            index++;
        } else if (choice == 2) {
            loopValue = 0; // was ==
            printf("Who would you like to remove?\n\n");
            for (i = 0; i < index; i++) {
                printf("%i. %s %s\n", i+1, ptrBook[i].personName, ptrBook[i].personLname);
            }
            printf("Who would you like to remove? ");
            scanf("%d", &choice); // didn't have &
            for (int i = (choice - 1); i < (index - 1); i++) {
                ptrBook[i] = ptrBook[i + 1];
            }
            index--;
            // used to be redundant/confusing/wrong printf and scanf
        } else if (choice == 3) { // used to not be else if
            for (i = 0; i<index; i++) {
                printf("%s %s\n", ptrBook[i].personName, ptrBook[i].personLname);
                printf("%i. %s\n\n\n", index, ptrBook[i].phoneNumber);
            }
        } else if (choice == 8) { // Should've been 10
            printf("Exiting");
            stopValue = 1;
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...