提问人:BenG 提问时间:10/3/2023 最后编辑:Vlad from MoscowBenG 更新时间:10/4/2023 访问量:97
为什么会出现分段错误?代码在 CLion 和 VSC 中工作正常
Why do I get a segmentation fault? The code works fine in CLion and VSC
问:
我目前正在使用锻炼来提高我的编程技能。该代码在我的 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';
答:
0赞
Vlad from Moscow
10/4/2023
#1
对于使用可变长度数组的初学者
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赞
Chris
10/4/2023
#2
来自莫斯科的 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);
}
}
评论
char temp[length + 1];
将为终止 0 留出空间。为什么不在复制时转换为小写?无需两个循环。最后两个循环看起来有点奇怪,你确定这些循环条件是正确的吗?您能否提供一个最小的可重现示例来说明您如何为预期的真和假结果调用它?char arr[length];
length - 1
arr[length]
i < length
malloc
temp[length] = '\0';
?ChatGPT 是一个 f!*&^#!@ 愚蠢的反刍机器,它可以吐出它塞满的任何垃圾。C 数组是从零开始的,所以如果数组的大小是越界的。而 ChatGPT 真的太愚蠢了,无法意识到这一点。ChatGPT 背后的“智能”为零。length
temp
temp[length]