我正在尝试设计一种算法,该算法可以找到每个给定单词的起始字母,然后将其保存到一个类似于直方图的数组中



首先,我最近才开始学习编码,所以可能很明显我缺少了一些东西。如果是这样的话,我很抱歉。

当给定单词时,算法总是跳过第一个单词,从第二个单词开始。我试着用手分析,但没能找出问题所在。如果有人能帮我,我将不胜感激。

#include <stdio.h>
int main()
{
int n,i;
char word[100][100];
char tmp;
int counter[100];
printf("Enter the number of words ");
scanf("%d", &n);
for(i=0; i<n; i++)
{
printf("Enter the word ");
scanf("%s", word[i]);
}
for(i='a'; i<'z'; i++)
{
counter[i]=0;
}
for(i=0; i<n; i++)
{
tmp=word[i][0];
counter[tmp]=counter[tmp]+1;
}
for(i='a'; i<'z'; i++)
{
printf("%d", counter[i]);
}
return 0;
}

如果没有看到您传递给程序的输入,很难判断为什么第一个单词没有被计数,但我在这里看到的两个问题是:

  1. 您将每个字符的ASCII值视为索引。在ASCII中,"A"的值为65,"Z"为90,"A"为97,"Z"为122。您的计数器数组最多只能达到100,因此尝试访问counter['z']将超出数组界限,并将损坏堆栈上的内存,从而导致意外结果。由于我们只考虑字母,而不是所有的ASCII字符,所以我们应该将数组的大小设为26,并且我们应该通过将每个ASCII字符转换为索引来访问它。这可以通过减去"a"来完成(因此"a"-"a"将产生0的索引,"b"-"a"将产生1的索引,等等(

  2. 你没有考虑大写字母。这些是不同于小写字母的ASCII值范围,在对数组进行索引之前,最好将所有字母转换为小写字母。

这是一个有这两个变化的代码版本:

int main()
{
int n,i;
char word[100][100];
char tmp;
const int numLetters = 'z' - 'a' + 1;
int counter[numLetters];
printf("Enter the number of words ");
scanf("%d", &n);
for(i=0; i<n; i++)
{
printf("Enter the word ");
scanf("%s", word[i]);
}
for(i=0; i<numLetters; i++)
{
counter[i]=0;
}
for(i=0; i<n; i++)
{
tmp=word[i][0];
//convert the letter to lowercase
tmp=tolower(tmp);

//subtract tmp-'a' to get the array index
counter[tmp-'a']++;
}
for(i=0; i<numLetters; i++)
{
printf("%d", counter[i]);
}
return 0;
}

使用字符代码值'a'(97(到'z'(122(对数组counter[]进行索引,但数组长度为100。您正在溢出缓冲区,并踩踏相邻的变量——在本例中是word[0]的开始,可能是tmp,但这在当时是未初始化的,因此没有影响。

与特定变量实际相邻的内容是未定义的,这将取决于编译器如何定位和排序内存中的数据对象;在不同的编译器中,您可能会得到不同的结果,包括简单的崩溃和中止。

初始化循环是不必要的;你可以将整个数组归零,这样:

int counter[100] = {0} ;

代码安全性和样式还有其他问题,但语义错误包括循环在'z'之前停止一次。要包含'z',您需要<= 'z'< 'z'+1:

for( int i = 'a'; i <= 'z'; i++ )
{
printf("%d", counter[i]);
}

不需要分配超过26个元素的counter数组。最好根据字符值计算范围:

int counter['z'-'a' + 1] = {0} ;

然后,您应该通过从字符代码值减去'a'来生成索引:

for( int i = 0; i < n; i++ )
{
char index = word[i][0] - 'a' ;
counter[index]++ ;
}

要处理大小写相同,您可能需要忽略大小写:

char index = tolower(word[i][0]) - 'a' ;

如果任何字母的计数>10.例如,您需要用空格或逗号分隔每个值。

for( int i = 'a'; i <= 'z'; i++ )
{
printf("%-3d", counter[i]);
}

您可以通过定义字符数的常量来增加清晰度:

#define NUM_COUNTERS ('z'-'a' + 1)

简化counter[]声明和输出循环:

int counter[NUM_COUNTERS] = {0} ;
...
for( int i = 0; i < NUM_COUNTERS; i++ )
{
printf( "%-3d ", counter[i - 'a'] ) ;
}

为了防止超过words[],您应该限制n的值,并进一步防止每个单词输入超过99个字符。

总之:

#include <stdio.h>
#include <ctype.h>
#define MAX_WORDS 100
#define NUM_COUNTERS ('z'-'a' + 1)
int main()
{
int n = 0 ;
printf( "Enter the number of words " ) ;
scanf( "%d", &n ) ;
if( n > MAX_WORDS )
{
n = MAX_WORDS ;
}
char word[MAX_WORDS][100] ;
for( int i = 0; i < n; i++ )
{
printf( "Enter the word: " );
scanf( "%99s", word[i] ) ;
}
int counter[NUM_COUNTERS] = {0} ;
for( int i = 0; i < n; i++ )
{
char index = word[i][0] - 'a' ;
counter[index]++ ;
}
for( int i = 0; i < NUM_COUNTERS; i++ )
{
printf( "%-3d ", counter[i - 'a'] ) ;
}
return 0;
}

相关内容

最新更新