如何让用户输入我想要的信息?

huangapple go评论81阅读模式
英文:

How should I make users to put in the info that I want?

问题

我刚刚开始学习计算机科学。

我正在通过哈佛大学在线教授的CS50课程学习。
嗯,我正在解决一个问题,我需要从用户那里在命令行中获取密钥,然后获取明文,然后将该文本按ASCII中的密钥数量进行移位,以生成密文。

以下是我迄今为止的代码。

#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <math.h>

int main(int argc, string argv[])
{
    if (argc != 2)
    {
        printf("Usage: ./caesar key\n");
    }

    {
        string plaintext = get_string("plaintext:  ");

        int key = atoi(argv[1]);
        int n = strlen(plaintext);
        char chr[n];

        printf("ciphertext: ");
        for (int i = 0; i < n; i++)
        {
            chr[i] = plaintext[i];
            if (isalpha(chr[i]))
            {
                if (isupper(chr[i]))
                {
                    chr[i] = (chr[i] - 65 + key) % 26 + 65;
                    printf("%c", chr[i]);
                }
                else if (islower(chr[i]))
                {
                    chr[i] = (chr[i] - 97 + key) % 26 + 97;
                    printf("%c", chr[i]);
                }
            }
            else
            {
                printf("%c", chr[i]);
            }
        }
        printf("\n");
    }
}

嗯,我知道这看起来有点混乱,但这是我在全职工作的第二周学习编程。

无论如何,我希望用户能够通过以下方式运行此程序:
./caesar "密钥的任何数字"。

如果用户输入其他内容,我想要打印:
"Usage: ./caesar key\n"。

到目前为止,我唯一能想到的方法是使用 argc != 2 的 if 语句,这样至少我可以确保用户在程序名称之上只输入了一个命令。

但问题是,如果用户输入其他内容,例如:
./caesar HELLO
./caesar YolO

程序仍然会运行。

我正在尝试找出如何防止这种情况发生。

非常感谢您花时间阅读并提供帮助。

英文:

I just started learning computer science.

I'm studying through CS50 taught at Harvard online.
Well, I'm working on this one problem where I need to get the key from the user in command line,
then a plaintext, and then shift that text for key amount of numbers in ASCII to make a ciphertext.

here is what I've got so far.

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;ctype.h&gt;
#include &lt;math.h&gt;

int main(int argc, string argv[])
{
    if (argc != 2)
    {
        printf(&quot;Usage: ./caesar key\n&quot;);
    }

    {
        string plaintext = get_string(&quot;plaintext:  &quot;);

        int key = atoi(argv[1]);
        int n = strlen(plaintext);
        char chr[n];

        printf(&quot;ciphertext: &quot;);
        for (int i = 0; i &lt; n; i++)
        {
            chr[i] = plaintext[i];
            if (isalpha(chr[i]))
            {
                if (isupper(chr[i]))
                {
                    chr[i] = (chr[i] - 65 + key) % 26 + 65;
                    printf(&quot;%c&quot;,chr[i]);    
                }
                else if (islower(chr[i]))
                {
                    chr[i] = (chr[i] - 97 + key) % 26 + 97;
                    printf(&quot;%c&quot;,chr[i]);    
                }            
            }
            else
            {
                printf(&quot;%c&quot;,chr[i]);        
            }
        }
    printf(&quot;\n&quot;);
    }
}

well I know this seems very floppy but man it's my second week into programming while working full time.

anyways, I'm trying to have the user to run this program by using
./caesar "any number for the key".

if the user puts in any other things, then I'd like to print
"Usage: ./caesar key\n"

so far the only way i can think of is making the if statement with argc != 2
so that I can at least make sure the user puts in just one command on top of the program's name.

but the problem is that if the user puts in other things such as
./caesar HELLO
./caesar YolO

the program still runs.

I'm trying to figure out what I can do in order to prevent that from happening.

Really appreciate your time for reading this and help.

答案1

得分: 5

这是为什么旧的 atoi 函数被 strtol 取代的原因。前者仅尝试从给定字符串中转换初始数值部分,而后者还会告诉您转换部分后面的内容。

因此,为了确保用户只提供了一个数字作为唯一参数,您可以这样做:

