技术标签: c语言 C Primer Plus
加粗与下面的点是用来标记我的知识盲区,无特殊含义。
- 重定向和文件及之前的点由加粗标记
- 之后的知识应反复学习
本章介绍以下内容:
更详细地介绍输入、输出以及缓冲输入和无缓冲输入的区别;
如何通过键盘模拟文件结尾条件;
如何使用重定向把程序和文件相连接;
创建更友好的用户界面。
最初,输入/输出函数不是C定义的一部分,C把开发这些函数的任务留给编译器的实现者来完成。
在实际应用中,UNIX系统中的C实现为这些函数提供了一个模型。ANSI C库吸取成功的经验,把大量的UNIX I/O函数囊括其中,包括一些我们曾经用过的。
由于必须保证这些标准函数在不同的计算机环境中能正常工作,所以它们很少使用某些特殊系统才有的特性。因此,许多C供应商会利用硬件的特性,额外提供一些I/O函数。
自从ANSI C标准发布以后,C就把stdio.h头文件与使用getchar()和putchar()相关联,这就是为什么程序中要包含这个头文件的原因(其实,getchar()和putchar()都不是真正的函数,它们被定义为供预处理器使用的宏,我们在第16章中再详细讨论)。
如果在老式系统运行程序清单8.1,你输入文本时可能显示如下:
HHeelllloo, tthheerree… II wwoouulldd[enter]
lliikkee aa #
这样回显用户输入的字符后立即重复打印该字符是属于无缓冲(或直接)输入,即正在等待的程序可立即使用输入的字符。
/* echo.c -- 重复输入 */
#include <stdio.h>
int main(void)
{
char ch;
while ((ch = getchar()) != '#')
putchar(ch);
return 0;
}
Hello, there. I would[enter]
Hello, there. I wouldlike a #3 bag of potatoes.[enter]
like a
检测文件结尾的一种方法是,在文件末尾放一个特殊的字符标记文件结尾。
CP/M、IBM-DOS和MS-DOS的文本文件曾经用过这种方法。如今,这些操作系统可以使用内嵌的Ctrl+Z字符来标记文件结尾。这曾经是操作系统使用的唯一标记,不过现在有一些其他的选择,例如记录文件的大小。所以现代的文本文件不一定有嵌入的Ctrl+Z,但是如果有,该操作系统会将其视为一个文件结尾标记。
操作系统使用的另一种方法是存储文件大小的信息。如果文件有3000字节,程序在读到3000字节时便达到文件的末尾。 MS-DOS及其相关系统使用这种方法处理二进制文件,因为用这种方法可以在文件中存储所有的字符,包括Ctrl+Z。新版的DOS也使用这种方法处理文本文件。UNIX使用这种方法处理所有的文件。
无论操作系统实际使用何种方法检测文件结尾,在C语言中,用getchar()读取文件检测到文件结尾时将返回一个特殊的值,即EOF(end of file的缩写)。scanf()函数检测到文件结尾时也返回EOF。
#define EOF (-1)
为什么是-1?因为getchar()函数的返回值通常都介于0~127,这些值对应标准字符集。但是,如果系统能识别扩展字符集,该函数的返回值可能在0~255。无论哪种情况,-1都不对应任何字符,所以,该值可用于标记文件结尾。
这里关键要理解EOF是一个值,标志着检测到文件结尾,并不是在文件中找得到的符号。
while ((ch = getchar()) != EOF)
getchar()的返回值和EOF作比较。如果两值不同,就说明没有到达文件结尾。
绝大部分系统(不是全部)都有办法通过键盘模拟文件结尾条件。
/* echo_eof.c -- 重复输入,直到文件结尾 */
#include <stdio.h>
int main(void)
{
int ch;
while ((ch = getchar()) != EOF)
putchar(ch);
return 0;
}
注意:
UNIX(运行命令行模式时)、Linux(ditto)和Window命令行提示(模仿旧式DOS命令行环境)都能重定向输入、输出。重定向输入让程序使用文件而不是键盘来输入,重定向输出让程序输出至文件而不是屏幕。
文本文件(text file)是内含文本的文件,其中存储的数据是我们可识别的字符。文件的内容可以是一篇散文或者C程序。内含机器语言指令的文件(如存储可执行程序的文件)不是文本文件。
由于该程序的操作对象是字符,所以要使用文本文件。只需用下面的命令代替上面的命令即可:
./echo_eof < words
<符号是UNIX和DOS/Windows的重定向运算符。该运算符使words文件与stdin流相关联,把文件中的内容导入echo_eof程序。echo_eof程序本身并不知道(或不关心)输入的内容是来自文件还是键盘,它只知道这是需要导入的字符流,所以它读取这些内容并把字符逐个打印在屏幕上,直至读到文件结尾。因为C把文件和I/O设备放在一个层面,所以文件就是现在的I/O设备。
现在假设要用echo_eof把键盘输入的内容发送到名为mywords的文件中。然后,输入以下命令并开始输入:
./echo_eof>mywords
>符号是第2个重定向运算符。它创建了一个名为mywords的新文件,然后把echo_eof的输出(即,你输入字符的副本)重定向至该文件中。重定向把stdout从显示设备(即,显示器)赋给mywords文件。如果已经有一个名为mywords的文件,通常会擦除该文件的内容,然后替换新的内容(但是,许多操作系统有保护现有文件的选项,使其成为只读文件)。所有出现在屏幕的字母都是你刚才输入的,其副本存储在文件中。在下一行的开始处按下Ctrl+D(UNIX)或Ctrl+Z(DOS)即可结束该程序。
现在,假设你希望制作一份mywords文件的副本,并命名为savewords。只需输入以下命令即可:
./echo_eof < mywords > savewords
下面的命令也起作用,因为命令与重定向运算符的顺序无关:
./echo_eof > savewords < mywords
注意:
/* guess.c -- 一个拖沓且错误的猜数字程序 */
#include <stdio.h>
int main(void)
{
int guess = 1;
printf("Pick an integer from 1 to 100. I will try to guess ");
printf("it.\nRespond with a y if my guess is right and with");
printf("\nan n if it is wrong.\n");
printf("Uh...is your number %d?\n", guess);
while (getchar() != 'y') /* 获取响应,与 y 做对比 */
printf("Well, then, is it %d?\n", ++guess);
printf("I knew I could do it!\n");
return 0;
}
Pick an integer from 1 to 100. I will try to guess it.
Respond with a y if my guess is right and with
an n if it is wrong.
Uh…is your number 1?n
Well, then, is it 2?
Well, then, is it 3?n
Well, then, is it 4?
Well, then, is it 5?y
I knew I could do it!
while (getchar() != 'y') /* 获取响应,与 y 做对比*/
{
printf("Well, then, is it %d?\n", ++guess);
while (getchar() != '\n')
continue; /* 跳过剩余的输入行 */
}
Pick an integer from 1 to 100. I will try to guess it.
Respond with a y if my guess is right and with
an n if it is wrong.
Uh…is your number 1?n
Well, then, is it 2?no
Well, then, is it 3?no sir
Well, then, is it 4?forget it
Well, then, is it 5?y
I knew I could do it!
这的确是解决了换行符的问题。但是,该程序还是会把f视为n。
我们用if语句筛选其他响应。首先,添加一个char类型的变量存储响应:
char response;
修改后的循环如下:
while ((response = getchar()) != 'y') /* 获取响应 */
{
if (response == 'n')
printf("Well, then, is it %d?\n", ++guess);
else
printf("Sorry, I understand only y or n.\n");
while (getchar() != '\n')
continue; /* 跳过剩余的输入行 */
}
/* showchar1.c -- 有较大 I/O 问题的程序 */
#include <stdio.h>
void display(char cr, int lines, int width);
int main(void)
{
int ch; /* 待打印字符 */
int rows, cols; /* 行数和列数 */
printf("Enter a character and two integers:\n");
while ((ch = getchar()) != '\n')
{
scanf("%d %d", &rows, &cols);
display(ch, rows, cols);
printf("Enter another character and two integers;\n");
printf("Enter a newline to quit.\n");
}
printf("Bye.\n");
return 0;
}
void display(char cr, int lines, int width)
{
int row, col;
for (row = 1; row <= lines; row++)
{
for (col = 1; col <= width; col++)
putchar(cr);
putchar('\n'); /* 结束一行并开始新的一行 */
}
}
Enter a character and two integers:c 2 3
ccc
ccc
Enter another character and two integers;
Enter a newline to quit.
Bye.
该程序开始时运行良好。你输入c 2 3,程序打印c字符2行3列。然后,程序提示输入第2组数据,还没等你输入数据程序就退出了!
换行符在捣乱,这次是输入行中紧跟在3后面的换行符。scanf()函数把这个换行符留在输入队列中。和scanf()不同,getchar()不会跳过换行符,所以在进入下一轮迭代时,你还没来得及输入字符,它就读取了换行符,然后将其赋给ch。而ch是换行符正式终止循环的条件。
/* showchar2.c -- 按指定的行列打印字符 */
#include <stdio.h>
void display(char cr, int lines, int width);
int main(void)
{
int ch; /* 待打印字符*/
int rows, cols; /* 行数和列数 */
printf("Enter a character and two integers:\n");
while ((ch = getchar()) != '\n')
{
if (scanf("%d %d", &rows, &cols) != 2)
break;
display(ch, rows, cols);
while (getchar() != '\n')
continue;
printf("Enter another character and two integers;\n");
printf("Enter a newline to quit.\n");
}
printf("Bye.\n");
return 0;
}
void display(char cr, int lines, int width)
{
int row, col;
for (row = 1; row <= lines; row++)
{
for (col = 1; col <= width; col++)
putchar(cr);
putchar('\n'); /* 结束一行并开始新的一行 */
}
}
while循环实现了丢弃scanf()输入后面所有字符(包括换行符)的功能,为循环的下一轮读取做好了准备。
在if语句中使用一个break语句,可以在scanf()的返回值不等于2时终止程序,即如果一个或两个输入值不是整数或者遇到文件结尾就终止程序。
例如,假设你编写了一个处理非负数整数的循环,但是用户很可能输入一个负数。你可以使用关系表达式来排除这种情况:
long n;
scanf("%ld", &n); // 获取第1个值
while (n >= 0) // 检测不在范围内的值
{
// 处理n
scanf("%ld", &n); // 获取下一个值
}
另一类潜在的陷阱是,用户可能输入错误类型的值,如字符q。排除这种情况的一种方法是,检查scanf()的返回值。回忆一下,scanf()返回成功读取项的个数。因此,下面的表达式当且仅当用户输入一个整数时才为真:
scanf("%ld", &n) == 1
结合上面的while循环,可改进为:
long n;
while (scanf("%ld", &n) == 1 && n >= 0)
{
// 处理n
}
long get_long(void)
{
long input;
char ch;
while (scanf("%ld", &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;
}
// checking.c -- 输入验证
#include <stdio.h>
#include <stdbool.h>
// 验证输入是一个整数
long get_long(void);
// 验证范围的上下限是否有效
bool bad_limits(long begin, long end,
long low, long high);
// 计算a~b的整数平方和
double sum_squares(long a, long b);
int main(void)
{
const long MIN = -10000000L; // 范围的下限
const long MAX = +10000000L; // 范围的上限
long start; // 用户指定的范围最小值
long stop; // 用户指定的范围最大值
double answer;
printf("This program computes the sum of the squares of "
"integers in a range.\nThe lower bound should not "
"be less than -10000000 and\nthe upper bound "
"should not be more than +10000000.\nEnter the "
"limits (enter 0 for both limits to quit):\n"
"lower limit: ");
start = get_long();
printf("upper limit: ");
stop = get_long();
while (start != 0 || stop != 0)
{
if (bad_limits(start, stop, MIN, MAX))
printf("Please try again.\n");
else
{
answer = sum_squares(start, stop);
printf("The sum of the squares of the integers ");
printf("from %ld to %ld is %g\n",
start, stop, answer);
}
printf("Enter the limits (enter 0 for both "
"limits to quit):\n");
printf("lower limit: ");
start = get_long();
printf("upper limit: ");
stop = get_long();
}
printf("Done.\n");
return 0;
}
long get_long(void)
{
long input;
char ch;
while (scanf("%ld", &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;
}
double sum_squares(long a, long b)
{
double total = 0;
long i;
for (i = a; i <= b; i++)
total += (double) i * (double) i;
return total;
}
bool bad_limits(long begin, long end,
long low, long high)
{
bool not_good = false;
if (begin > end)
{
printf("%ld isn't smaller than %ld.\n", begin, end);
not_good = true;
}
if (begin < low || end < low)
{
printf("Values must be %ld or greater.\n", low);
not_good = true;
}
if (begin > high || end > high)
{
printf("Values must be %ld or less.\n", high);
not_good = true;
}
return not_good;
}
This program computes the sum of the squares of integers in a range.
The lower bound should not be less than -10000000 and
the upper bound should not be more than +10000000.
Enter the limits (enter 0 for both limits to quit):
lower limit: low
low is not an integer.
Please enter an integer value, such as 25, -178, or 3: 3
upper limit: a big number
a big number is not an integer.
Please enter an integer value, such as 25, -178, or 3: 12
The sum of the squares of the integers from 3 to 12 is 645
Enter the limits (enter 0 for both limits to quit):
lower limit: 80
upper limit: 10
80 isn’t smaller than 10.
Please try again.
Enter the limits (enter 0 for both limits to quit):
lower limit: 0
upper limit: 0
Done.
程序遵循模块化的编程思想,使用独立函数(模块)来验证输入和管理显示。程序越大,使用模块化编程就越重要。
main()函数管理程序流,为其他函数委派任务。它使用get_long()获取值、while循环处理值、bad_limits()函数检查值是否有效、sum_squres()函数处理实际的计算:
许多计算机程序都把菜单作为用户界面的一部分。菜单给用户提供方便的同时,却给程序员带来了一些麻烦。我们看看其中涉及了哪些问题。
菜单给用户提供了一份响应程序的选项。假设有下面一个例子:
Enter the letter of your choice:
a. advice b. bell
c. count q. quit
第1个目标是:当用户遵循指令时程序顺利运行;
第2个目标是:当用户没有遵循指令时,程序也能顺利运行。显而易见,要实现第2个目标难度较大,因为很难预料用户在使用程序时的所有错误情况。
现在的应用程序通常使用图形界面,可以点击按钮、查看对话框、触摸图标,而不是我们示例中的命令行模式。但是,两者的处理过程大致相同:给用户提供选项、检查并执行用户的响应、保护程序不受误操作的影响。除了界面不同,它们底层的程序结构也几乎相同。但是,使用图形界面更容易通过限制选项控制输入。
我们来更具体地分析一个菜单程序需要执行哪些任务。它要获取用户的响应,根据响应选择要执行的动作。另外,程序应该提供返回菜单的选项。C的switch语句是根据选项决定行为的好工具,用户的每个选择都可以对应一个特定的case标签。使用while语句可以实现重复访问菜单的功能。因此,我们写出以下伪代码:
获取选项
当选项不是’q’时
转至相应的选项并执行
获取下一个选项
当你决定实现这个程序时,就要开始考虑如何让程序顺利运行(顺利运行指的是,处理正确输入和错误输入时都能顺利运行)。例如,你能做的是让“获取选项”部分的代码筛选掉不合适的响应,只把正确的响应传入switch。这表明需要为输入过程提供一个只返回正确响应的函数。
定义get_choice()函数只能返回’a’、‘b’、‘c’和’q’。
下面的伪代码是设计这个函数的一种方案:
显示选项
获取用户的响应
当响应不合适时
提示用户再次输入
获取用户的响应
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 = getchar();
while ((ch < 'a' || ch > 'c') && ch != 'q')
{
printf("Please respond with a, b, c, or q.\n");
ch = getchar();
}
return ch;
}
缓冲输入依旧带来些麻烦,程序把用户每次按下Return键产生的换行符视为错误响应。为了让程序的界面更流畅,该函数应该跳过这些换行符。
这类问题有多种解决方案。一种是用名为get_first()的新函数替换getchar()函数,读取一行的第1个字符并丢弃剩余的字符。这种方法的优点是,把类似act这样的输入视为简单的a,而不是继续把act中的c作为选项c的一个有效的响应。我们重写输入函数如下:
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;
ch = getchar(); /* 读取下一个字符 */
while (getchar() != '\n')
continue; /* 跳过该行剩下的内容 */
return ch;
}
void count(void)
{
int n, i;
printf("Count how far? Enter an integer:\n");
scanf("%d", &n);
for (i = 1; i <= n; i++)
printf("%d\n", i);
}
如果输入3作为响应,scanf()会读取3并把换行符留在输入队列中。下次调用get_choice()将导致get_first()返回这个换行符,从而导致我们不希望出现的行为。
重写get_first(),使其返回下一个非空白字符而不仅仅是下一个字符,即可修复这个问题。
另一种方法是,在count()函数中清理换行符,如下所示:
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;
}
/* menuette.c -- 菜单程序 */
#include <stdio.h>
char get_choice(void);
char get_first(void);
int get_int(void);
void count(void);
int main(void)
{
int choice;
while ((choice = get_choice()) != 'q')
{
switch (choice)
{
case 'a': printf("Buy low, sell high.\n");
break;
case 'b': putchar('\a'); /* ANSI */
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;
ch = getchar();
while (getchar() != '\n')
continue;
return ch;
}
int get_int(void)
{
int input;
char ch;
while (scanf("%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;
}
设计一个程序,统计在读到文件结尾之前读取的字符数。
编写一个程序,在遇到EOF之前,把输入作为字符流读取。程序要打印每个输入的字符及其相应的ASCII十进制值。注意,在ASCII序列中,空格字符前面的字符都是非打印字符,要特殊处理这些字符。如果非打印字符是换行符或制表符,则分别打印\n或\t。否则,使用控制字符表示法。例如,ASCII的1是Ctrl+A,可显示为^A。注意,A的ASCII值是Ctrl+A的值加上64。其他非打印字符也有类似的关系。除每次遇到换行符打印新的一行之外,每行打印10对值。(注意:不同的操作系统其控制字符可能不同。)
编写一个程序,在遇到EOF之前,把输入作为字符流读取。该程序要报告输入中的大写字母和小写字母的个数。假设大小写字母数值是连续的。或者使用ctype.h库中合适的分类函数更方便。
编写一个程序,在遇到EOF之前,把输入作为字符流读取。该程序要报告平均每个单词的字母数。不要把空白统计为单词的字母。实际上,标点符号也不应该统计,但是现在暂时不同考虑这么多(如果你比较在意这点,考虑使用ctype.h系列中的ispunct()函数)。
修改程序清单8.4的猜数字程序,使用更智能的猜测策略。例如,程序最初猜50,询问用户是猜大了、猜小了还是猜对了。如果猜小了,那么下一次猜测的值应是50和100中值,也就是75。如果这次猜大了,那么下一次猜测的值应是50和75的中值,等等。使用二分查找(binary search)策略,如果用户没有欺骗程序,那么程序很快就会猜到正确的答案。
修改程序清单8.8中的get_first()函数,让该函数返回读取的第1个非空白字符,并在一个简单的程序中测试。
修改第7章的编程练习8,用字符代替数字标记菜单的选项。用q代替5作为结束输入的标记。
编写一个程序,显示一个提供加法、减法、乘法、除法的菜单。获得用户选择的选项后,程序提示用户输入两个数字,然后执行用户刚才选择的操作。该程序只接受菜单提供的选项。程序使用float类型的变量存储用户输入的数字,如果用户输入失败,则允许再次输入。进行除法运算时,如果用户输入0作为第2个数(除数),程序应提示用户重新输入一个新值。该程序的一个运行示例如下:
Enter the operation of your choice:
a. add s. subtract
m. multiply d. divide
q. quita
Enter first number: 22 .4
Enter second number: one
one is not an number.
Please enter a number, such as 2.5, -1.78E8, or 3: 1
22.4 + 1 = 23.4
Enter the operation of your choice:
a. add s. subtract
m. multiply d. divide
q. quitd
Enter first number: 18.4
Enter second number: 0
Enter a number other than 0: 0.2
18.4 / 0.2 = 92
Enter the operation of your choice:
a. add s. subtract
m. multiply d. divide
q. quitq
Bye.
#include <stdio.h>
int main(void)
{
unsigned count = 0u;
printf("Enter characters.The program is to count the numeber of characters!\n");
while (getchar() != EOF)
{
count++;
}
printf("%u character(s).\n",count);
return 0;
}
#include <iostream>
#include <string>
using namespace std;
int main(void)
{
string str = "";
char ch;
while ((ch = getchar()) != EOF)
{
/* code */
str.push_back(ch);
}
unsigned int count = 0u;
for (int i = 0; i < str.length(); i++)
{
cout << str[i] << " " << (int)str[i] << "\t";
count++;
if (str[i] == '\n')
{
count = 0u;
}
if (count == 10u)
{
cout << endl;
count = 0u;
}
}
return 0;
}
#include <stdio.h>
#include <ctype.h>
int main(void)
{
unsigned upper_num = 0u, lower_num = 0u;
char ch;
while ((ch = getchar()) != EOF)
{
if (islower(ch))
{
lower_num++;
}
else if (isupper(ch))
{
upper_num++;
}
}
printf("upper character: %u lower characters: %u\n", upper_num, lower_num);
return 0;
}
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char ch;
unsigned int char_num = 0u, word_num = 0u;
while ((ch = getchar()) != EOF)
{
if (ch != ' ' && !ispunct(ch) && isprint(ch))
{
char_num++;
}
if (ch == ' ' || ispunct(ch))
{
word_num++;
}
}
printf("%u %u %g\n", char_num, word_num, (float)char_num / word_num);
return 0;
}
#include <stdio.h>
#include <ctype.h>
int main(void)
{
int guess = (0 + 100) / 2;
char ch;
int up = 100, down = 0;
printf("Pick an integer from 1 to 100. I will try to guess ");
printf("it.\nRespond with a d if my guess is big and with");
printf("\na x if it is small.\n");
printf("and with a y if my guess is right.\n");
printf("Uh...is your number %d?\n", guess);
while ((ch = getchar()) != 'y') /* 获取响应,与 y 做对比 */
{
if (isalpha(ch))
{
ch = tolower(ch);
}
switch (ch)
{
case 'd':
up = guess;
guess = (guess + down) / 2;
printf("Well, then, is it %d?\n", guess);
break;
case 'x':
down = guess;
guess = (guess + up) / 2;
printf("Well, then, is it %d?\n", guess);
break;
default:
printf("Error!\n");
break;
}
while (getchar() != '\n')
{
continue;
}
}
printf("I knew I could do it!\n");
return 0;
}
#include <stdio.h>
#include <ctype.h>
char get_first(void)
{
int ch;
// ch = getchar(); /* 读取下一个字符 */
while (ch = getchar())
{
if (!isblank(ch))
break;
}
while (getchar() != '\n')
continue; /* 跳过该行剩下的内容 */
return ch;
}
int main(void)
{
char ch = get_first();
printf("%c\n",ch);
return 0;
}
#include <stdio.h>
#include <stdbool.h>
#include<ctype.h>
#define BASETIME 40
#define BI 1.5
#define SHUIBASE 300
#define SHUIBASE1 450
#define SHUIRATE 0.15
#define SHUIRATE2 0.2
#define SHUIRATE3 0.25
char get_first(void);
int main(void)
{
float base;
while (true)
{
printf("*****************************************************************\n");
printf("Enter the number corresponding to the desired pay rate or action:\n");
printf("a) $8.75/hr\n");
printf("b) $9.33/hr\n");
printf("c) $10.00/hr\n");
printf("d) $11.20/hr\n");
printf("q) quit\n");
printf("*****************************************************************\n");
printf("please enter option number: ");
char option = get_first();
switch (option)
{
case 'a':
base = 8.75;
break;
case 'b':
base = 9.33;
break;
case 'c':
base = 10.00;
break;
case 'd':
base = 11.20;
case 'q':
printf("Exit!\n");
return 0;
break;
default:
printf("Error!Repeat!\n");
continue;
break;
}
unsigned time;
printf("enter the number of work time: ");
scanf("%u", &time);
float money;
money = time >= BASETIME ? (BASETIME * base + (time - BASETIME) * BI * base) : (base * time);
float rate;
if (money <= SHUIBASE)
{
rate = money * SHUIRATE;
}
else if (money <= SHUIBASE1)
{
rate = SHUIBASE * SHUIRATE + (money - SHUIBASE) * SHUIRATE2;
}
else
{
rate = SHUIBASE * SHUIRATE + (SHUIBASE1 - SHUIBASE) * SHUIRATE2 + (money - SHUIBASE1) * SHUIRATE3;
}
printf("shuiqian: %g,shui: %g,shuihou: %g\n", money, rate, money - rate);
}
}
char get_first(void)
{
int ch;
// ch = getchar(); /* 读取下一个字符 */
while (ch = getchar())
{
if (!isblank(ch))
break;
}
while (getchar() != '\n')
continue; /* 跳过该行剩下的内容 */
return ch;
}
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdbool.h>
#include <ctype.h>
char get_first(void);
char get_choice(void);
float add(float num1, float num2);
float sub(float num1, float num2);
float mul(float num1, float num2);
float div(float num1, float num2);
float get_float(void);
int main(void)
{
char option;
float num1, num2;
while (true)
{
option = get_choice();
if (option == '0')
{
printf("Error!Repeat!\n");
continue;
}
if (option != 'q')
{
printf("Enter first number: \n");
num1 = get_float();
printf("Enter second number: \n");
num2 = get_float();
}
switch (option)
{
case 'a':
printf("%g + %g = %g\n", num1, num2, add(num1, num2));
break;
case 's':
printf("%g - %g = %g\n", num1, num2, sub(num1, num2));
break;
case 'm':
printf("%g * %g = %g\n", num1, num2, mul(num1, num2));
break;
case 'd':
while (num2 == 0)
{
printf("input error! Repeat!\n");
printf("Enter second number: \n");
num2 = get_float();
}
printf("%g / %g = %g\n", num1, num2, div(num1, num2));
break;
case 'q':
printf("Bye!\n");
return 0;
default:
printf("Program error!\n");
return 0;
break;
}
}
return 0;
}
char get_first(void)
{
int ch;
// ch = getchar(); /* 读取下一个字符 */
while (ch = getchar())
{
if (!isblank(ch))
break;
}
while (getchar() != '\n')
continue; /* 跳过该行剩下的内容 */
return ch;
}
char get_choice(void)
{
printf("=====================================\n");
printf("a. add s. subtract\n");
printf("m. multiply d. divide\n");
printf("q. quit\n");
printf("=====================================\n");
printf("Enter the operation of your choice:\n");
char ch = get_first();
if (ch != 'a' && ch != 's' && ch != 'm' && ch != 'd' && ch != 'q')
{
return '0';
}
return ch;
}
float add(float num1, float num2)
{
return num1 + num2;
}
float sub(float num1, float num2)
{
return num1 - num2;
}
float mul(float num1, float num2)
{
return num1 * num2;
}
float div(float num1, float num2)
{
return num1 / num2;
}
float get_float(void)
{
float num;
while (scanf("%f", &num) != 1)
{
printf("input error! Repeat!\n");
while (getchar() != '\n')
{
continue;
}
}
while (getchar() != '\n')
{
continue;
}
return num;
}
文章浏览阅读2w次,点赞51次,收藏33次。一、需求给定一个整数,返回大于等于该整数的最小2次幂(2的乘方)。例: 输入 输出 -1 1 1 1 3 4 9 16 15 16二、分析当遇到这个需求的时候,我们可能会很容易想到一个"笨"办法:..._整数 最小的2的几次方
文章浏览阅读865次。选项,以防止命令将 IP 地址解析为主机名。如果只想在命令的输出中显示 unix套接字 连接,可以使用。不带任何选项,用来显示已建立连接的所有套接字的列表。如果只想在命令的输出中显示 tcp 连接,可以使用。如果只想在命令的输出中显示 udp 连接,可以使用。如果不想将ip地址解析为主机名称,可以使用。如果要取消命令输出中的标题行,可以使用。如果只想显示被侦听的套接字,可以使用。如果只想显示ipv4侦听的,可以使用。如果只想显示ipv6侦听的,可以使用。_ss@,,x,, 0
文章浏览阅读568次。CommandNotFoundError: 'activate'_commandnotfounderror: 'activate
文章浏览阅读426次,点赞10次,收藏19次。完成以上步骤后,您已在 Windows 10 上成功安装并验证了 Apache Kafka。在生产环境中,通常会将 Kafka 与外部 ZooKeeper 集群配合使用,并考虑配置安全、监控、持久化存储等高级特性。在生产者窗口中输入一些文本消息,然后按 Enter 发送。ZooKeeper 会在新窗口中运行。在另一个命令提示符窗口中,同样切换到 Kafka 的。Kafka 服务器将在新窗口中运行。在新的命令提示符窗口中,切换到 Kafka 的。,应显示已安装的 Java 版本信息。_win10安装部署kafka
文章浏览阅读1.4w次。缓冲区对象(Buffer Object)是在OpenGL中用于存储和管理数据的一种机制。缓冲区对象可以存储各种类型的数据,例如顶点、纹理坐标、颜色等。在渲染过程中,缓冲区对象中存储的数据可以被复制到渲染管线的不同阶段中,例如顶点着色器、几何着色器和片段着色器等,以完成渲染操作。相比传统的CPU访问内存,缓冲区对象的数据存储和管理更加高效,能够提高OpenGL应用的性能表现。_js 缓冲数据 new float32array
文章浏览阅读912次。(1)图(Graph):图是数学和计算机科学中的一个抽象概念,它由一组节点(顶点)和连接这些节点的边组成。图可以是有向的(有方向的,边有箭头表示方向)或无向的(没有方向的,边没有箭头表示方向)。图用于表示各种关系,如社交网络、电路、地图、组织结构等。(2)网络(Network):网络是一个更广泛的概念,可以包括各种不同类型的连接元素,不仅仅是图中的节点和边。网络可以包括节点、边、连接线、路由器、服务器、通信协议等多种组成部分。网络的概念在各个领域都有应用,包括计算机网络、社交网络、电力网络、交通网络等。_图论与网络优化数学建模
文章浏览阅读1.5k次。我们经常会碰见 正在加载中,加载出错, “暂无商品”等一系列的相似的布局,因为我们有很多请求网络数据的页面,我们不可能每一个页面都写几个“正在加载中”等布局吧,这时候将这些状态的布局封装在一起就很有必要了。我们可以将这些封装为一个自定布局,然后每次操作该自定义类的方法就行了。 首先一般来说,从服务器拉去数据之前都是“正在加载”页面, 加载成功之后“正在加载”页面消失,展示数据;如果加载失败,就展示_adnroid加载数据转圈封装全屏转圈封装
文章浏览阅读1.6k次,点赞23次,收藏29次。PS: 如果执行sudo grep 'temporary password' /var/log/mysqld.log 后没有报错,也没有任何结果显示,说明默认密码为空,可以直接进行下一步(后面设置密码时直接填写新密码就行)。3.(可选)当操作系统为Alibaba Cloud Linux 3时,执行如下命令,安装MySQL所需的库文件。下面示例中,将创建新的MySQL账号,用于远程访问MySQL。2.依次运行以下命令,创建远程登录MySQL的账号,并允许远程主机使用该账号访问MySQL。_alibaba cloud linux 3
文章浏览阅读7.8k次。EXCEL中数据如何做离散性分析纠错。离散不是均值抄AVEDEV……=AVEDEV(A1:A100)算出来的是A1:A100的平均数。离散是指各项目间指标袭的离散均值(各数值的波动情况),数值较低表明项目间各指标波动幅百度小,数值高表明波动幅度较大。可以用excel中的离散公式为STDEV.P(即各指标平均离散)算出最终度离散度。excel表格函数求一组离散型数据,例如,几组C25的...用exc..._excel数据分析离散
文章浏览阅读406次,点赞7次,收藏8次。i < 5){ //第3行。int count;System.out.println ("危险!System.out.println(”真”);System.out.println(”假”);System.out.print(“姓名:”);System.out.println("无匹配");System.out.println ("安全");
文章浏览阅读3.6k次。背景测试到性能、压力时,经常需要查看磁盘、网络、内存、cpu的性能值这里简单介绍下各个指标的含义一般磁盘比较关注的就是磁盘的iops,读写速度以及%util(看磁盘是否忙碌)CPU一般比较关注,idle 空闲,有时候也查看wait (如果wait特别大往往是io这边已经达到了瓶颈)iostatiostat uses the files below to create ..._/proc/diskstat
文章浏览阅读2.4k次。问题:在Android上使用 glReadPixel 读取当前渲染数据,在若干机型(华为P9以及魅族某魅蓝手机)上读取数据失败,glGetError()没有抓到错误,但是获取到的数据有误,如果将获取到的数据保存成为图片,得到的图片为黑色。解决方法:glReadPixels实际上是从缓冲区中读取数据,如果使用了双缓冲区,则默认是从正在显示的缓冲(即前缓冲)中读取,而绘制工作是默认绘制到后缓..._glreadpixels 全黑