【问题标题】:Why am I getting a message segmentation fault?为什么我收到消息分段错误?
【发布时间】:2022-01-21 00:56:53
【问题描述】:

使用 C,我正在尝试实现一个函数,该函数根据密钥 string_wordword 转换为 mutated_word。例如:当word"HE" 时,使用键"QWERTYUIOPASDFGHJKLZXCVBNM",mutated_word 应该变成"IT"。但它总是给出分段错误,不知道如何改进。

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

int main(void) {
    string word = "HE" ;
    string string_word = "QWERTYUIOPASDFGHJKLZXCVBNM";
    char mutated_word[strlen(word)]; 
    
    for (int i = 0; word[i] != '\0'; i++) {
        string_word[(int)word[i] - 65] = mutated_word[i];
    }
    
    printf("%s", mutated_word);
}

【问题讨论】:

  • 我猜你的意思是mutated_word[i] = string_word[word[i]-65],但你还必须用\0字节终止mutated_word
  • 感谢您的回复。好的,谢谢!!
  • 另请注意:mutated_word 的长度必须为 strlen(word)+1 才能适合终止的 \0 字节。

标签: c cs50


【解决方案1】:
  1. 您需要用空字符终止新字符串。
  2. 您的数组太小
  3. 为索引使用正确的类型(int 不正确)
  4. 检查字符是否为字母。如果不决定做什么(在我的示例中,我将所有字母转换为大写,其他字符保持原样)
  5. 不要使用幻数。而不是65 使用'A'
  6. 你的任务错了,你实际上想要相反的东西。
  7. 它不适用于所有字符编码。
#include <ctype.h>
#include <stdio.h>

int main (void) 
{
    string word = "HE" ;
    string string_word = "QWERTYUIOPASDFGHJKLZXCVBNM" ;
    char mutated_word [strlen(word) + 1]; 
    
    size_t i;
    for (i = 0; word[i] != '\0'; i++)
    {
        if(isalpha((unsigned char)word[i]))
        {
            mutated_word[i] = string_word[toupper((unsigned char)word[i]) - 'A'];
        }
        else
        {
            mutated_word[i] = word[i];
        }
    }
    mutated_word[i] = 0;
   
    printf("%s", mutated_word); 
}

https://godbolt.org/z/4zqq98Y3n

为了使其更便携:

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

ptrdiff_t findIndex(const char ch, const char * restrict dict)
{
    char *result = strchr(dict, ch);
    if(!result) return -1;
    return result - dict;
}

int main (void) 
{
    string word = "He124" ;
    string string_word = "QWERTYUIOPASDFGHJKLZXCVBNM" ;
    string dict = "ABCDEFGHIJKLMNOPQRSTUVXYWZ";
    ptrdiff_t index;
    char mutated_word [strlen(word) + 1]; 
    
    size_t i;
    for (i = 0; word[i] != '\0'; i++)
    {
        if(isalpha((unsigned char)word[i]))
        {
            index = findIndex(toupper((unsigned char)word[i]), dict);
        }
        else index = -1;
        mutated_word[i] = index == -1 ? word[i] : string_word[index];

    }
    mutated_word[i] = 0;
   
    printf("%s", mutated_word); 
}

https://godbolt.org/z/KW8TxxEvq

【讨论】:

  • 您可能还会评论说,尽管使用'A'&lt;ctype.h&gt; 宏使代码更便携,但它仍然默默地假设从AZ 的字母形成一个连续的块,即EBCDIC 中的情况并非如此 :)
  • @chqrlie 添加了更便携的版本
  • 对不起,不能投票两次......但我会删除在这种情况下没用的restrict,并且因为result指向同一个数组而有些不正确。
  • 我不相信ssize_t 已经进入标准C。使用int 似乎没问题,因为要设置一个result - dict 超过INT_MAX 的字典需要不正常的思维。
  • @chqrlie 我不记得 ssize_t 不是标准的。更改为更标准的类型(也更正确)
【解决方案2】:

由于赋值顺序错误,您的程序崩溃:string_word[(int)word[i] - 65] = mutated_word[i]; 正在尝试修改具有未定义行为的字符串文字。另请注意,对于空终止符,目标字符串必须长 1 个字节,您必须明确设置。

这是一个更便携的版本:

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

int main(void) {
    const char *word = "HE";
    const char *normal_word = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    const char *string_word = "QWERTYUIOPASDFGHJKLZXCVBNM";
    char mutated_word[strlen(word) + 1]; 
    unsigned char c;
    const char *p;
    size_t i;

    for (i = 0; (c = word[i]) != '\0'; i++) {
        if (isupper(c) && (p = strchr(normal_word, c)) != NULL) {
            c = string_word[p - normal_word];
        } else
        if (islower(c) && (p = strchr(normal_word, toupper(c))) != NULL) {
            c = string_word[p - normal_word];
            c = tolower(c);
        }
        mutated_word[i] = c;
    }
    mutated_word[i] = '\0';
   
    printf("%s\n", mutated_word); 
    return 0;
}

【讨论】:

    【解决方案3】:

    这是因为您超出了 string_word[] 的大小,请注意每个示例 'Z'-65 == 25 大于 (int)strlen(string_word)

    【讨论】:

    • 对于i=0,程序更有可能立即崩溃,因为string_word[(int)word[i] - 65] = mutated_word[i] ; 正在尝试修改字符串文字。
    • @chqrlie 我从未使用过 cs50.h 库,所以我不知道它是不可变的,我注意到我错了。
    猜你喜欢
    • 2021-01-12
    • 1970-01-01
    • 2015-01-25
    • 1970-01-01
    • 2014-04-12
    • 2022-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多