程序可以编译,但是当我尝试使用它时,会出现一个无限循环。我在哪里做错了。我对要完成的工作发表了评论。
我尝试将其更改为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语句中解释了输出。输入字符串,重新打印,并分开并列出元音和辅音。
答案 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;
由于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);
}
(问题:您知道为什么在以上'\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;