【问题标题】:Segmentation Error in c, week 2 caesar, cs50x harvard coursec 中的分割错误,第 2 周凯撒,cs50x 哈佛课程
【发布时间】:2021-05-21 10:53:26
【问题描述】:

所以我参加了哈佛 cs50 在线课程(2021x 版)的第 2 周。我们应该编写一个加密文本的程序,将每个字母的 ASCII 码移动一定的量,由用户通过命令行决定。 Here is the full problem. 我快完成了,但是当我尝试运行程序时(它编译得很好),它告诉我有一个分段错误。我真的不明白这个问题。我读过这个问题与访问无法访问的某个内存部分有关?我该如何解决这个问题?先感谢您! 这是我的代码..

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

int main(int argc, string argv[])
{
    int k, i;
    if (argc == 2 && isdigit(argv[1]) && argv[1] > 0)
    {
        k = (int) argv[1];
        string plaintext = get_string("plaintext: ");
        printf("cyphertext: ");
        for (i = 0; i < strlen(plaintext); i++)
        {
            if (islower(plaintext[i]) || isupper(plaintext[i]))
            {
                printf("%c", (((plaintext[i] + k) - 97) % 26) + 97);
                return 0;
            }
            
        }
    }
    else
    {
        printf("Usage: ./caesar key");
        return 1;
    }
}

【问题讨论】:

  • Debugging is a useful skill, now would be a great time to try it. 至少调试器会提示您崩溃发生的位置。
  • 你能显示string类型的声明吗? argv[1]是指向字符串的指针,(int) argv[1]不能得到argv[1]的十进制值,而是字符串的地址。对不起我的英语不好。
  • 其他异常可见:argv[1]&gt;0 不是一个定义明确的操作(再次指针),return 0 在处理完第一个字母后看起来也有点不合适。
  • @guapi 好像是typedef char *string;,见github.com/cs50/libcs50/blob/develop/src/cs50.h
  • isdigit(argv[1]) 应该是isdigit(*argv[1])(或isdigit(argv[1][0])。 k = (int) argv[1]; 应该是 k = atoi(argv[1]); 或使用 strtol 的类似名称。

标签: c segmentation-fault cs50 caesar-cipher


【解决方案1】:

我正在参加哈佛 cs50 在线课程的第 2 周

我很遗憾听到这个消息。您的大多数问题都源于糟糕的 CS-50 类,它诱使您相信 C 不知何故有一个预制的、糖衣的字符串类。它没有,它只有以空终止结尾的原始字符数组,因此大多数字符串操作都是手动的。

其他问题来自于编译器向您指出错误时不听。这里有一些:

  • isdigit(argv[1]) 没有意义。一个好的编译器会告诉你很多,例如 clang:

    警告:从“string”(又名“char *”)转换为更小的整数类型“int”

    您将指针与字符串进行比较,而 isdigit 需要单个字符。为了使用isdigit,您必须在循环中为字符串的每个字符调用它。

  • argv[1] &gt; 0 没有意义,因为它将指针与 0 进行比较。

    错误:指针和零之间的有序比较

  • k = (int) argv[1]; 也没有意义。

    警告:从“string”(又名“char *”)转换为更小的整数类型“int”

    要将字符串转换为整数,必须使用strtol 函数,例如k = strtol(argv[1], NULL, 10)。它附带了您可能想要使用的各种错误处理。

    因为k 包含废话 - 实际上它包含转换为整数的内存地址,plaintext[i] + k 也变得废话。

  • if (islower(plaintext[i]) || isupper(plaintext[i])) 没有意义,它说“如果一个字符是小写还是大写”。嗯,大概是吧?相反,您可能打算使用 touppertolower 以大写或小写形式进行所有计算,无论用户输入什么。

【讨论】:

    【解决方案2】:

    您应该分别检查小写字符和大写字符。 如果角色是较低的角色,你是对的。你应该减去 97。但是如果字符是大字符你应该减去 65。否则在模式操作之前你会得到一个否定的结果,这会导致分段错误。

    if(isupper(plainText[i])){
                    
                    cipherText[i] = (((plainText[i] - 65 + key) % 26) + 65);
                    
                } else {
    if(islower(plainText[i])){
                    
                    cipherText[i] = (((plainText[i] - 97 + key) % 26) + 97);
                        
                    }
                }
    

    【讨论】:

    • 不,不是这样。它在isdigit 崩溃。
    • 你是对的,但这也是另一个问题吗?
    • 这也是个问题。不是 segfaulty (将任何 int 值分配给 char 将做一些明确定义的事情),更多“不正确的结果”。无论如何,建议 65 和 97 不是最好的,用 'a' 和 'A' 代替呢?
    • (提示 ebcdic 人群“b-b-但不连续的字母编码”):)
    • 感谢您的建议!我什至没有注意到它,但它是有道理的。像预期的其他 cmets 一样,它并没有解决段错误。
    猜你喜欢
    • 2020-08-02
    • 1970-01-01
    • 2020-12-03
    • 2020-10-20
    • 1970-01-01
    • 2021-12-20
    • 1970-01-01
    • 2018-12-28
    • 2015-01-08
    相关资源
    最近更新 更多