用不同的编程结构替换 goto

Replacing `goto` with a different programming construct

我正在尝试用防御性编程来完成这个小程序,但我很难处理这个避免 Loop-Goto 的问题,因为我知道这是 BAD 编程。我尝试过 while 和 do...while 循环,但在一种情况下我没有问题。当我打算做另一件事时,问题就开始了……而对于第二种情况 ("Not insert space or click enter button")。我试过嵌套 do...while 但这里的结果更复杂。

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

int main()
{
    int i;
    int length;
    char giventext [25];        
    Loop:

    printf("String must have 25 chars lenght:\n");
    gets(giventext);

    length = strlen(giventext);

    if (length > 25) {
        printf("\nString has over %d chars.\nMust give a shorter string\n", length);
        goto Loop;
    }
    /* Here i trying to not give space or nothing*/
    if (length < 1) {
        printf("You dont give anything as a string.\n");
        goto Loop;
    } else {
        printf("Your string has %d\n",length);
        printf("Letter in lower case are: \n");

        for (i = 0; i < length; i++) {
            if (islower(giventext[i])) {                            
                printf("%c",giventext[i]);
            }
        }
    }
    return 0;
}

请注意,您的代码根本不是防御性的。您无法避免缓冲区溢出,因为,

  1. 您在将字符串输入程序后检查字符串的长度,以便在缓冲区溢出已经发生并且
  2. 您使用了 gets(),它不检查输入长度,因此很容易发生缓冲区溢出。

改用 fgets() 并丢弃多余的字符。

我认为您需要了解 strlen() 不计算输入的字符数,而是计算字符串中的字符数。

如果你想确保插入的字符少于 N 那么

int
readinput(char *const buffer, int maxlen)
{
    int count;
    int next;

    fputc('>', stdout);
    fputc(' ', stdout);

    count = 0;
    while ((next = fgetc(stdin)) && (next != EOF) && (next != '\n')) {
        // We need space for the terminating '[=10=]';
        if (count == maxlen - 1) {
            // Discard extra characters before returning
            // read until EOF or '\n' is found
            while ((next = fgetc(stdin)) && (next != EOF) && (next != '\n'))
                ;
            return -1;
        }
        buffer[count++] = next;
    }
    buffer[count] = '[=10=]';
    return count;
}

int
main(void)
{
    char string[8];
    int result;

    while ((result = readinput(string, (int) sizeof(string))) == -1) {
        fprintf(stderr, "you cannot input more than `%d' characters\n", 
                            (int) sizeof(string) - 1);
    }
    fprintf(stdout, "accepted `%s' (%d)\n", string, result);
}

注意,通过使用函数,本程序的流程控制清晰简单。这正是 goto 不被鼓励的原因,不是因为它是邪恶的东西,而是因为它可能像您一样被滥用。

尝试使用标记程序需要执行的逻辑步骤的函数:

char * user_input() - returns 来自用户的输入作为指向字符的指针(使用 get() 以外的东西!例如,查看 scanf

bool validate_input(char * str_input) - 从上述函数获取用户输入并执行检查,例如验证长度在 1 到 25 个字符之间。

str_to_lower(char * str_input) - 如果 validate_input() returns 为真,则您可以调用此函数并将其传递给用户输入。然后,此函数的主体可以将用户输入以小写形式打印回控制台。您可以在此处使用标准库函数 tolower() 将每个字符小写。

您的主要函数的主体将变得更加简单,并执行一系列逻辑步骤来解决您的问题。这是防御性编程的本质 - 将您的问题模块化为独立的且易于测试的独立步骤。

主要功能的可能结构可以是:

char * user_input();
bool validate_input(char *);
void str_to_lower(char *);

int main()
{
    char * str_input = user_input();

    //continue to get input from the user until it satisfies the requirements of 'validate_input()'
    while(!validate_input(str_input)) { 
        str_input = user_input();
    }

    //user input now satisfied 'validate_input' so lower case and print it
    str_to_lower(str_input);
    return 0;
}