陷入无限循环,不确定我做错了什么

时间:2019-04-15 20:45:25

标签: c

程序可以编译,但是当我尝试使用它时,会出现一个无限循环。我在哪里做错了。我对要完成的工作发表了评论。

我尝试将其更改为for循环,但是仍然遇到问题。我想我应该坚持使用while循环来完成我要完成的工作。

  //Declare the arrays to hold the strings
  char str[21], vowels[21], consonants[21];
int i=0;

  //Declare the pointers
  char *strPointer, *vowelPointer, *consonantPointer;

  //Print out the prompt to the user
  printf("Enter a string (20 characters maximum): ");

  //Scan the user input into str
  //Only allow 20 characters
  scanf("%s", str);

  //Set strPointer to the beginning of the user's string
  strPointer = str;

  //Set vowelPointer to the beginning of the vowels string
  vowelPointer = vowels;

  //Set consonantPointer to the beginning of tht consonant string
  consonantPointer = consonants;

  //Loop through the user's string until the end of the string
  while(*strPointer !='\0')
  {
    //Check if what strPointer is pointing to is a vowel
    if(strPointer[i]=='A'||strPointer[i]=='a'||strPointer[i]=='E'||strPointer[i]=='e'||strPointer[i]=='I'||strPointer[i]=='i'||strPointer[i]=='O'||strPointer[i]=='o'||strPointer[i]=='U'||strPointer[i]=='u')
    {

      //Move the letter from strPointer to vowelPointer
    strPointer=vowelPointer
      ;

      //Move the vowelPointer
    vowelPointer=vowels
      ;

    }
    else
    {

      //Move the letter from strPointer to consonantPointer
    strPointer=consonantPointer
      ;

      //Move the consonantPointer
     consonantPointer=consonants
      ;

    }

    //Move the strPointer
    strPointer=str;
  }

  //Add null terminators where appropriate
  strPointer[21]='\0';
  str[21]='\0';

  //Set the vowel and consonant pointers back to the beginning of their strings
  vowelPointer[0];
  consonantPointer[0];

  //Print the original string and the resulting vowel and consonant strings
  printf("Original string: %s\n", str);
  printf("%s\n", vowelPointer);
  printf("%s\n", consonantPointer);

最后在我的printf语句中解释了输出。输入字符串,重新打印,并分开并列出元音和辅音。

2 个答案:

答案 0 :(得分:1)

我想提出一些建议来帮助您。

首先,当您从用户输入进行扫描时,明智的做法是使用缓冲区。然后,将缓冲区的内容strcpy放入char数组。这将有助于防止溢出。请参阅下面的代码以获取有关此主题的更多详细信息。

第二,您可以使用for循环遍历每个字母。希望我的回答能帮助您理解我的意思。

#include <stdio.h>
#include <ctype.h>
#include <string.h>

int main(void)
{

    //Declare the arrays to hold the strings
     char c, str[21], vowels[21], consonants[21], buffer[21];
     int i = 0, j = 0, h = 0;

     //Declare the pointers
     char *strPointer, *vowelPointer, *consonantPointer;

     //Print out the prompt to the user
     printf("Enter a string (20 characters maximum): ");

     //Scan the user input into str
     scanf("%s", buffer);

     // Copy the buffer into the str
     strcpy(str, buffer);

     // go letter by letter checking if it is a vowel or consonant
     for (int i = 0; str[i]; i++)
     {
         // make the character uppercase
         c = toupper(str[i]);

         // if the letter is a vowel add the letter to the vowel array, 
         // then increase the position
         if (c == 'A' || c == 'E' || c == 'I' || c == 'O' || c == 'U')
             vowels[j++] = str[i];
         else
            // add the letter to the consonants array, then increase the position
            consonants[h++] = str[i];
     }

     // properly terminate the strings
     vowels[j] = '\0';
     consonants[h] = '\0';

     //Print the original string and the resulting vowel and consonant strings
     printf("Original string: %s\n", str);
     printf("%s\n", vowels);
     printf("%s\n", consonants);

    return 0;
}

答案 1 :(得分:1)

您可以通过以下方式调用无限循环:

    strPointer=str;

while (*strPointer !='\0')循环的末尾。这会将strPointer保留的地址重置为str的开头。 strPointer永远不会递增,因此您的循环会反复遍历strPointer指向str中的第一个字符...

此外,您初始化vowelPointer=vowels;,该地址将vowelPointer的地址设置为指向未初始化 vowels数组的开始元素。 consonantPointer=consonants;

也会发生同样的情况

