【问题标题】:My constant is changing, and I dont know why, or even how我的常数在变化,我不知道为什么,甚至如何
【发布时间】:2022-01-14 19:33:33
【问题描述】:

我正在制作一个基本上“加密”文本的程序,方法是用其他字母替换字母。所以你基本上运行程序并输入一个分布,然后输入你想要加密的文本,它会给你返回密码。

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

string make_lower(string word);

int main (int argc, string argv[])
{
    //we examine the input
    if (argc < 2 || argc > 2)
    {
        printf("Usage: ./substitution key\n");
        return (1);
    }
    
    if (strlen(argv[1]) != 26)
    {
        printf("Key must contain 26 characters.\n");
        return (1);
    }
    
    if (strlen(argv[1]) == 26)
    {
        for (int i = 0; i < 26; i++)
        {
            if (isdigit(argv[1][i]))
            {
                printf("Key must onlyontain alphabetic characters.\n");
                return (1);
                exit(0);
            }
        }
        
        for (int i = 0; i < 26; i++)
        {
            for (int o = i + 1; o < 26; o++)
            {
                if (argv[1][i] == argv[1][o])
                {
                    printf("Key must not contain repeated characters.\n");
                    return (1);
                    exit(0);
                }
            }
        }
        
        //we prompt the user for the words to transcribe
        const string text = get_string("plaintext:  ");
        
        //we set everithing in lower caso to compare it, and set a new variable to store the original text so we can convert the 
        // upper cases back later
        string ntext = text;
        
        printf("%s\n", text);
        
        argv[1] = make_lower(argv[1]);
        
        ntext = make_lower(ntext);
        
        printf("%s\n", text);
        
        string alphabet = "abcdefghijklmnopqrstuvwxyz";
        
        //we substitute the text to the desired outcome
        for (int i = 0, n = strlen(ntext); i < n; i++)
        {
            for (int o = 0; o < 26; o++)
            {
                if (ntext[i] == alphabet[o])
                {
                    ntext[i] = argv[1][o];
                }
            }
        }
        
        printf("%s\n", text);
        
        printf("ciphertext: ");
        
        for (int i = 0, n = strlen(ntext); i < n; i++)
        {
            if (isupper(text[i]))
            {
                printf("%c", toupper(ntext[i]));
            }
            else
            {
                printf("%c", ntext[i]);
            }
        }
        
        printf("%s\n", text);
        
        printf("\n");
        
        return(0);
        
        exit(0);
    }
}

string make_lower(string word)
{
    for (int i = 0; i < strlen(word); i++)
    {
        word[i] = tolower(word[i]);
    }
    
    return(word);
}

所以我的问题出在代码的输出上,因为问题是如果你想要加密的文本是“Hello”,它应该出现像“Ktlly”这样的例子,但我的输出是“ktlly ",因此结果中不会显示大写字母。

当您输入要加密的代码时,程序将其存储在一个常量字符串中,然后创建一个新变量并将其设置为等于您输入的文本,然后程序将该新变量转换为小写,以便它可以进行比较,最后,当我们将文本加密时,我尝试通过创建一个 if 语句(在第 82 行)将那些我想要的字符再次变为大写,但事实并非如此。我试图看看为什么,这就是为什么我设置在第 56、62、78 和 94 行打印常量,看看为什么它不起作用,结果发现变量正在改变,即使应该是成为一个常数。起初在第 56 行,它仍然是原始文本;然后在第 62 行,它的文本相同,但小写;然后在第 78 行和第 94 行,它本身被修改为文本的加密版本。

基本上就是这样,我不知道为什么会这样。至少对我来说,代码似乎是正确的,我的理论是它与函数有关,或者与内置漏洞代码的大“if”语句有关。感谢您通读所有这些。

