一道Leetcode题引发的思考:Segmentation fault是什么?

在Leetcode上刷题时,刷到题目Valid Anagram,给定两个字符串st,编写一个函数来肯定t是不是s的一个anagram,谷歌翻译对anagram的解释是经过从新排列另外一个单词的字母顺序而组成的一个新单词,好比cinema是iceman的anagram。本质就是判断st是否有同样的字母组成。算法

什么是Segmentation fault

我看到这个题目的第一印象就是对字符串st中的字母排序,而后逐一比对,若是所有相同,就返回true,不然返回false数组

#include <string.h>
#include <stdlib.h>
#include <stdbool.h>

int charcmp(const void *a, const void *b) {
    return *(char *)a - *(char *)b;
}

bool isAnagram(char* s, char* t) {
    int i;
    int s_len;
    int t_len;

    s_len = strlen(s);
    t_len = strlen(t);
    if (s_len != t_len) {
        return false;
    }
    qsort(s, s_len, sizeof(s[0]), charcmp);
    qsort(t, t_len, sizeof(t[0]), charcmp);
    for (i = 0; i < s_len; i++) {
        if (s[i] != t[i]) {
            return false;
        }
    }
    return true;
}

程序编译没有任何问题,但运行出错,提示Segmentation fault (core dumped)。咦!好像见过,这不社区来着。查了查维基,存储器段错误会出如今当程序企图访问CPU没法定址的存储器区块时。函数

产生Segmentation fault的情景

stackoverflow上的一个回答有更详细的解释,存储器段错误是因为访问没有权限的内存而致使的一种错误,它能够防止破坏内存和引入难调试的内存bug。
在C语言中有不少情景都会致使存储器段错误,如对一个空指针解引用(dereference),性能

int *p = NULL;
*p = 1;

另外一种常见缘由是对只读内存区域执行写操做,这也是上段程序产生bug的缘由。翻译

char *str = "Foo";
*str = 'b';

还有一种就是悬空指针,它指向根本不存在的东西。指针

char *p = NULL;
{
    char c;
    p = &c;
}

p是一个悬空指针,由于变量c是代码块做用域,代码执行后,就被销毁了,不复存在。此时,若是对p进行解引用,就可能会出现存储器段错误,此处的代码在gcc下并无报错,是由于程序简单。调试

解决问题

st是字符串常量,是不可修改的,我想对它从新排序,势必须要改变字符串常量。解决办法就是复制一份,对复制后的字符数组排序。code

bool isAnagram(char* s, char* t) {
    int i;
    int s_len;
    int t_len;
    char *s_cpy;
    char *t_cpy;

    s_len = strlen(s);
    t_len = strlen(t);
    s_cpy = (char *)malloc(sizeof(char)*s_len);
    t_cpy = (char *)malloc(sizeof(char)*t_len);
    strcpy(s_cpy, s);
    strcpy(t_cpy, t);

    if (s_len != t_len) {
        return false;
    }
    qsort(s_cpy, s_len, sizeof(s_cpy[0]), charcmp);
    qsort(t_cpy, t_len, sizeof(t_cpy[0]), charcmp);
    for (i = 0; i < s_len; i++) {
        if (s_cpy[i] != t_cpy[i]) {
            return false;
        }
    }
    return true;
}

问题解决了,不过对于这个问题还有更好的算法,使用哈希表。排序

bool isAnagram(char* s, char* t) {
    char alphabet[26];
    char *ptr;
    int i;
    
    for (i = 0; i < 26; i++) {
        alphabet[i] = 0;
    }
    for (ptr = s; *ptr != '\0'; ptr++) {
        alphabet[*ptr-'a']++;
    }
    for (ptr = t; *ptr != '\0'; ptr++) {
        alphabet[*ptr-'a']--;
    }
    for (i = 0; i < 26; i++) {
        if (alphabet[i] != 0) {
            return false;
        }
    }
    return true;
}

排序是须要成本的,使用哈希表就能够节省下这个资源,性能就快了很多,哈希是4ms,上一个排序则是24ms。ip


参考资料

相关文章
相关标签/搜索