Вы запускаете бесконечный цикл, устанавливая:
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