我目前正在使用锻炼来提高我的编程技能。该代码在我的 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';
行,但这并不能解决问题。
对于使用可变长度数组的初学者
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
来自莫斯科的 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);
}
}