C电话簿程序:如何退出避免无限循环以及如何返回到switch语句菜单

时间:2017-02-17 06:22:56

标签: c switch-statement infinite-loop

我有一个用C编写的简单电话簿,可以将输入信息保存到我的电脑上的文本文件中。

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

void validateName(char name[], FILE *fptr);
void validateID(char id[], FILE *fptr);
void validateScore(int score, FILE *fptr);
void addContact(char name[], char id[], int score, FILE *fptr);
void printContact(FILE *fptr);
void printAll();

int main()
{
    char name[30], id[10];
    int score;
    int i;

   FILE *fptr;
   fptr = fopen("C:\\c\\program.txt","w");

   if(fptr == NULL)
   {
      printf("Error!");   
      exit(1);             
   }
    else {  

        bool flag = true;
        do{
            printf("\n1. Press 1 to display record\n"
                   "2. Press 0 to add a new contact\n"
                   "3. Press -1 to display all records\n\n");

            int option;
            scanf("%d", &option);
            switch(option) {
                case 1:
                    printContact(fptr);
                    flag = false;
                    break;
                case 0:
                    addContact(name, id, score, fptr);
                    flag = false;
                    break;
                case -1:
                    printAll();
                    flag = false;
                    break;
                default:
                    printf("wrong choice, try again\n\n");             
            }       

        } while(flag);  

    fclose(fptr);
    return(0);
    }   
}

void validateName(char name[], FILE *fptr){

    bool flag = true;

    while(flag){
        fgets(name, 30, stdin);
        if ((strlen(name) < 3) || (strlen(name) > 20)) {
                printf("error\nplease enter name again: ");
        } else {
            flag = false;
        }       
    }   
}

void validateID(char id[], FILE *fptr){

    bool flag = true;
    while(flag) {
         if (!isalpha(id[0])){
            printf("enter a letter as first char\n");  
        }
         else if(strlen(id) > 10) {
            printf("error too much numbers \n");
        } else {
             flag = false;
         }
    }
}

void validateScore(int score, FILE *fptr) {

        if(score >= 0 && score <= 100) {
            fprintf(fptr, "SCORE: %d\n", score);
            } else {
                printf("invalid input");

                (exit(1));
            }
}

void addContact(char name[], char id[], int score, FILE *fptr) {

    //first name 
    printf("Enter name: ");    
    scanf("%s", name);
    validateName(name, fptr);
    fprintf(fptr,"NAME: %s \n", name);  

     //id   
    printf("Enter id: ");
    scanf("%s", id);
    validateID(id, fptr);
    fprintf(fptr,"STUDENT NO: %s\n", id);

    //score      
    printf("enter score: ");
    scanf("%d", &score);
    validateScore(score, fptr);
}

void printContact(FILE *fptr) {

    int c;
    char contacts[50];

   while((c = getchar()) != EOF) {
       fscanf(fptr, "%s", &contacts);

       for(int i = 50; i < 50; i++){
           printf("%s", &contacts);
       }
   }




}

void printAll() {

}

我的第一个问题是在validateID函数中: 当我尝试验证第一个条件时,我会不断进入无限循环,这是为了确保第一个索引是一个字符。

我的第二个问题是,当我输入姓名,学生ID和分数时,程序结束,我不会返回菜单开关语句来选择其他选项?

我做错了什么或我错过了什么?

4 个答案:

答案 0 :(得分:2)

在我看来,使用像void validateXXX这样的功能是错误的。将其与isalpha进行比较,这类似于验证。 isalpha会返回int,以便您可以将其用于检查。您的验证功能应该也可以这样做。所以而不是:

void validateID(char id[], FILE *fptr){

    bool flag = true;
    while(flag) {
         if (!isalpha(id[0])){
            printf("enter a letter as first char\n");  
        }
         else if(strlen(id) > 10) {
            printf("error too much numbers \n");
        } else {
             flag = false;
         }
    }
}

该功能可以是:

int validateID(char id[]){
    if (!isalpha(id[0])){
            printf("enter a letter as first char\n");  
            return 0;
    }    
    if(strlen(id) > 10) {
            printf("error too much numbers \n");
            return 0;
    }    
    return 1;
}

然后你可以像:

一样使用它
do {
    scanf("%s", id);    // See below !!!!
} while(!validateID(id));

这样您就可以继续阅读,直到输入有效的ID。

下一步:

从不使用scanf("%s", ...) - 从不

没有检查输入的长度,因此用户可以输入一些文本太长而无法存储在您提供的缓冲区中(例如id)。这对你的程序来说是灾难性的,因为它会在数组边界外编写。你的程序可能崩溃或做各种奇怪的事情。

您应该使用fgets来阅读用户输入。它更容易,也更安全。

对于你的主循环:

是的,因为它会在flag的所有case中将switch设置为false时终止。

答案 1 :(得分:0)

对于validateID(),您不会在while循环中更改任何会导致终止的内容。您始终会检查id[0]strlen(id),但不会更改任何有关id或您如何检查的内容。如果id[0]不是字母数字,那么您将永远循环使用它。或者,如果它是字母数字但strlen(id)是&lt; = 10,那么你将永远循环。你究竟在这里循环什么?

您的程序在单个菜单选择后终止,因为所有选择都将flag设置为false并且永远不会重新初始化为true - 因此while循环终止并且您的程序结束。< / p>

答案 2 :(得分:0)

您必须在此行scanf

之后使用printf("enter a letter as first char\n");

答案 3 :(得分:0)

以下是isalpha()函数的声明。

  

int isalpha(int c);

如果c是字母表,则此函数返回非零值,否则返回0.您的while将始终保持真实条件。它进入上面两个案例中的一个吧?所以一旦它离开,请确保你返回false或0,以便它出来。现在取决于你如何修改它。