由于vowelPointerconsonantPointer均指向以自动存储持续时间声明的数组,因此当您尝试访问未初始化的数组时,您将调用未定义行为值:

printf("%s\n", vowelPointer);
printf("%s\n", consonantPointer);

(但幸运的是,由于while (*strPointer !='\0')上的无尽循环,您从未到达那里)

另外,通过将 field-width 修饰符与scanf(或更佳的是使用fgets())一起使用,验证每个输入并肯定地保护数组边界。例如:

//Only allow 20 characters
if (scanf( "%20s", str) != 1) {
    fputs ("error: (user canceled input)\n", stderr);
    return 1;
}

注意:当使用"%s"进行读取时,结尾的'\n'不会被使用,并且会保留在您的输入缓冲区中)

要解决指针问题,可以执行以下操作:

    //Declare the arrays to hold the strings
    char str[21], vowels[21], consonants[21];
    size_t vidx = 0, cidx = 0;           /* indexes for vowels/consonants */
    ...
    //Loop through the user's string until the end of the string
    while (*strPointer)
    {
        //Check if what strPointer is pointing to is a vowel
        if (strPointer[i]=='A'|| strPointer[i]=='a'||
            strPointer[i]=='E'|| strPointer[i]=='e'||
            strPointer[i]=='I'|| strPointer[i]=='i'||
            strPointer[i]=='O'|| strPointer[i]=='o'||
            strPointer[i]=='U'|| strPointer[i]=='u')
        {
            //Copy the letter from strPointer to vowelPointer
            if (vidx < 20) {
                vowelPointer[vidx] = *strPointer;
                vidx++;
            }
            /* or using pointer arithmetic */
            // if (vowelPointer - vowels < 20) {
            //     *vowelPointer = *strPointer;
            //     vowelPointer++;
            // }

        }
        else {
            //Copy the letter from strPointer to consonantPointer
            if (cidx < 20) {
                consonantPointer[cidx] = *strPointer;
                cidx++;
            }
            /* same alternative available for consonantPointer */
        }

        //Move the strPointer
        strPointer++;
    }

    //Add null terminators where appropriate
    vowelPointer[vidx] = 0;
    consonantPointer[cidx] = 0;

    //Reset the ponters
    vowelPointer = vowels;
    consonantPointer = consonants;

    //Print the original string and the resulting vowel and consonant strings
    printf("Original string: %s\n", str);
    printf("%s\n", vowelPointer);
    printf("%s\n", consonantPointer);

如果您仍然遇到困难,可以将其放在一个简短但更简洁的示例中,如下所示:

#include <stdio.h>
#include <ctype.h>

#define MAXC 1024   /* don't skimp on buffer size */

int main (void) {

    char str[MAXC], cons[MAXC], vowels[MAXC],                   /* arrays */
        *strptr = str, *consptr = cons, *vowelptr = vowels;     /* pointers */

    fputs ("Enter a string (1022 characters maximum): ", stdout);
    if (!fgets (str, MAXC, stdin)) {    /* validate EVERY read */
        fputs ("error: (user canceled input)\n", stderr);
        return 1;
    }

    while (*strptr) {                   /* loop over each character */
        char lc = tolower (*strptr);    /* convert to lowercase to compare */
        if (lc == 'a' || lc == 'e' || lc == 'i' || lc == 'o' || lc == 'u')
                *vowelptr++ = *strptr;  /* copy vowel to array */
        else if (!isspace (*strptr))    /* otherwise if not whitespace */
            *consptr++ = *strptr;       /* copy to consonant array */
        strptr++;                       /* advance string pointer */
    }
    *vowelptr = *consptr = 0;           /* nul-terminate arrays */

    printf ("str   : %scons  : %s\nvowels: %s\n", str, cons, vowels);
}

问题:您知道为什么在以上'\n'的{​​{1}}之后不需要"str : %s"吗?)

请注意,在比较元音之前将字符转换为小写,以将检查元音所需的条件数量减少一半。不要忽略缓冲区大小。通常,您有1M的堆栈空间(Linux上为4M)。使用至少256个字符的缓冲区或上面使用的简单1K缓冲区。另外请注意,如果您要使用指针进行打印,只需退出循环后立即将它们重置为指向原始数组即可,例如

printf

无论如何,您可以在重置数组或指针后使用它们进行打印,因为它们都将指向相同的地址。参见C11 Standard - 6.3.2.1 Other Operands - Lvalues, arrays, and function designators(p3)

使用/输出示例

    strptr = str;
    consptr = cons;
    vowelptr = vowels;