互动,限制性,动态的用户输入

时间:2018-09-21 01:22:29

标签: c multidimensional-array fgets

我在作业说明的PDF文件中提供了link

[TL; DR]

问两个问题: 您是否害怕黑暗?你运动吗?

输入: 'Y''N'

如果第二个问题的输入'Y',则另一个问题:每天要执行几分钟?

输入: 整数> 0。但是,如果每天少于10 ,则不合格

输出:告诉用户是否可以输入忍者训练。


我遇到的困难

  1. 动态分配多维字符串数组

我只编写了大约一个星期的代码,所以我知道这对于这项作业来说可能有些过头了。话虽如此,我在做这项作业的时候就有了一个主意,虽然我发现用言语表达我的主意是非常具有挑战性的,但是我觉得这是一张捕捉到我“可视化”的图像。

Visual posted on https://www.eskimo.com/~scs/cclass/int/sx9b.html by Steve Summit

在这个特定的作业中,我认为保留用户的答案是浪费内存。但是,如果我想编写一个程序来询问用户一系列输入,最后将它们关联起来,或者对lulz进行虚假关联,该怎么办?

Spurious Correlations http://www.tylervigen.com/spurious-correlations by Tyler Vigen

更实际的原因是MBTI个性类型测试吗?我不知道所有的可能性,但它们似乎令人兴奋。

这就是我要动态分配多维字符串数组要实现的目标


稍后会更新

随后是原始帖子……

该代码有效,但仍然允许某些输入,即,如果第一个元素为Y或N,则输入的任何字符。

代码如下:

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

int main() {
    char reference[][2] = { "Y", "N" };
    char (*ptr_reference)[2] = reference;

    int reference_minutes[1] = { 10 };
    int *ptr_reference_minutes = reference_minutes;

    char **user_input;

    user_input = (char**)malloc(3 * sizeof(char*));

    int i;
    for (i = 0; i < 3; i++)  {
        user_input[i] = (char*)malloc(4 * sizeof(char));
    }
    if (!user_input) {
        printf("Could not allocate memory!/n");
        exit(1);
    }

    i = 0;
    while (i == 0) {
        printf("\nAre you afraid of the dark? Choose either [Y/N], and press enter when finished: \n");
        fgets(user_input[i], 4, stdin);
        user_input[i] = realloc(user_input[i], sizeof(char));

        if (strncmp(user_input[i], *ptr_reference, 1) == 0) {
            printf("\nPatience, Young Grasshoper! You are not ready to become a ninja.");
            i = 3;
            break;
        } else if (strncmp(user_input[i], *(ptr_reference + 1), 1) == 0) {
            i++;
            break;
        } else {
            printf("\nPlease enter Y for yes or N for no.\n\n");
            continue;
        }
    }
    while (i == 1) {
        printf("\nDo you exercise? Input [Y/N], and press enter when finished: \n");
        fgets(user_input[i], 4, stdin);

        if (strncmp(user_input[i], *ptr_reference, 1) == 0) {
            i++;
            break;
        } else if (strncmp(user_input[i], *(ptr_reference + 1), 1) == 0) {
            printf("\nDo you even lift, Bro?");
            i = 3;
            break;
        } else {
            printf("\nPlease enter Y for yes or N for no.\n\n");
            continue;
        }
    }
    while (i == 2) {
        int sscanf_result, answer;

        printf("\nHow many minutes a day do you exercise? Type an integer greater than 9 and press enter when finished.\n");
        fgets(user_input[i], 4, stdin);

        sscanf_result = sscanf(user_input[i], "%d", &answer);

        if ((sscanf_result == 0) | (sscanf_result == EOF)) {
            /* either a non-integer entered or an end-of-line */
            printf ("\nYou have to enter an integer!\n");
            i = 2;
            continue;
        } else if (answer < *ptr_reference_minutes) {
            printf("\nCome on! You kids are soft! You lack discipline!\n");
            i = 3;
            break;
        } else {
            printf("\nYou are a good fit for ninja training.\n");

            for (i = 0; i < 3; i++) {
                free(user_input[i]);
            }
            free(user_input);
            user_input = NULL;
            break;
        }
    }
    return 0;
}

2 个答案:

答案 0 :(得分:2)

好的,我可以看看您的程序。问题不在于分配,而在于字符串管理。在C中,一个字符串是一个以null结尾的char数组(请复制100次...)。

当您读取带有fgets的行时,会在缓冲区中获得换行符(\n),因此,如果用户键入 Y Enter ,您得到{'Y', '\n', '\0', undeterminated_char }。那么以下realloc就是错误的:

  • 这可能是个小问题:编译器将只给您一个缓冲区至少与您的要求一样大。从4> 1开始,它可以(并且我的实现做到了)保持原始缓冲区不变
  • 不允许您使用超出要求的任何内容,尤其是,您不应假定存在null!

