用不同的编程结构替换 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;
}
请注意,您的代码根本不是防御性的。您无法避免缓冲区溢出,因为,
- 您在将字符串输入程序后检查字符串的长度,以便在缓冲区溢出已经发生并且
- 您使用了
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;
}
我正在尝试用防御性编程来完成这个小程序,但我很难处理这个避免 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;
}
请注意,您的代码根本不是防御性的。您无法避免缓冲区溢出,因为,
- 您在将字符串输入程序后检查字符串的长度,以便在缓冲区溢出已经发生并且
- 您使用了
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;
}