为什么会出现分段错误?该代码在 CLion 和 VSC 中运行良好

问题描述 投票:0回答:2

我目前正在使用锻炼来提高我的编程技能。该代码在我的 IDE 中运行良好,但在网站上导致错误消息。我做错了什么以及您将如何改进我的代码?提前谢谢:)

make: *** [makefile:22: test] 分段错误(核心转储)

#include "isogram.h"
#include <string.h>
#include <ctype.h>

bool is_isogram(const char phrase[]) {
    int length = strlen(phrase);
    char temp[length];
    
    for (int i = 0; i < length; i++)
        temp [i] = phrase[i];

    temp[length] = '\0';

    for(int i = 0; temp[i]; i++){
        temp[i] = tolower(temp[i]);
    }

    for(int i = 0; i < length; i++){
        for(int j = i+1; j < length;j++) {
            if (temp[i] == temp[j] && temp[i] != ' ' && temp[i] != '-')
                return false;
        }
    }
    return true;
}

int main(void) {
    char phrase[] = "lumberjacks";
    if (is_isogram(phrase))
        printf("true");
    else
        printf("false");
    return 0;
}

我询问了 ChatGPT,它建议使用

temp[length] = '\0';
行,但这并不能解决问题。

c nested-loops c-strings function-definition tolower
2个回答
0
投票

对于使用可变长度数组的初学者

int length = strlen(phrase);
char temp[length];

不安全且多余。注意函数的返回类型

strlen
是无符号类型
size_t
而不是有符号类型
int

另外调用函数

strlen
也是多余的。您可以根据字符串以终止零字符
'\0'
结束的事实来扫描字符串。

您定义的数组没有空间容纳终止零字符

'\0'
。结果这个作业

temp[length] = '\0';

调用未定义的行为。

在检查字符串是否为等值线之前,先转换变长数组的所有字符

for(int i = 0; temp[i]; i++){
    temp[i] = tolower(temp[i]);
}

效率低下。

短语中的单词不仅可以用空格字符

' '
分隔,还可以用制表符
'\t'
分隔。您还应该排除标点符号。

我会按照以下方式编写函数,如下面的演示程序所示。

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

bool is_isogram( const char phrase[] )
{
    bool isogram = true;

    if (*phrase != '\0')
    {
        for (const char *current = phrase + 1; isogram && *current != '\0'; ++current)
        {
            if (!isblank( ( unsigned char )*current ) && !ispunct( ( unsigned char )*current ))
            {
                char c = tolower( ( unsigned char )*current );

                const char *prev = current;

                while (isogram && prev != phrase)
                {
                    --prev;
                    isogram = tolower( ( unsigned char )*prev ) != c;
                }
            }
        }
    }  

    return isogram;
}

int main( void )
{
    const char *phrase = "lumberjacks";

    printf( "The phrase \"%s\" is isogram: %s\n",
        phrase, is_isogram( phrase ) ? "true" : "false" );
}

程序输出为

The phrase "lumberjacks" is isogram: true

0
投票

来自莫斯科的 Vlad 很好地指出了数组长度的问题,但正如他指出的那样,您使用的数组是不必要的。这个问题的 O(n) 解决方案可能涉及创建直方图:我们将使用 26 元素数组来计算每个字母,其中每个元素对应于英文字母表中的一个字母。然后可以在一次迭代中检查这一点,以确保没有字母出现多次(或者每个字母出现相同的次数)。

我们可以通过在一个函数中执行此操作来提高效率,但这演示了如何将程序分解为更小的问题。

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

int *alpha_histogram(const char *str) {
    int *hist = calloc(sizeof(int), 26);
    if (!hist) return NULL;

    for (const char *ch = str; *ch; ch++) {
         if (!isalpha(*ch)) continue;

         hist[tolower(*ch) - 'a']++;
    }

    return hist;
}

bool is_isogram(const char *str) {
    int *hist = alpha_histogram(str);
    if (!hist) exit(EXIT_FAILURE);

    for (size_t i = 0; i < 26; ++i) {
         if (hist[i] > 1) return false;
    }

    free(hist);

    return true;
}

int main(void) {
    const char *str = "lumberjacks";

    if (is_isogram(str)) {
        printf("\"%s\" is an isogram.\n", str);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.