0

我正在用 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("Error\n");
            }
        }
    }
    else{
        printf("Error: the number of characters must be < 10");
    }

    return 0;
}

int vowels(char str[]){
    int i, j;

    while(str[i] != '\0'){
        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:%d\n", j); 

return 0;
}

4

3 回答 3

1

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

#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("Error\n"); // 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] != '\0'){  // 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:%d\n", j); 

  return 0;  // Again, maybe this function returns void if we don't need a return.
}
于 2020-04-23T19:14:48.063 回答
1

函数中的问题vowels是由未初始化的变量引起的。既没有i也没有j给出初始值。一个好的编译器会对此产生警告。如果您使用 gcc 或 clang 进行编译,请务必使用-Wall -Wextra. 然后阅读警告,并修复所有警告。

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

int vowels(char str[]){
    int count = 0;

    for (int i=0; str[i] != '\0'; 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数组太小。AC 字符串使用零字节(称为 NUL 终止符)来标记字符串的结尾。因此,例如,如果strlen字符串的 5 为 5,则保存该字符串的数组必须至少为 6 个字节,其中 5 为字符串,加上 1 为 NUL。

在您的程序中,您将字符串长度限制为小于 10 的数字,因此您可以只声明str具有固定大小的数组,例如char str[16],它总是足够大。OTOH,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 input\n");
                break;
            }
            else if(strlen(str) == x){
                int count = vowels(str);
                printf("Number of vowels in the string:%d\n", count); 
            }
            else{
                printf("Error\n");
                break;
            }
        }
    }
    else{
        printf("Error: the number of characters must be < 10");
    }

    return 0;
}
于 2020-04-23T19:16:44.530 回答
1

您的代码包含两个错误:

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

改为使用

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

所以应该是

char str[x+1];

通过这些更改,您的代码将起作用。

但...

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

scanf("%s", str);

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

如何解决?由于您的输入字符串的最大长度为 9,因此只需定义一个固定长度的数组

char str[11];

为什么选择 11 号?首先,您的数组必须包含最多 9 个字符和终止符。所以 10。但它还必须包含一个额外的字符,这样输入的长度才能检测到 9 个字符。

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

scanf("%10s", str);

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

请注意,对于长字符串,超过前 10 个的所有字符都将在stdin缓冲区中保持未读状态。因此,如果出现错误,您需要一种机制来使用这些字符,否则您会在下一个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("Error\n");
                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] != '\0')
    {
        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:%d\n", j); 

    return 0;
}
于 2020-04-23T19:17:48.020 回答