8.10 复习题
1. putchar(getchar())是一个有效表达式,它实现什么功能?getchar(putchar())是否也是有效表达式?
答案:
putchar(getchar())功能是读取下一个输入字符并打印出来。
getchar(putchar())不是有效表达式,因为getchar()不需要参数,而putchar()需要一个参数。
2. 下面的语句分别完成什么任务?
a. putchar('H');
b. putchar('\007');
c. putchar('\n')
d. putchar('\b')
答案:
a. 显示字符H
b. 发出一声警报
c. 把光标移至下一行的开始
d. 退后一格
3. 假设有一个名为count的可执行程序,用于统计输入的字符数。设计一个使用count程序统计essay文件中字符数的命令行,并把统计结果保存在essayct文件中。
答案:(count < essay) > essayct
4. 给定复习题3的程序和文件,下面哪一条是有效命令?
a. essayct < essay
b. count essay
c. essay > count
答案: 都不是有效命令
5. EOF是什么?
答案:
EOF(end of file的缩写)是由scanf()和sacnf()返回的信号(一个特殊值),表明函数监测到文件结尾。通常,EOF定义在stdio.h文件中:#define EOF (-1)。
6. 对于给定的输出(ch是int类型,而且是缓冲输入),下面各程序段的输出分别是什么?
#include <stdio.h>
void printA();
void printB();
int main(void)
{printA();printB();return 0;
}
void printA()
{char ch;printf("a: \n");while ((ch = getchar()) != 'i')putchar(ch);printf("\n");while ((ch = getchar()) != '\n')continue;
}
void printB()
{char ch;printf("b: \n");while ((ch = getchar()) != '\n'){putchar(ch++);putchar(++ch);}
}
答案:
7. C如何处理不同计算机系统中的不同文件和换行约定?
答案:C的标准I/O把不同的文件映射为统一的流来统一处理。
8. 在使用缓冲输入的系统中,把数值和字符混合输入会遇到什么潜在的问题?
答案:
在使用缓冲输入的系统中,混合输入数值和字符可能会导致以下问题:
1. 换行符或空白字符会被下一个输入函数(如 scanf("%c"))错误地读取。
2. 输入缓冲区中可能残留字符,影响后续输入。
其中getchar()会读取每一个字符,包括空格、制表符和换行符;scanf()在读取数字时则会跳过空格、制表符和换行符。
8.11 编程练习
1. 设计一个程序,统计在读到文件结尾之前读取的字符数。
#include <stdio.h>
#include <stdlib.h>
int main(void)
{int ch;FILE* fp;char filename[50];unsigned long count = 0;printf("Enter the name of the file: ");scanf_s("%s", filename, sizeof(filename));if (fopen_s(&fp, filename, "r") != 0){printf("Failed to open file. Bye\n");exit(1);}while ((ch = getc(fp)) != EOF){putchar(ch);count++;}fclose(fp);printf("\nThe file contais %lu characters\n", count);getchar();return 0;
}
示例:
2. 编写一个程序,在遇到EOF之前,把输入作为字符流读取。程序要打印每个输入的字符极其相应的ASCII十进制值。注意,在ASCII序列中,空格字符前面的字符都是非打印字符,要特殊处理这些字符。如果非打印字符是换行符或制表符,则分别打印\n或\t。否则,使用控制字符表示法。例如,ASCII的1是Ctrl+A,可显示为^A。注意,A的ASCII值是Ctrl+A的值加上64.其他非打印字符也有类似的关系。除每次遇到换行符打印新的一行外,每行打印10对值。(注意:不同的操作系统其控制字符可能不同)。
#include <stdio.h>
#include <ctype.h>
int main(void)
{char ch;int count = 0;while ((ch = getchar()) != EOF){if (isprint(ch)){printf("'%c'--%d ", ch, ch);}else if(ch == '\n'){printf("'\\n'--%d ", ch);}else if(ch == '\t'){printf("'\\t'--%d ", ch);}else{printf("^%c--%d ", ch + 64, ch);}count++;if (count % 10 == 0){printf("\n");}}printf("Done!\n");return 0;
}
3. 编写一个程序,在遇到EOF之前,把输入流作为字符流读取。该程序要报告输入的大写字母和小写字母的个数。假设大小写字母数值是连续的。或者使用ctype.h库中合适的分类函数更方便。
#include <stdio.h>
#include <ctype.h>
int main(void)
{char ch;int lowerCharCount = 0;int upperCharCount = 0;while ((ch = getchar()) != EOF){if (islower(ch)){lowerCharCount++;}else if(isupper(ch)){upperCharCount++;}}printf("There are %d upper characters, and %d lower characters.\n", upperCharCount, lowerCharCount);return 0;
}
4. 编写一个程序,在遇到EOF之前,把输入作为字符流读取。该程序要报告平均每个单词的字母数,不要把空白统计为单词的字母。实际上,标点符号也不应该统计,但是现在暂时不要考虑那么多(如果你比较在意这点,考虑使用ctype.h系列中的ispunct()函数)。
#include <stdio.h>
#include <ctype.h>
int main(void)
{int ch;int isWord = 0;int wordCount = 0;int charCount = 0;while ((ch = getchar()) != EOF){if (isalpha(ch)){charCount++;if (!isWord){wordCount++;isWord = 1;}}if (isspace(ch)){isWord = 0;}}printf("There are %d words, and %d characters.\n", wordCount, charCount);return 0;
}
5. 修改程序清单8.4的猜数字程序,使用更智能的猜测策略。例如,程序最初猜50,询问用户是猜大了,猜小了还是猜对了。如果猜小了,那么下一次猜测的值应是50和100中值,也就是75。如果这次猜大了,那么下一次猜测的值应是50和75的中值,等等。使用二分查找(binary search)策略,如果用户没有欺骗程序,那么程序很快就会猜到正确的答案。
#include <stdio.h>
int main(void)
{int head = 1;int tail = 100;int guess = (head + tail) / 2;char ch;printf("Pick an integer from 1 to 100. I will try to guess it.\n");printf("Respond with a y if my guess is right and with\n");printf("an n if it is wrong.\n");do{printf("Oh...is your number %d?\n", guess);if (getchar() == 'y')break;printf("Well, then, %d is larger or smaller than yours? (l or s):", guess);while ((ch = getchar()) == '\n')continue;if (ch == 'l' || ch == 'L'){tail = guess - 1;guess = (head + tail) / 2;continue;}else if (ch == 's' || ch == 'S'){head = guess + 1;guess = (head + tail) / 2;continue;}}while (getchar() != 'y');printf("I know I could do it!\n");return 0;
}
6. 修改程序清单8.8中的get_first()函数,让该函数返回读取的第1个非空白字符,并在一个简单的程序中测试。
#include <stdio.h>
char get_choice(void);
char get_first(void);
int get_int(void);
void count(void);
int main(void)
{int choice;void count(void);while ((choice = get_choice()) != 'q'){switch (choice){case 'a':printf("Buy low, sell high.\n");break;case 'b':putchar('\a');break;case 'c':count();break;default:printf("Program error!\n");break;}}printf("Bye.\n");return 0;
}
void count(void)
{int n, i;printf("Count how far? Enter an integer:\n");n = get_int();for (i = 1; i <= n; i++){printf("%d\n", i);}while (getchar() != '\n')continue;
}
char get_choice(void)
{int ch;printf("Enter the letter of your choice:\n");printf("a. advice b. bell\n");printf("c. count q. quit\n");ch = get_first();while ((ch < 'a' || ch > 'c') && ch != 'q'){printf("Please respond with a, b, c, or q.\n");ch = get_first();}return ch;
}
char get_first(void)
{int ch;do{ch = getchar();} while (ch == ' ' || ch == '\t' || ch == '\n');return ch;
}
int get_int(void)
{int input;char ch;while (scanf_s("%d", &input) != 1){while ((ch = getchar()) != '\n')putchar(ch);printf(" is not an integer.\nPlease enter an ");printf("integer value, such as 25, -178, or 3: ");}return input;
}
7. 修改第7章的编程练习8,用字符代替数字标记菜单的选项。用q替代5作为结束输入的标记。
#include <stdio.h>
#define BASE_SALARY 10.00
#define EXTRA_HOUR 1.5
#define BASE_TAX 0.15
#define EXTRA_TAX 0.2
#define EXCEED_TAX 0.25void showMenu();
void calcSalary(float baseSalary, float hours);
void clear_input_buffer();int main(void)
{float hours = 0;char ch;do{showMenu();scanf_s("%c", &ch);switch (ch){case 'a':case 'A':printf("You select $8.75/hr. Enter the work hours:");scanf_s("%f", &hours);calcSalary(8.75, hours);clear_input_buffer();break;case 'b':case 'B':printf("You select $9.33/hr. Enter the work hours:");scanf_s("%f", &hours);calcSalary(9.33, hours);clear_input_buffer();break;case 'c':case 'C':printf("You select $10.00/hr. Enter the work hours:");scanf_s("%f", &hours);calcSalary(10.00, hours);clear_input_buffer();break;case 'd':case 'D':printf("You select $11.33/hr. Enter the work hours:");scanf_s("%f", &hours);calcSalary(11.33, hours);clear_input_buffer();case 'q':case 'Q':clear_input_buffer();break;default:printf("Error selected! please try again!");scanf_s("%c", &ch);break;}} while (ch != 'q' && ch != 'Q');printf("Done!\n");return 0;
}
void clear_input_buffer()
{char ch;while ((ch = getchar()) != '\n' && ch != EOF);
}void showMenu()
{char sOne[] = "a) $8,75/hr";char sTwo[] = "b) $9.33/hr";char sThree[] = "c) $10.00/hr";char sFour[] = "d) $11.20/hr";char sFive[] = "q) quit";printf("\n***********************************************\n");printf("%-40s", sOne);printf("%-40s\n", sTwo);printf("%-40s", sThree);printf("%-40s\n", sFour);printf("%-40s", sFive);printf("\n***********************************************\n");}void calcSalary(float baseSalary, float hours)
{float salary, tax, taxed_salary;if (hours <= 30){salary = hours * baseSalary;tax = salary * BASE_TAX;taxed_salary = salary - tax;}else if (hours <= 40){salary = hours * baseSalary;tax = 300 * BASE_TAX + (salary - 300) * EXCEED_TAX;taxed_salary = salary - tax;}else{salary = (40 + (hours - 40) * EXTRA_HOUR) * baseSalary;if (salary <= 450)tax = 300 * BASE_TAX + (salary - 300) * EXTRA_TAX;elsetax = 300 * BASE_TAX + 150 * EXTRA_TAX + (salary - 450) * EXCEED_TAX;taxed_salary = salary - tax;}printf("Your salary before tax is %.2f, tax is %.2f, salary after tax is %.2f\n", salary, tax, taxed_salary);
}
8. 编写一个程序,显示一个提供加法、减法、乘法、和除法的菜单。获得用户选择的选项后,程序提示用户输入两个数字,然后执行用户刚才选择的操作。该程序只接受菜单提供的选项。程序使用float类型的变量储存用户输入的数字,如果用户输入失败,则允许再次输入。进行除法运算时,如果用户输入0作为第2个数(除数)。程序应提示用户重新输入一个新值。该程序的一个运行示例如下:
#include <stdio.h>
void showMenu();
float getFloatNumber();
int main(void)
{char operate;float firstNumber, secondNumber;do {showMenu();operate = getchar();while (getchar() != '\n') continue;switch (operate){case 'a':printf("Enter first number: ");firstNumber = getFloatNumber();printf("Enter second number: ");secondNumber = getFloatNumber();printf("%g + %g = %g \n", firstNumber, secondNumber, firstNumber + secondNumber);break;case 's':printf("Enter first number: ");firstNumber = getFloatNumber();printf("Enter second number: ");secondNumber = getFloatNumber();printf("%g - %g = %g \n", firstNumber, secondNumber, firstNumber - secondNumber);break;case 'm':printf("Enter first number: ");firstNumber = getFloatNumber();printf("Enter second number: ");secondNumber = getFloatNumber();printf("%g * %g = %g \n", firstNumber, secondNumber, firstNumber * secondNumber); break;case 'd':printf("Enter first number: ");firstNumber = getFloatNumber();printf("Enter second number: ");while ((secondNumber = getFloatNumber()) == 0)printf("Enter a number other than 0: ");printf("%g / %g = %g \n", firstNumber, secondNumber, firstNumber / secondNumber);break;case 'q':break;default:printf("Please enter a char, such as a, s, m, d and q:\n");while (getchar() != '\n');break;}while (getchar() != '\n');} while (operate != 'q');printf("Bye.\n");return 0;
}
void showMenu()
{printf("Enter the operation of your choice:\n");printf("a. add s. subtract\n");printf("m. multiply d. divide\n");printf("q. quit \n");
}
float getFloatNumber()
{float number;char ch;while (scanf_s("%g", &number) != 1){while ((ch = getchar()) != '\n')putchar(ch);printf(" is not an number.\n");printf("Please enter a number, such as 2.5, -1, 78E8, or 3: ");}return number;
}