在字符串中查找元音
Find vowels in a string
下面是我在给定字符串中查找元音的代码:
#include <stdio.h>
#include <string.h>
int main() {
char str[100];
int i, str_length;
//scanf("%[^\n]%*c", &str[100]);
fgets(str, sizeof(str), stdin);
str_length = strlen(str);
for (i = 0; i < str_length; i++) {
if (str[i] == 'a' || str[i] == 'e' ||
str[i] == 'i' || str[i] == 'o' ||
str[i] == 'u' || str[i] == 'A' ||
str[i] == 'E' || str[i] == 'I' ||
str[i] == 'O' || str[i] == 'U')
{
printf("Vowels in the string are: %c \n", str[i]);
}
}
return 0;
}
我只想知道,为什么 scanf("%[^\n]%*c",&str[100])
在我的代码中不起作用?
因为我尝试使用 scanf
多次执行我的程序,但没有成功。
在使用 fgets
之后我得到了想要的输出。
所以,谁能帮我理解一下,我哪里错了!!
在 scanf
函数调用中,这个 &str[100]
接受一个指向 str
的指针,使其指向索引为 100 的元素(这是数组末尾之后的元素) ),取消引用它,然后获取该(不存在的)元素的地址。这很可能会导致尝试进行无效写入,这可能会被终止程序的操作系统捕获。无论如何,字符串都没有写入正确的位置。
相反,您希望参数指向 str
的第一个元素的内存位置,即:
scanf("%[^\n]%*c", str);
也就是说,使用 fgets
更好,因为它接受防止缓冲区溢出的大小参数。也可以给 scanf
一个大小,但是因为它是格式说明符的一部分,所以它不能是一个变量;只有一个硬编码常量:
scanf("%99[^\n]%*c", str);
请注意,这是针对 99 元素的,因为空终止符 ([=20=]
) 也需要有空间。有关 scanf
的更多信息,请参阅 here。但同样,使用 fgets
不太容易出错,因此更受欢迎。
一些额外的建议:
- 不使用参数的
main
函数的典型签名是 int main(void)
。
- 如果输入的是单个换行符,
scanf
版本将失败。两个版本都在没有输入时失败。检查输入(和输出)函数的 return 值总是一个好主意。
- 在 for 循环内部,您可以使用 tolower 函数创建将当前字符转换为小写的副本,然后仅执行小写比较。即:
for (i = 0; i < str_length; i++) {
char ch = tolower(str[i]);
if (ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u')
printf("Vowels in the string are: %c \n", str[i]);
}
- 另一种选择是将 if 语句中的比较替换为对
strchr
的调用,这使程序更加通用和可扩展(一个字符串比多次比较更容易更改):
char ch = tolower(str[i]);
if (strchr("aeiou", ch) != NULL)
printf("Vowels in the string are: %c \n", str[i]);
下面是我在给定字符串中查找元音的代码:
#include <stdio.h>
#include <string.h>
int main() {
char str[100];
int i, str_length;
//scanf("%[^\n]%*c", &str[100]);
fgets(str, sizeof(str), stdin);
str_length = strlen(str);
for (i = 0; i < str_length; i++) {
if (str[i] == 'a' || str[i] == 'e' ||
str[i] == 'i' || str[i] == 'o' ||
str[i] == 'u' || str[i] == 'A' ||
str[i] == 'E' || str[i] == 'I' ||
str[i] == 'O' || str[i] == 'U')
{
printf("Vowels in the string are: %c \n", str[i]);
}
}
return 0;
}
我只想知道,为什么 scanf("%[^\n]%*c",&str[100])
在我的代码中不起作用?
因为我尝试使用 scanf
多次执行我的程序,但没有成功。
在使用 fgets
之后我得到了想要的输出。
所以,谁能帮我理解一下,我哪里错了!!
在 scanf
函数调用中,这个 &str[100]
接受一个指向 str
的指针,使其指向索引为 100 的元素(这是数组末尾之后的元素) ),取消引用它,然后获取该(不存在的)元素的地址。这很可能会导致尝试进行无效写入,这可能会被终止程序的操作系统捕获。无论如何,字符串都没有写入正确的位置。
相反,您希望参数指向 str
的第一个元素的内存位置,即:
scanf("%[^\n]%*c", str);
也就是说,使用 fgets
更好,因为它接受防止缓冲区溢出的大小参数。也可以给 scanf
一个大小,但是因为它是格式说明符的一部分,所以它不能是一个变量;只有一个硬编码常量:
scanf("%99[^\n]%*c", str);
请注意,这是针对 99 元素的,因为空终止符 ([=20=]
) 也需要有空间。有关 scanf
的更多信息,请参阅 here。但同样,使用 fgets
不太容易出错,因此更受欢迎。
一些额外的建议:
- 不使用参数的
main
函数的典型签名是int main(void)
。 - 如果输入的是单个换行符,
scanf
版本将失败。两个版本都在没有输入时失败。检查输入(和输出)函数的 return 值总是一个好主意。 - 在 for 循环内部,您可以使用 tolower 函数创建将当前字符转换为小写的副本,然后仅执行小写比较。即:
for (i = 0; i < str_length; i++) {
char ch = tolower(str[i]);
if (ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u')
printf("Vowels in the string are: %c \n", str[i]);
}
- 另一种选择是将 if 语句中的比较替换为对
strchr
的调用,这使程序更加通用和可扩展(一个字符串比多次比较更容易更改):
char ch = tolower(str[i]);
if (strchr("aeiou", ch) != NULL)
printf("Vowels in the string are: %c \n", str[i]);