C语言 - 限制字符串长度

3

很抱歉我的英语不好!

我写了一个程序,要求你输入一个密码,长度不能超过八个字符。超出限制的字符将从数组中被删除:

#include <stdio.h>
#define MAXCHAR 8

main()
{
    char password[MAXCHAR];
    int i;
    char c;

    printf("Insert password: MAX 8 CHARS!\n\n");
    for(i = 0; i <= MAXCHAR; i++){
        c = getchar();

        if(i == MAXCHAR){
            break;
        }
        else{
            password[i] = c;
        }
    }

    printf("%s\n", password);
}

程序可以运行,但是存在一个“奇怪”的问题。如果限制为8个字符,而我输入的密码超过了8个字符(例如:P455w0rds98),则输出将会如下所示:

P455w0rd☺

所以它在结尾放上了一个笑脸,我不知道为什么。只有当限制设定为8时才会发生。


稍作修正(无意冒犯):你是指“要求你输入密码”(“数字”有不同的含义,在这里相当令人烦恼)。 - undefined
你应该多了解一下 getchar - undefined
Olaf,如果你期望在这个论坛上看到精确的术语,那你会感到失望的。我很少见到即使是“专家”们也能以一贯、深思熟虑的方式使用正确的术语。 - undefined
1
@BruceDavidWilner 你为什么会说出这样的话? "...计算机编程可能不适合你。" 该死,你把我彻底打击了,当初我只是个菜鸟。 你说的话一点都不鼓励人。 - undefined
3个回答

5

必须指定要打印或终止字符串的长度。否则,您将调用未定义行为。尝试使用以下代码,其中实现了后一种方法。

#include <stdio.h>
#define MAXCHAR 8

int main(void)
{
    char password[MAXCHAR + 1]; /* allocate one more element for terminating null-character */
    int i;
    char c;

    printf("Insert password: MAX 8 CHARS!\n\n");
    for(i = 0; i <= MAXCHAR; i++){
        c = getchar();

        if(i == MAXCHAR){
            break;
        }
        else{
            password[i] = c;
        }
    }
    password[MAXCHAR] = '\0'; /* terminate the string */

    printf("%s\n", password);
}

有些人说if(i == MAXCHAR){ break; }这部分不太好看,所以这里提供另一个代码示例:

#include <stdio.h>
#define MAXCHAR 8

int main(void)
{
    char password[MAXCHAR + 1]; /* allocate one more element for terminating null-character */
    int i;

    printf("Insert password: MAX 8 CHARS!\n\n");
    /* read exactly 8 characters. To improve, breaking on seeing newline or EOF may be good */
    for(i = 0; i < MAXCHAR; i++){
        password[i] = getchar();
    }
    password[MAXCHAR] = '\0'; /* terminate the string */
    getchar(); /* to match number of call of getchar() to the original: maybe for consuming newline character after 8-digit password */

    printf("%s\n", password);
}

1
for(i = 0; i <= MAXCHAR; i++)...你确定吗?不是像9个元素吗?你可以把整个break;的东西去掉。 - undefined
@SouravGhosh 会读取9个字符,但只会存储8个字符加上空字符。这可能是一个奇怪的规定,但我认为它并不无效。 - undefined
1
@MikeCAT 这会误导用户,让他们以为密码是9个字符。 - undefined
@EugeneSh。它可能包括8个字符和换行符,但此处不允许使用7个字符或更少的密码...“MAX”是什么意思? - undefined
1
根据你的代码,@MikeCAT,结果是8 + 换行。不过,这整个"if-break"的东西都是一种胡说八道。 - undefined
显示剩余4条评论

0
所有C风格的字符串都有一个终止字符\0(值为0)。这与任何其他字符值都不同,因此可以用它来表示字符串的结尾。你看到的笑脸只是一部分相邻内存块的一部分,恰好在第一个字节后面有一个空字符(因此只有一个额外的字符)。printf函数从给定的字符串中读取字节,直到遇到\0为止。要解决你的问题,你可以选择写入
password[MAXCHAR] = '\0';

(你需要在数组中额外预留一个字节,用于\0)。

或者你可以从一开始就将数组清零:

char password[MAXCHAR + 1] = { };

或者使用 memset

memset(password, '\0', sizeof password);

0
除了你已经从MikeCAT那里得到的答案之外,另一种方法是使用fgets()来读取用户输入。
在这种情况下,你不需要对每个字符输入进行计数,你可以指定最大大小并完成。就像这样
 fgets(password, MAXCHAR, stdin);

可以为您完成工作,减少每个元素的循环和赋值。

但是有一件事需要记住,对于比给定长度更短的输入,fgets() 也会读取并存储尾随的换行符,您可能需要手动去除它。请阅读链接的 man 页面获取更多想法。

话虽如此,在托管环境中,main() 是非常糟糕且几乎是非标准的。您应该使用 int main(void),至少要符合标准。


fgets函数以实际读取MAXCHAR - 1个字符,并将最后一个字符用于字符串结束。它还会在读取到第MAXCHAR-1个字符后停止读取,无论该字符是否为换行符。因此,使用fgets时可能会遇到接受最多6个字符+换行或7个字符(流中仍保留着换行符)的问题,这使得精确达到最大字符数更加困难。 - undefined
@tofro 你为什么这样认为呢?1)MAXCHAR 需要调整,它不是一个固定值。2)你必须检查并删除尾部的换行符(如果有的话),然后检查字符串的长度,那里有什么问题吗?3)在这里,流中仍然存在一个换行符并不应该是太大的问题,对吧? - undefined
@SouravGosh 主要问题是:一旦用户提供了最大字符数,fgets不会等待密码的确认 - 这至少令人恼火,但可能导致各种错误。虽然能工作,但我永远不会在生产代码中使用它。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接