计算C中一系列字符串中元音的数量



我正在用C编写一个程序,它计算用户决定的一系列字符串中元音的数量,甚至字符串的元素数量也由用户决定。问题是,函数总是给出相同数量的元音,即第一个字符串中的元音。

这是代码:

#include <stdio.h>
#include <string.h>
int vowels(char str[]);
int main(){
int n, i, x;
printf("How many strings do you want to insert?");
scanf("%d", &n);
printf("How many characters per string?");
scanf("%d", &x);
char str[x];
if(x < 10){
for(i = 0; i < n; i++){
printf("Insert a string:");
scanf("%s", str);
if(strlen(str) == x){
vowels(str);
}
else{
printf("Errorn");
}
}
}
else{
printf("Error: the number of characters must be < 10");
}
return 0;
}
int vowels(char str[]){
int i, j;
while(str[i] != ''){
if(str[i] == 'a' || str[i] == 'A' || str[i] == 'e' || 
str[i] == 'E' || str[i] == 'i' || str[i] == 'I' || 
str[i] == 'o' || str[i] == 'O' || str[i] == 'u' || 
str[i] == 'U'){
j++; }
i++;
}
printf("Number of vowels in the string:%dn", j); 
return 0;
}

您的代码包含两个错误:

  1. vowels()函数的ij索引未初始化,因此它们包含垃圾,并将导致循环的不可预测行为。这是因为局部变量与全局变量不同,默认情况下不会初始化为0

使用

int i=0, j=0;
  1. 缓冲区char str[x];将不能包含包含x个字符的字符串。实际上,字符串结束符字符''所需的空间

所以应该是

char str[x+1];

有了这些更改,您的代码就可以工作了。

但是

但这还不够。事实上,当您获得输入字符串时,您不会对检索到的字符数进行任何检查:

scanf("%s", str);

通过插入一个很长的字符串,您将远远超出str字符串的范围,从而导致未定义的行为,并可能导致程序崩溃。

如何修复由于输入字符串的最大长度为9,只需定义一个固定长度数组

char str[11];

为什么选择11码首先,数组最多必须包含9个字符和终止符。所以10。但它也必须包含一个额外的字符,这样可以检测到超过9个字符的输入。

之后,只需使用接收输入字符串

scanf("%10s", str);

通过这种方式,可以存储所有合法的输入字符串(从大小1到大小9(。所有长度超过10个字符的字符串将被截断为10个字符长的字符串,并且您的长度检查将按预期失败。

请注意,如果是长字符串,则stdin缓冲区中所有超过前10个的字符都将保持未读状态。因此,如果出现错误,您需要一种机制来使用这些字符,否则您将在下一个scanf中找到它们。我写了这个技巧:

while( fgets( str, 10, stdin ) != NULL )
{
if( strlen(str) < 10 )
break;
}

得到的代码,包括我所描述的所有更改,如下所示:

#include <stdio.h>
#include <string.h>
int vowels(char str[]);
int main(){
int n, i, x;
printf("How many strings do you want to insert?");
scanf("%d", &n);
printf("How many characters per string?");
scanf("%d", &x);
if(x < 10){
char str[11];
for(i = 0; i < n; i++){
printf("Insert a string:");
scanf("%10s", str);
if(strlen(str) == x){
vowels(str);
}
else{
printf("Errorn");
while( fgets( str, 10, stdin ) != NULL )
if( strlen(str) < 10 )
break;
}
}
}
else{
printf("Error: the number of characters must be < 10");
}
return 0;
}
int vowels(char str[]){
int i=0, j=0;
while(str[i] != '')
{
if(str[i] == 'a' || str[i] == 'A' || str[i] == 'e' || 
str[i] == 'E' || str[i] == 'i' || str[i] == 'I' || 
str[i] == 'o' || str[i] == 'O' || str[i] == 'u' || 
str[i] == 'U')
{
j++;
}
i++;
}
printf("Number of vowels in the string:%dn", j); 
return 0;
}

我正在粘贴您的代码并在内联中添加注释。注意:我不是在修复任何东西,只是指出一些需要你修复的东西。

#include <stdio.h>
#include <string.h>
int vowels(char str[]);
int main(){
int n, i, x;
printf("How many strings do you want to insert?");
scanf("%d", &n);  // Consider a more descriptive variable name than 'n'
printf("How many characters per string?");
scanf("%d", &x);  // Consider a more descriptive name here too.
char str[x];  // Note, a string needs 1 extra character for the NUL character.
if(x < 10){  // 10 is a very magic number.  Consider making a constant.  
for(i = 0; i < n; i++){
printf("Insert a string:");
scanf("%s", str);
if(strlen(str) == x){
vowels(str);
}
else{
printf("Errorn"); // Consider breaking or returning here if error...
}
}
}
else{
printf("Error: the number of characters must be < 10");
}
return 0;
}
int vowels(char str[]){  // Do you need a return value?  What does it represent?
int i, j;
while(str[i] != ''){  // i and j are not initialized (to 0).  Turning on compiler warnings would catch this.  
//  a for() loop may make more sense
if(str[i] == 'a' || str[i] == 'A' || str[i] == 'e' || 
str[i] == 'E' || str[i] == 'i' || str[i] == 'I' || 
str[i] == 'o' || str[i] == 'O' || str[i] == 'u' || 
str[i] == 'U'){
j++; }
i++;
}
printf("Number of vowels in the string:%dn", j); 
return 0;  // Again, maybe this function returns void if we don't need a return.
}

vowels函数中的问题是由未初始化的变量引起的。CCD_ 10和CCD_。一个好的编译器会对此产生警告。如果使用gcc或clang进行编译,请确保使用-Wall -Wextra进行编译。然后阅读警告,并修复所有警告。

变量i可以用for循环声明和初始化,如下所示。变量j应该被赋予一个更具描述性的名称,如count,并在循环之前初始化。您可能还想从vowels函数返回count,并让main进行打印。这样,您可以在另一个程序中重用vowels函数,该程序需要计算元音,但不希望打印计数。

int vowels(char str[]){
int count = 0;
for (int i=0; str[i] != ''; i++){
if(str[i] == 'a' || str[i] == 'A' || str[i] == 'e' || 
str[i] == 'E' || str[i] == 'i' || str[i] == 'I' || 
str[i] == 'o' || str[i] == 'O' || str[i] == 'u' || 
str[i] == 'U'){
count++; 
}
}
return count;
}

程序中的另一个问题是str阵列太小。C字符串使用一个零字节(称为NUL终止符(来标记字符串的末尾。因此,例如,如果一个字符串的strlen为5,那么包含该字符串的数组必须至少为6个字节,字符串为5,NUL为1。

在您的程序中,您将字符串长度限制为小于10的数字,因此您只需声明具有固定大小的str数组,例如char str[16],它将始终足够大。另外,scanf不会限制写入字符串中的字符数,除非您告诉它。下面的代码显示了如何限制scanf写入字符串的字符数。

int main(){
int n, x;
printf("How many strings do you want to insert?");
scanf("%d", &n);
printf("How many characters per string?");
scanf("%d", &x);
char str[16];
if(x < 10){
for(int i = 0; i < n; i++){
printf("Insert a string:");
if (scanf("%15s", str) != 1) {
printf("That wasn't a valid inputn");
break;
}
else if(strlen(str) == x){
int count = vowels(str);
printf("Number of vowels in the string:%dn", count); 
}
else{
printf("Errorn");
break;
}
}
}
else{
printf("Error: the number of characters must be < 10");
}
return 0;
}

最新更新