【问题讨论】:

    标签: c cs50


    【解决方案1】:

    以下注释有误:

    //we set everithing in lower caso to compare it, and set a new variable to store the original text so we can convert the 
    // upper cases back later
    string ntext = text;
    

    cs50.h 中定义的标识符string 只不过是数据类型char *typedef。这意味着string 类型的变量实际上并不包含字符串,而只是指向一个字符串。

    在上面引用的行中,您只是在复制指针,而不是实际的字符串。由于ntexttext现在都指向同一个字符串,所以当你修改ntext指向的字符串时,你也在修改text指向的字符串。这似乎不是您想要的。

    如果要创建字符串的副本,而不是只复制指针,则必须先使用malloc为新字符串分配内存,然后才能使用strcpy复制字符串:

    //allocate memory for copy of the string
    string ntext = malloc( strlen(text) + 1 ); //add 1 for the terminating null character of the string
    
    //copy the string
    strcpy( ntext, text );
    

    大多数编译器还支持函数strdup,它在单个函数调用中处理内存分配和字符串复制。如果您的编译器支持该功能,那么您可以使用它:

    string ntext = strdup( text );
    

    请注意,所有内存分配函数,例如mallocstrdup,都可能会失败,例如当操作系统内存不足时。在这种情况下,函数mallocstrdup 将返回一个NULL 指针。如果你使用这样的NULL 指针而不事先检查它是否是NULL,那么你的程序很可能会崩溃。出于这个原因,我上面发布的代码实际上很糟糕,因为它在取消引用指针之前没有检查NULL

    因此,下面的代码会更好,它检查NULL的返回值,如果内存分配失败,则打印错误消息并退出程序:

    对于malloc/strcpy

    //allocate memory for copy of the string
    string ntext = malloc( strlen(text) + 1 );
    
    //verify that allocation was successful
    if ( ntext == NULL )
    {
        fprintf( stderr, "memory allocation error!\n" );
        exit( EXIT_FAILURE );
    }
    
    //copy the string
    strcpy( ntext, text );
    

    对于strdup

    string ntext = strdup( text );
    
    if ( ntext == NULL )
    {
        fprintf( stderr, "memory allocation error!\n" );
        exit( EXIT_FAILURE );
    }
    

    【讨论】:

    • 谢谢,我有一个问题,malloc 代码是如何工作的?我对编程很陌生,所以我只知道基础知识
    • malloc 为您提供一些可以使用的全新内存。在需要之前不要想太多。
    • @DavidC.Rankin:实际上,根据链接文档,strdup 应该成为 ISO C23 的一部分。据我所知,所有主要的编译器都已经支持它。因此,我认为值得一提的是 strdup 如果 OP 的编译器支持它,则可能可以使用它。但我也提供了符合 ISO-C17 的解决方案。
    • @DavidC.Rankin strdup() 在某个库中?
    • @Laughcheeta1:你好像在上CS50课程,指针和动态内存分配在week 4 of the course中解释。我相信大卫马兰能比我更好地解释它。 :-)
    【解决方案2】:

    make_lower 覆盖了它的论点。您需要复制string。考虑使用strdup()

    我有点惊讶这没有引发编译器警告。

    string make_lower(string word)
    {
        word = strdup(word);
        //...
    

    【讨论】:

    • 什么意思?
    • 这是怎么回事?该函数采用char *;修改它,并返回它。正常的,惯用的,C.
    • @mevets:答案中的示例是如何修复它。问题中的示例没有strdup,因此当他传递给make_lower() 的字符串发生变化时,OP 会感到惊讶。无论如何,安德烈斯发布的答案比我的两分钟版本更好。
    • 好吧,我只是无法想象为什么编译器会想要警告完全正常和有效的 C。我不明白 OP 认为赋值复制了字符串;也许 cs50 的人应该重新考虑他们的抽象。
    • @mevets:在我看来,他将const string 传递给了需要string 的东西。这会产生一个警告。
    猜你喜欢
    • 2021-01-25
    • 1970-01-01
    • 1970-01-01
    • 2017-05-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-13
    相关资源
    最近更新 更多