因此,如果您坚持进行字符串比较,则应仅确保第二个字符为空:user_input[i][2] = '\0';

但是恕我直言,这里需要的只是:

if (user_input[i][0] == 'Y') {
    ...

那还不是全部。您尝试在输入处理中做得很好,但是只忘记了一个细节:如果一行的长度超出了声明的大小,则fgets会填充其缓冲区,并使行的其余部分可供下次读取。

以下只是我的建议:

您已尝试将您所知道的一切(可能还没有完全掌握的东西)用于单个简单的程序。别。保持每个程序尽可能的简单(保持愚蠢简单是一种普遍的好习惯...),并相信您的学习者会为您提供其他分配给其他模式的作业。所以在这里您应该:

  • 阅读一行,直到找到\n(可能需要几个fgets
  • 测试缓冲区的第一个字符为'Y''N'
  • 测试第二个到'\0'

因为这是现实世界中的普遍要求,并且只有在程序运行后,您才可以考虑:

  • 忽略初始空白字符
  • 接受小写字母作为大写字母
  • 接受第一个字符后的任何字符(以接受是和否)

如果合适的编码对您很重要,请提供最后的建议:程序正常运行后,您应该考虑将其发布在Code Review上以获得有趣的评论。

答案 1 :(得分:0)

@Serge Ballesta @Serga Ballesta非常感谢您的反馈。这非常有帮助。在听取了您的建议之后,我能够编写一个更好的程序,尽管我不确定在“保持简单,愚蠢”方面是否成功。

我仍然不知道如何在'Y'或'N'之后限制字符,即Nnb或Nq被接受为N并进入第二个问题。

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

int main (void) {

char *user_input = NULL;
user_input = (char*)malloc(3*sizeof(char));

int sscanf_result, answer;
int i;
while (!*user_input)
{
printf("\nAre you afraid of the dark? \n\nInput Specifications: Please type 'Y' to indicate yes, or 'N' to indicate no, and then press the 'Enter' or 'return' key when finished.\n\n");

i = 0;        
fgets(user_input, sizeof(user_input), stdin);

/* trim off last character */
user_input[strlen(user_input)-1] = '\0';

if (user_input[i]  == 'Y')
{
printf("\nFear of the dark? Fear those who lurk in the dark, my friend. Ninjas! You may not train as a ninja!");

free(user_input);
for (i = 0; i < 3; i++)
{
user_input[i] = '\0';
}
exit(0);
}
else if (user_input[i]  == 'N')
{
free(user_input);
for (i = 0; i < 3; i++)
{
user_input[i] = '\0';
}
printf("\nDo you exercise?\n\nInput Specifications: Please type 'Y' to indicate yes, or 'N' to indicate no, and then press the 'Enter' or 'return' key when finished.\n\n");

i = 0;                           
fgets(user_input, sizeof(user_input), stdin);
user_input[strlen(user_input)-1] = '\0';
if (user_input[i]  == 'N')
{
printf("\nDo you even lift, Bro?\n");

free(user_input);
for (i = 0; i < 3; i++)
{
user_input[i] = '\0';
}
exit(0);
}
else if (user_input[i]  == 'Y')
{
free(user_input);
for (i = 0; i < 3; i++)
{
user_input[i] = '\0';
}
printf("\nHow many minutes a day do you exercise?\n\nInput Specifications: Please type a positive integer and press the 'Enter' or 'return' key when finished.\n\n");

i = 0;                        
fgets(user_input, sizeof(user_input), stdin);
user_input[strlen(user_input)-1] = '\0';

sscanf_result = sscanf(user_input, "%d", &answer);

if ((sscanf_result == 0) | (sscanf_result == EOF))
{
/* either a non-integer entered or an end-of-line */

printf ("\nPlease type a positive integer and then press the 'Enter' or 'return' key when finished.\n");

free(user_input);
for (i = 0; i < 3; i++)
{
user_input[i] = '\0';
}
continue;
}
if (answer < 10)
{
printf("\nCome on! You kids are soft! You lack discipline!\n");

free(user_input);
for (i = 0; i < 3; i++)
{
user_input[i] = '\0';
 }
 exit(0);
 }
else
{
printf("\nYou may begin training as a ninja!\n");

free(user_input);
for (i = 0; i < 3; i++)
{
user_input[i] = '\0';
}
exit(0);
}
}
else
{
printf("\nInput Error: Please carefully read the input specifications that are provided after each question prompt and then try again.\n");

free(user_input);
for (i = 0; i < 3; i++)
{
user_input[i] = '\0';
}
continue;
}
}
else 
{
printf("\nInput Error: Please carefully read the input specifications that are provided after each question prompt and then try again.\n");

free(user_input);
for (i = 0; i < 3; i++)
{
user_input[i] = '\0';
}
continue;
}
}
return 0;
}