int main(int argc, char *argv[]) {
    long key;
    int reject = 0;

    if (argc != 2) {                         // 确保只有一个参数
        reject = 1;
    }
    else {
        char *end;
        key = strtol(argv[1], &end, 10);    // 确保不为空且为数字
        if ((*end != 0) || (end == argv[1])) reject = 1;
     }
    if (reject) {
        printf("Usage: %s key\n", argv[0]);
        return 1;
    }
}

sscanf 也可以用来实现相同的目标。它甚至允许在数字后面有空白字符,但由于 argv 数组是用空格分隔的,这不应该发生:

int main(int argc, char *argv[]) {
    int key;
    char empty[2];

    if ((argc != 2) || (sscanf(argv[1], "%d%1s", &key, empty) != 1)) {
        printf("Usage: %s key\n", argv[0]);
        return 1;
    }
    // 其他操作...
}
英文:

That is the reason way the old atoi function has been superseded by strtol. The former only try to convert an initial numeric part from the given string, while the latter also tells what remains after the converted part.

So to make sure that the user has given a number as sole argument, you could do:

int main(int argc, char *argv[]) {
    long key;
    int reject = 0;

    if (argc != 2) {                         // ensure one argument
	    reject = 1;
    }
    else {
    	char *end;
    	key = strtol(argv[1], &amp;end, 10);    // ensure not empty and numeric
    	if ((*end != 0) || (end == argv[1])) reject = 1;
     }
    if (reject) {
    	printf(&quot;Usage: %s key\n&quot;, argv[0]);
	return 1;
}

sscanf could be used too. It even allows blank characters after the number, which should not happen as the argv array is blank separated:

int main(int argc, char *argv[]) {
    int key;
    char empty[2];

    if ((argc != 2) || (sscanf(argv[1], &quot;%d%1s&quot;, &amp;key, empty) != 1)) {
    	printf(&quot;Usage: %s key\n&quot;, argv[0]);
	    return 1;
    }
    ...

答案2

得分: -1

为了重述你的问题:你想对用户输入进行验证,其中唯一合法的输入值是数字字符串:1234534000 都可以被视为有效,但 hello worldf00one hundred thirty two 都不是有效的。

在大多数编程语言中,包括 C 语言,字符串基本上只是由单个 char 元素组成的数组(换句话说,char 是一个原始数据类型,但 string 不是... C 没有 string 数据类型。提示:看一下你如何声明 main)。那么,你如何利用这一点来验证程序的输入呢?很简单:输入字符串中的每个字符必须来自域 [0123456789](以及末尾的空字符 \0)。

因此,要解决这个问题,你只需要实现一个检查,验证输入值是否具有这个属性。有许多方法可以做到这一点,其中可能最简单的方法之一是:

int num;
int y = scanf("%d", &num);

然后检查 y 的值。它将被设置为 scanf 读取的有效输入数量(如果给出了数字,它将设置为 1)。

注意: 如评论中所提到的,这也会接受诸如 123abc 这样的输入(它会去掉数字并忽略末尾的字符)。如果你绝对需要只接受数字作为输入,scanf 可能不是正确的函数。在这种情况下,使用 fgets 以字符串形式读取输入,然后循环遍历每个输入以检查它是否来自有效的输入域可能是更好的方法。

英文:

To rephrase your question: You want to perform validation on user input, where the only legal input values are numeric strings: 123 and 4534 and 000 could all be considered valid, but hello world and f00 and one hundred thirty two are not valid.

In most programming languages, including C, strings are more or less just arrays of individual char elements (in other words, char is a primitive data type, but string is not.... C doesn't have a string data type at all. hint: take a look at the way you've declared main). So how can you use that to your advantage to validate the input to this program? Easy enough: every character in the input string must come from the domain [0123456789] (plus the null terminator \0 at the end...).

So to solve this problem, you just need to implement a check that verifies that the inputted value has that property. There are a number of ways to do that, maybe the easiest of which is:

int num;
int y = scanf(&quot;%d&quot;, &amp;num);

then check the value of y. It will be set to the number of valid inputs that scanf read (so it will be 1 if a number was given).

Note:<br> as mentioned in the comments, this will also accept things like 123abc (it will strip off the numbers and ignore the characters at the end). If you absolutely must have only numbers for input, scanf might not be the right function. In that case, using fgets to read the input as a string and then looping over each input to check that it is from the valid input domain might be a better approach.

huangapple
  • 本文由 发表于 2020年1月6日 21:59:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/59613439.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定