Застрял в бесконечной петле, не уверен, что я сделал не так - PullRequest
0 голосов
/ 15 апреля 2019

Программа компилируется, но когда я пытаюсь ее использовать, я получаю бесконечный цикл. Где я сделал неправильно? Я помещаю комментарии в то, что я пытаюсь достичь.

Я попытался изменить его на цикл 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 ]

1 голос
/ 16 апреля 2019

Вы запускаете бесконечный цикл, устанавливая:

    strPointer=str;

в конце вашего while (*strPointer !='\0') цикла. Это сбрасывает адрес, удерживаемый strPointer, в начало str. strPointer никогда не увеличивается, поэтому ваш цикл повторяется с strPointer, указывающим на первый символ в str снова и снова и снова ...

Далее, вы инициализируете vowelPointer=vowels;, который устанавливает адрес vowelPointer так, чтобы он указывал на начальный элемент массива неинициализированного vowels. То же самое происходит с consonantPointer=consonants;

Поскольку и vowelPointer, и consonantPointer указывают на массивы, объявленные с длительностью автоматического хранения , вы вызываете Неопределенное поведение , когда вы пытаетесь получить доступ к неинициализированным значениям с помощью:

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);
}

( вопрос: знаете ли вы, почему после "str : %s" в printf выше нет необходимости '\n'?)

Обратите внимание, что символ преобразуется в в нижнем регистре перед сравнением гласного, чтобы сократить вдвое количество условных выражений, необходимых для проверки гласного. Не экономьте на размере буфера. Обычно у вас есть 1M стекового пространства (4M в Linux). Используйте буфер из 256 символов или простой 1K буфер, как указано выше. Также обратите внимание, что если вы хотите печатать с использованием указателя, вы просто сбросите их так, чтобы они указывали на исходные массивы сразу после выхода из цикла, например,

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

Несмотря на это, вы можете печатать, используя массивы или указатели после сброса их, так как оба будут указывать на один и тот же адрес. См. C11 Standard - 6.3.2.1 Другие операнды - L-значения, массивы и обозначения функций (p3)

Пример использования / Вывод

$ ./bin/sepvowels
Enter a string (1022 char max): A quick brown fox jumps over the lazy dog
str   : A quick brown fox jumps over the lazy dog
cons  : qckbrwnfxjmpsvrthlzydg
vowels: Auioouoeeao
1 голос
/ 16 апреля 2019

Я хотел бы сделать несколько предложений, чтобы помочь вам.

Во-первых, при сканировании с пользовательского ввода целесообразно использовать буфер. Затем поместите содержимое буфера в массив 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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...