Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/69.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 我应该如何让用户输入我想要的信息?_C_Cs50_Caesar Cipher - Fatal编程技术网

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

C 我应该如何让用户输入我想要的信息?,c,cs50,caesar-cipher,C,Cs50,Caesar Cipher,我刚开始学计算机科学 我在哈佛在线学习CS50课程。 我正在解决一个问题,我需要从命令行中的用户那里获取密钥, 然后是纯文本,然后将该文本转换为ASCII码中的关键数字量,生成密文 这是我到目前为止得到的 #include <stdio.h> #include <string.h> #include <ctype.h> #include <math.h> int main(int argc, string argv[]) { if (ar

我刚开始学计算机科学

我在哈佛在线学习CS50课程。 我正在解决一个问题,我需要从命令行中的用户那里获取密钥, 然后是纯文本,然后将该文本转换为ASCII码中的关键数字量,生成密文

这是我到目前为止得到的

#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密钥\n

到目前为止,我所能想到的唯一方法是使用argc!=2. 因此,我至少可以确保用户只在程序名称上方输入一个命令

但问题是,如果用户输入其他内容,例如 凯撒你好 /凯撒·约洛

该程序仍在运行

我在想我能做些什么来防止这种情况发生


非常感谢您抽出时间阅读本文和帮助。

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

因此,为了确保用户提供了一个数字作为唯一参数,您可以执行以下操作:

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], &end, 10);    // ensure not empty and numeric
        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;
    }
    ...

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

因此,为了确保用户提供了一个数字作为唯一参数,您可以执行以下操作:

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], &end, 10);    // ensure not empty and numeric
        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;
    }
    ...

重新表述您的问题:您希望对用户输入执行验证,其中唯一合法的输入值是数字字符串:123、4534和000都可以被认为是有效的,但hello world和f00和132是无效的

在包括C在内的大多数编程语言中,字符串或多或少只是单个字符元素的数组。换句话说,字符是一种原始数据类型,但字符串不是。。。。C根本没有字符串数据类型。提示:看看您声明main的方式。那么,您如何利用这一优势来验证该程序的输入呢?很简单:输入字符串中的每个字符必须来自域[0123456789]加上结尾处的空终止符\0

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

int num;
int y = scanf("%d", &num);
然后检查y的值。它将被设置为scanf读取的有效输入数,因此如果给定一个数字,它将为1


注意:正如在评论中提到的,这也会接受像123abc这样的东西,它会去掉数字并忽略结尾的字符。如果绝对必须只有数字作为输入,scanf可能不是正确的函数。在这种情况下,使用fgets将输入读取为字符串,然后在每个输入上循环检查它是否来自有效的输入域可能是一种更好的方法。

重新表述您的问题:您希望对用户输入执行验证,其中唯一合法的输入值是数字字符串:123、4534和000都可以被视为有效,但是hello world和f00以及一百三十二是无效的

在包括C在内的大多数编程语言中,字符串或多或少只是单个字符元素的数组。换句话说,字符是一种原始数据类型,但字符串不是。。。。C根本没有字符串数据类型。提示:看看您声明main的方式。那么,您如何利用这一优势来验证该程序的输入呢?很简单:输入字符串中的每个字符必须来自域[0123456789]加上结尾处的空终止符\0

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

int num;
int y = scanf("%d", &num);
然后检查y的值。它将被设置为scanf读取的有效输入数,因此如果给定一个数字,它将为1

注意:正如在评论中提到的,这也会接受像123abc这样的东西,它会去掉数字并忽略结尾的字符。如果绝对必须只有数字作为输入,scanf可能不是正确的函数。在这种情况下,使用fgets将输入读取为字符串,然后在每个输入上循环以检查它是否来自
有效的输入域可能是一种更好的方法。

看起来您在初始if之后缺少了一个else?我建议使用'a'而不是65,使用'a'而不是97。我非常确定您的main应该是int main argc,char*argv[]除非我落后于C++,否则c.1005HON罗伯茨- ReNetra Munic的字符串类型是很好的一点,这是C还是C++?看起来你在初始的If之后丢失了另一个?我建议使用“A”而不是65和“A”而不是97。我很确定你的main应该是int alqc,char *avg[]。除非我落后于C++,否则C.1005HON罗伯茨- ReNetra Munic的字符串类型不好,这是C还是C++?当使用Strtol时,结果值超出范围。errno应该对照ERANGE进行检查。@lxerx:如果值超出范围,则始终返回负值的LONG_MAX或LONG_LMIN。因此,它可能不是给定的值,但仍然可以用作键。无论如何,对caesar密码使用大于26的密钥并没有真正意义……如果使用大于26的密钥并没有真正意义,那么超出该范围的值,即负值和大于26的值也应该被拒绝。所以它可能不是给定的值。。。总的来说,这是一个大问题。@lxerx:我必须承认我在吹毛求疵。。。当然,您是对的,并且应该始终测试超出范围的值:-。我的评论只是坚持strtol即使在超出范围的情况下也要返回合理的值。当使用strtol时,结果值可能超出范围。errno应该对照ERANGE进行检查。@lxerx:如果值超出范围,则始终返回负值的LONG_MAX或LONG_LMIN。因此,它可能不是给定的值,但仍然可以用作键。无论如何,对caesar密码使用大于26的密钥并没有真正意义……如果使用大于26的密钥并没有真正意义,那么超出该范围的值,即负值和大于26的值也应该被拒绝。所以它可能不是给定的值。。。总的来说,这是一个大问题。@lxerx:我必须承认我在吹毛求疵。。。当然,您是对的,并且应该始终测试超出范围的值:-。我的评论只是坚持strtol即使在超出范围的情况下也要返回合理的值。但是,如果输入是123abc,那么scanf仍然会在无效输入时返回1。不,我不是否决你答案的人,请随意使用我答案中的%1s部分来解决@lxerx提出的问题,也不是否决你答案的人……好的观点。我添加了一个注释来解释scanf在本例中的行为。我认为对于OP来说,这仍然是一个很好的方法,因为它将复杂性降到最低,只要这个警告被理解,所以我现在就把它放在这里,不管反对者是否投反对票:但是如果输入是,例如,123abc,那么scanf仍然会在无效输入时返回1。不,我不是否决你答案的人,请随意使用我答案中的%1s部分来解决@lxerx提出的问题,也不是否决你答案的人……好的观点。我添加了一个注释来解释scanf在本例中的行为。我认为这对于OP来说仍然是一个很好的方法,因为它最大限度地降低了复杂性,只要我们理解了这个警告,所以我现在就把它放在这里,不管反对者是否投了反对票: