我正在尝试从输入中找到小写和大写字符。
这是我的代码:
#include <stdio.h>
#include <string.h>
int main()
{
char cAFirst[25];
int k = 0,uc =0 ,lc =0 ;
fgets(cAFirst,25,stdin);
// printf("out: %d \n",k);
for (size_t i = 0; i < 25; i++) {
k = (int)cAFirst[i];
if ((k <= 90) && (k >= 65)) {
uc++;
}
if ((k >= 97) && (k <= 122)) {
lc++;
}
}
printf("Uppercase Letters=%i \nLowercase Letters=%i \n",uc,lc );
return 0;
}
小写(lc
)可以,但是uc
的值是随机增加的。
我已经尝试过更改printf的格式,有时它可以工作,但是问题是我必须以上面给出的相同格式提交此代码。
答案 0 :(得分:3)
然后始终迭代25次,直到检测到输入结束为止。
// for (size_t i = 0; i < 25; i++) {
for (size_t i = 0; cAFirst[i]; i++) { // detect null character.
答案 1 :(得分:2)
从OP的已发布代码中考虑以下代码段:
char cAFirst[25]; // <- Uninitialized, the contents are indeterminated
// ...
fgets(cAFirst,25,stdin); // <- We don't know if it succeeded or not
// ...
for (size_t i = 0; i < 25; i++) {
// ... ^^^^^^
}
它将stdin
中最多<24>个字符复制到数组(包括换行符,如果存在)中,还添加了null终止符(如果没有发生流错误),但是当执行循环后,即使输入的字符串较短,也要考虑数组值不确定的char,遍历数组的所有 25 char。
为避免这种情况,我们只需要通过对字符进行计数或使用空终止符作为标记来测试从输入流中实际读取的字符。
我们可以将数组初始化为零(零),并且避免使用重复的幻数,这容易出错。
#include <stdio.h>
// I'd use a bigger value, like 256, but OP's use case is not specified.
enum {
BUF_SIZE = 25
};
int main(void)
{
// All the elements of the array are set to zero, not only the first.
char buf[BUF_SIZE] = {'\0'};
// ...
现在,即使在上一个循环中测试了数组中的所有字符,也不会出现虚假值,并且统计信息将保持一致。不过,这不是一个真正的解决方案,尽管通常建议在使用所有变量之前先对其进行初始化,但在这种情况下没有必要。
如chux所述,应检查诸如fgets
之类的函数的返回值,以验证操作是否成功并且我们的变量处于有效状态。
if ( fgets(buf, BUF_SIZE, stdin) == NULL ) {
if (feof(stdin)) {
fprintf(stderr, "Abnormal end of input.\n");
// The contents of the array are not altered
}
if (ferror(stdin)) {
fprintf(stderr, "A stream error occurred.\n");
// The contents of the array are indeterminated, maybe not even null-terminated
}
exit(EXIT_FAILURE);
}
关键是要确保在此调用之后,数组以null终止。甚至像下面这样的检查也足够:
if ( fgets(buf, BUF_SIZE, stdin) == NULL ) {
fprintf(stderr, "An error occurred while reading from stdin.\n");
buf[0] = '\0';
// Continues the program despite the error, but with a valid (empty) string
}
值得记住的是,除了读取的字符外,其他任何字符都保留在输入流中。
现在我们有了一个有效的(以null结尾的)数组,我们可以遍历它:
int uc = 0, lc = 0;
for (size_t i = 0; buf[i] != '\0'; i++) {
// which can also be written as 'for (size_t i = 0; buf[i]; i++) {'
// It's also more readable without magic numbers:
if ( 'A' <= buf[i] && buf[i] <= 'Z' ) {
uc++;
}
else if ( 'a' <= buf[i] && buf[i] <= 'z' ) {
lc++;
}
}
printf("Uppercase Letters = %i\nLowercase Letters = %i\n", uc, lc);
return EXIT_SUCCESS;
}
可以使用标头isupper
中定义的islower
和<ctype.h>
之类的函数从ASCII代码中概括上一个片段。另外,字符串的实际长度可用于限制for循环:
// Length of the maximum initial segment of the array, that consists of
// only the characters not equal to a newline or null character
size_t length = strcspn(buf, "\n");
int uc = 0, lc = 0;
for (size_t i = 0; i < length; i++) {
unsigned char k = buf[i];
if ( isupper(k) ) {
uc++;
}
else if ( islower(k) ) {
lc++;
}
}
// ...
答案 2 :(得分:1)
您应该首先使用一种方法仅在while
循环中迭代一次字符串,并尝试不仅读取您需要的内容,而且还读取不应该计算的内容。如果有\t
或\n
会发生什么情况?
这是一种可以帮助您理解的方法:
#include <stdio.h>
int main( void )
{
char string[] = "AbcDEfgHiJKlmnOPqrstUVWxyZ\n§$%$§";
int uc, lc, i, others;
uc = lc = i = others = 0;
while ( string[i] )
{
if ( string[i] >= 'A' && string[i] <= 'Z' )
{
uc++;
}else if ( string[i] >= 'a' && string[i] <= 'z' ){
lc++;
}else{
others++;
}
i++;
}
if ( i == ( lc + uc + others ) )
{
printf( "OK\n\n" );
printf("Uppercase Letters = %i \nLowercase Letters = %i \nOthers = %d \n", uc, lc, others );
printf("Total = %d\n", i );
}else
{
printf("Something went Wrong.\n\n");
}
}
您的if/else
语句很容易替换为isupper( string[i] )
中的函数islower( string[i] )
和ctype.h
if ( isupper( string[i] ) )
{
uc++;
}else if ( islower( string[i] ) )
{
lc++;
}else{
others++;
}