文章目录
6.1 再探 while 循环
经过上一章的学习,读者已经熟悉了 while 循环。这里,我们用一个程序来回顾一下。
/* 根据用户输入的整数求和 */
#include <stdio.h>
int main(void)
{
long num;
long sum = 0L; /* 把 sum 初始化为0 */
int status;
printf("Please enter an integer to be summed ");
printf("(q to quit): ");
status = scanf("%ld", &num);
while(status == 1) /* == 的意思是“等于” */
{
sum = sum + num;
printf("Please enter next integer (q to quit): ");
status = scanf("%ld", &num);
}
printf("Those integers sum to %ld.\n", sum);
return 0;
}
Please enter an integer to be summed (q to quit): 44
Please enter next integer (q to quit): 33
Please enter next integer (q to quit): 88
Please enter next integer (q to quit): 121
Please enter next integer (q to quit): q
Those integers sum to 286.
6.1.1 程序注释
先看 while 循环,该循环的测试条件是如下表达式:
status == 1
== 运算符是C的相等运算符(equality operator),该表达式判断 status 是否等于 1。
现在,我们来看看该程序的结构。总结如下:
把 sum 初始化为 0
提示用户输入数据
读取用户输入的数据
当输入的数据为整数时,
——输入添加给 sum,
——提示用户进行输入,
——然后读取下一个输入
输入完成后,打印 sum 的值
这叫作 伪代码(pseudocode) ,是一个用简单的句子表示程序思路的方法,它与计算机语言的形式相对应。伪代码有助于设计程序的逻辑。确定程序的逻辑无误之后,再把伪代码翻译成实际的编程代码。
6.2 while 语句
while 循环的通用形式如下:
while(expression)
statement
statement 部分可以是以分号结尾的简单语句,也可以是用花括号括起来的复合语句。
6.2.1 终止 while 循环
while 循环有一点非常重要:在构建 while 循环时,必须让测试表达式的值有变化,表达式最终要为假。否则,循环就不会终止。
6.2.2 何时终止循环
要明确一点:只有在对测试条件求值时,才决定时终止还是继续循环。
6.2.3 while :入口条件循环
while 循环是使用入口条件的有条件循环。所谓 “有条件” 指的是语句部分的执行取决于测试表达式描述的条件。该表达式是一个 入口条件(entry condition),因为必须满足条件才能进入循环体。
6.2.4 语法要点
使用 while 时,要牢记一点:只有在测试条件后面的单独语句(简单语句或复合语句)才是循环部分。如果入口条件一直为真,这循环会一直执行下去,除非强行关闭程序。这是一个 无限循环(infinite loop)。
#include <stdio.h>
int main(void)
{
int n = 0;
while(n++ < 3);
printf("n is %d\n", n);
printf("That's all this program does.\n");
return 0;
}
n is 4
That’s all this program does.
在该例中,测试条件后面的单独分号是 空语句(null statement),它什么也不做。在C语言中,单独的分号表示空语句。
注意,为了提高代码的可读性,应该让这个分号独占一行,不要直接把它放在测试表达式同行。这样做一方面让读者更容易看到空语句,一方面也提醒自己和读者空语句是有意而为之。
6.3 用关系运算符和表达式比较大小
while 循环经常依赖测试表达式作比较,这样的表达式被称为 *关系表达式(relational expression)*出现在关系表达式中间的运算符叫做 关系运算符(relational operator)。
6.3.1 新的 _Bool 类型
在编程中,表示真或假的变量被称为 布尔变量(Boolean variable) .
#include <stdio.h>
int main(void)
{
long num;
long sum = 0L;
_Bool input_is_good;
printf("Please enter an integer to be summed ");
printf("(q to quit): ");
input_is_good = (scanf("%ld", &num) == 1);
while(input_is_good)
{
sum = sum + num;
printf("Please enter next integer (q to quit): ");
input_is_good = (scanf("%ld", &sum) == 1);
}
printf("Those integers sum to %ld.\n", sum);
return 0;
}
注意程序中把比较的结果赋值给 _Bool 类型的变量 input_is_good:
input_is_good = (scanf("%ld", &sum) == 1);
这样做没问题,因为 == 运算符返回的值不是 1 就是 0。顺带一提,从优先级方面考虑的话,并不需要用圆括号把 scanf("%ld", &sum) == 1 括起来。但是,这样做可以提高代码可读性。还要注意,如何为变量命名才能让 while 循环的测试简单易懂:
while(input_is_good)
C99 提供了 stdbool.h 头文件,该头文件让 bool 成为 _Bool 的别名,而且还把 true 和 false 分别定义为 1 和 0 的符号常量。包含该头文件后,写出的代码可以与 C++ 兼容,因为 C++ 把 bool、true、false 定义为关键字。
如果系统不支持 _Bool 类型,导致无法运行该程序,可以把 _Bool 替换成 int 即可。
6.3.2 优先级和关系运算符
关系运算符的优先级比算术运算符(包括 + 和 -)低,比赋值运算符高。这意味着 x > y + 2 和 x > (y + 2) 相同,x = y > 2 和 x = (y > 2) 相同。换言之,如果 y 大于 2,则给 x 赋值 1,否则赋值 0,y 的值不会赋给 x。
关系运算符比赋值运算符的优先级高,因此,x_bigger = x > y; 相当于 x_bigger = (x > y); 。关系运算符之间有两种不同的优先级。
高优先级组: <<= >>=
低优先级组: == !=
与其他大多数运算符一样,关系运算符的结合律也是从左往右。
小结:while 语句
关键字: while
一般注解:
while 语句创建了一个循环,重复执行直到测试表达式为假或 0。while 语句是一种入口条件循环,也就是说,在执行多次循环之前已决定是否执行循环。因此,循环有可能不被执行。循环体可以是简单语句,也可以是复合语句。
形式:while(expression) statement
在 expression 部分为假或 0 之前,重复执行 statement 部分。
示例:while(n++ < 100) printf(" %d %d\n", n, 2 * n + 1); //简单语句 while(fargo < 1000) { // 复合语句 fargo = fargo + step; step = 2 * step; }
小结:关系运算符和表达式
关系运算符:
每个关系运算符都把它左侧的值和右侧的值进行比较。< 小于 <= 小于或等于 == 等于 >= 大于或等于 > 大于 != 不等于
关系表达式:
简单的关系表达式由关系运算符及其运算对象组成。如果关系为真,关系表达式的值为 1;如果关系为假,关系表达式的值为 0;
示例:
5 > 2 为真,关系表达式的值为 1
(2 + a) == a 为假,关系表达式的值为 0
6.4 不确定循环和计数循环
一些 while 循环是 不确定循环(indefinite loop)。所谓不确定循环,指在测试表达式为假之前,预先不知道要执行多少次循环。例如,下面程序通过与用户交互获得数据来计算整数之和。我们事先并不知道用户会输入什么整数。另外,还有一类是 计数循环(counting loop)。这类循环在执行循环之前就知道要重复执行多少次。
// 一个技术循环
#include <stdio.h>
int main(void)
{
const int NUMBER = 22;
int count = 1; // 初始化
while(count <= NUMBER) // 测试
{
printf("Be my Valentine!\n"); // 行为
count++; // 更新计数
}
return 0;
}
虽然程序运行情况良好,但是定义循环的行为并未阻止在一起,程序的编排并不是很理想。
在创建一个重复执行固定次数的循环中涉及了 3 个行为:
1、必须初始化计数器;
2、计数器与有限的值作比较;
3、每次循环时递增计数器。
while 循环的测试条件执行比较,递增运算执行递增。递增发生在循环的末尾,这可以防止不小心漏掉递增。因此,这样做比将测试和更新组合放在一起(即使用 count++ <= NUMBER)要好,但是计数器的初始化放在循环外,就有可能忘记初始化。实践告诉我们可能会发生的事前终究会发生,所以我们来学习另一种控制语句,可以避免这些问题。
6.5 for 循环
for 循环把上述 3 个行为(初始化、测试和更新)组合在一处。如下程序:
// 使用 for 循环的技术循环
#include <stdio.h>
int main(void)
{
const int NUMBER = 22;
int count;
for(count = 1; count <= NUMBER; count++)
printf("Be my Valentine!\n");
return 0;
}
关键字 for 后面的圆括号中有 3 个表达式,分别用两个分号隔开。第 1 个表达式是初始化,只会在 for 循环开始时执行一次。第 2 个表达式是测试条件,在执行循环之前对表达式求值。如果表达式为假(本例中,count 大于 NUMBER 时),循环结束。第 3 个表达式执行更新,在每次循环结束时求值。完整的 for 语句还包括后面的简单语句或复合语句。for 圆括号中的表达式也叫做控制表达式,它们都是完整表达式,所以每个表达式的副作用(如,递增变量)都发生在对下一个表达式求值之前。
6.6 其他赋值运算符:+=、-=、*=、/=、%=
C有许多赋值运算符。最基本、最常见的是 =,它把右侧表达式的值赋给左侧的变量。其他赋值运算符都用于更新变量,其用法都是左侧是一个变量,右侧是一个表达式。赋给变量的新值是根据右侧表达式的值调整后的值。确切的调整方案取决于具体的运算符。例如:
scores += 20 与 scores = scores + 20 相同
dimes -= 2 与 dimes = dimes - 2 相同
bunnies *= 2 与 bunnies = bunnies * 2 相同
time /= 2.73 与 time = time / 2.73 相同
reduce %= 3 与 reduce = reduce % 3 相同
x *= 3 * y + 12 与 x = x * (3 * y + 12) 相同
6.7 逗号运算符
逗号运算符扩展了 for 循环的灵活性,以便在循环头中包含更多的表达式。例如,打印一类邮件资费(first-class postage rate)的程序(假设邮资为首重 40 美分/盎司,续重 20 美分/盎司)。
// 一类邮资
#include <stdio.h>
int main(void)
{
const int FIRST_OZ = 46;
const int NEXT_OZ = 20;
int ounces, cost;
printf(" ounces cost\n");
for(ounces = 1, cost = FIRST_OZ; ounces <= 16; ounces++, cost += NEXT_OZ)
printf("%5d $%4.2f\n", ounces, cost / 100.0);
return 0;
}
该程序在初始化表达式和更新表达式中使用了逗号运算符。初始化表达式中的逗号使 ounces 和 cost 都进行了初始化,更新表达式中的逗号使每次迭代 ounces 递增 1、cost 递增 20(NEXT_OZ 的值是 20)。绝大多数计算都在 for 循环头中进行。
逗号运算符并不局限于在 for 循环中使用,但是这是它最常用的地方。逗号运算符有两个其他性质。首先,它保证了被它分隔的表达式从左往右求值(换言之,逗号使一个序列点,所以逗号左侧项的所有副作用都在程序执行逗号右侧项之前发生)。因此,ounces 在 cost 之前被初始化。在该例中,顺讯并不重要,当如果 cost 的表达式中包含了 ounces 时,顺讯就很重要。
小结:新的运算符
赋值运算符:
+= 把右侧的值加到左侧的变量上
-= 从左侧的变量中减去右侧的值
*= 把左侧的变量乘以右侧的值
/= 把左侧的变量除以右侧的值
%= 左侧变量除以右侧值得到的余数
逗号运算符:
逗号运算符把两个表达式连接成一个表达式,并保证最左边的表达式最先求值。逗号运算符通常在 for 循环头的表达式中用于包含更多的信息。整个逗号表达式的值是逗号右侧表达式的值。
6.8 出口条件循环:do while
while 循环和for 循环都是入口条件循环,即在循环的每次迭代之前坚持测试条件,所以有可能根本不执行循环体中的内容。C语言还有 出口条件循环(exit-condition loop) ,即在循环的每次迭代之后检查测试条件,这保证了至少执行循环体中的内容一次。这种循环被称为 do while 循环。例如:
// 出口条件循环
#include <stdio.h>
int main(void)
{
const int secret_code = 13;
int code_entered;
do
{
printf("To enter the triskaidekaphobia therapy club,\n");
printf("please enter the secret code number: ");
scanf("%d", &code_entered);
}while(code_entered != secret_code);
printf("Congratulations! You are cured!\n");
return 0;
}
输出:
To enter the triskaidekaphobia therapy club,
please enter the secret code number: 12
To enter the triskaidekaphobia therapy club,
please enter the secret code number: 14
To enter the triskaidekaphobia therapy club,
please enter the secret code number: 13
Congratulations! You are cured!
小结:do while 语句
**关键字:**do while
一般注解:
do while 语句创建一个循环,在 expression 为假或 0 之前重复执行循环体中的内容。do while 语句是一种出口条件循环,即在执行完循环体后才根据测试条件决定是否再次执行循环。因此,该循环至少必须执行一次。statement 部分科室一条简单语句或复合语句。
6.9 如何选择循环
首先,确定是需要入口条件还是出口条件。通常,入口条件循环用得比较多,有一个原因。奇异,一般原则是在执行徐怒吼之前测试条件比较好。其二,测试放在循环的开头,成的可读性更高。另外,在许多应用中,要求在一开始不满足测试条件时就直接跳过整个循环。
6.10 嵌套循环
嵌套循环(nested loop) 指在一个循环内包含另一个循环。嵌套循环常用于按行和列显示数据,也就是说,一个循环处理一行中的所有列,另一个循环处理 所有的行。在外层的叫做外层循环(outer loop),在内层的叫做内层循环(inner loop)。
6.11 数组简介
数组(array) 是按顺序储存的一系列类型相同的值,通过整数下表访问数组中单独的项或元素(element)。用于识别数组元素的数字被称为下标(subscript)、索引(indice)或偏移量(offset)。下标必须是整数,而且要从 0 开始计数。数组的元素被依次储存在内存中相邻的位置。
6.12 关键概念
循环是一个强大的编程工具。在创建循环时,要特别注意一下 3 个方面:
- 注意循环的测试条件要能使循环结束;
- 确保循环测试中的值在首次使用之前已初始化;
- 确保循环在每次迭代都更新测试的值。
C通过求值类处理测试条件,结果为 0 表示假,非 0 表示真。带关系运算符的表达式常用于循环测试,它们有些特殊。如果关系表达式为真,其值为 1;如果为假,其值为 0。这与新类型 _Bool 的值保持一致。
数组由相邻的内存位置组成,值储存相同类型的数据。记住,数组元素的标号从 0 开始,所有数组最后一个元素的下标一定比元素数目少 1。C编译器不会检查数组下标值是否有效,自己要多留心。
使用函数涉及 3 个步骤:
- 通过函数原型声明函数;
- 在程序中通过函数调用使用函数;
- 定义函数。
函数原型是为了方便编译器查看程序中使用的函数是否正确,函数定义描述了函数如何工作。现代的编程习惯是把程序要素分为接口部分和实现部分。接口部分描述了如何使用一个特性,也就是函数原型所做的;实现部分描述了具体的行为,这正是函数定义所做的。
6.13 本站小结
本章的主题是程序控制。C语言为实现结构化的程序提供了许多工具。while 语句和 for 语句提供了入口条件循环。for 语句特别使用与需要初始化和更新的循环。使用逗号运算符可以在 for 循环中初始化和更新多个变量。又饿场合也需要使用出口条件循环,C为此提供了 do while 语句。
除了关系运算符,本章还介绍了其他的组合赋值运算符。这些运算符通过对其左侧运算对象执行算术运算类修改它的值。
6.14 复习题
1、写出执行完下列各行后 quack 的值是多少。后 5 行中使用的是第 1 行 quack 的值。
int quack = 2;
quack += 5;
quack *= 10;
quack -= 6;
quack /= 8;
quack %= 3;
答案:2、7、70、64、8、2
2、假设 value 是 int 类型,下面循环的输出是什么?
for(value = 36; value > 0; value /= 2)
printf("%3d", value);
如果 value是 double 类型,会出现什么问题?
答案:循环输出:36 18 9 4 2 1 。如果 value 是 double 类型的,条件 value > 0 将永远满足,进入死循环,而且 转换符 %d 类型也不符,打印出来的数与实际值不相同(实际打印的值为随机数)
3、用代码表示一下测试条件:
a、x 大于 5
b、scanf() 读取一个名为 x 的 double 类型值且失败
c、x 的值等于 5
答案:a、 x > 5;b、scanf("%lf", &x) != 1;c、x = 5
4、用代码表示一下测试条件:
a、scanf() 成功读入一个整数
b、x 不等于 5
c、x 大于或等于 20
答案: a、scanf("%d", &x) == 1;b、x != 5;c、x >= 20
5、下面的程序有点问题,请找出问题所在。
#include <stdio.h>
int main(void)
{ /** 第 3 行 */
int i, j, list(10); /** 第 4 行 */
for(i = 1 i <= 10 i++) /** 第 6 行 */
{ /** 第 7 行 */
list[i] = 2 * i + 3; /** 第 8 行 */
for(j = 1, j > = i, j++) /** 第 9 行 */
printf(" %d", list[j]); /** 第 10 行 */
printf("\n"); /** 第 11 行 */
} /** 第 12 行 */
答案:
#include <stdio.h>
int main(void)
{
int i, j, list[10];
for(i = 0; i < 10; i++)
{
list[i] = 2 * i + 3;
for(j = 0; j <= i; j++)
printf(" %d", list[j]);
printf("\n");
}
return 0;
}
6、编写一个程序打印下面的图案,要求使用嵌套循环:
$$$$$$$$
$$$$$$$$
$$$$$$$$
$$$$$$$$
答案:
#include <stdio.h>
int main(void)
{
for(int i = 0; i < 5; i++)
{
for(int j = 0; j < 8; j++)
{
printf("$");
}
printf("\n");
}
return 0;
}
7、下面的程序个打印什么内容?
a、
#include <stdio.h>
int main(void)
{
int i = 0;
while(++i < 4)
printf("Hi! ");
do
printf("Bye! ");
while (i++ < 8);
return 0;
}
b、
#include <stdio.h>
int main(void)
{
int i;
char ch;
for(i = 0, ch = 'A'; i < 4; i++, ch += 2 * i)
printf("%c", ch);
return 0;
}
答案:a、Hi! Hi! Hi! Bye! Bye! Bye! Bye! Bye! ;b、ACGM
8、假设用户输入的是 Go west, young man!,下面各程序的输出是什么?(在ASCII码中,!紧跟在空格字符后面)
a、
#include <stdio.h>
int main(void)
{
char ch;
scanf("%c", &ch);
while(ch != 'g'){
printf("%c", ch);
scanf("%c", &ch);
}
return 0;
}
b、
#include <stdio.h>
int main(void)
{
char ch;
scanf("%c", &ch);
while(ch != 'g'){
printf("%c", ++ch);
scanf("%c", &ch);
}
return 0;
}
c、
#include <stdio.h>
int main(void)
{
char ch;
scanf("%c", &ch);
do
{
printf("%c", ch);
scanf("%c", &ch);
} while (ch != 'g');
return 0;
}
d、
#include <stdio.h>
int main(void)
{
char ch;
scanf("%c", &ch);
for(ch = '$'; ch != 'g'; scanf("%c", &ch))
{
printf("%c", ch);
}
return 0;
}
答案:a、Go west, youn;b、Hp!xftu-!zpvo;c、Go west, young;d、$o west, young;
9、下面的程序打印什么内容?
#include <stdio.h>
int main(void)
{
int n ,m;
n = 30;
while(++n <= 33)
printf("%d|", n);
n = 30;
do
printf("%d|", n);
while(++n <= 33);
printf("\n***\n");
for(n = 1; n*n < 200; n += 4)
printf("%d\n", n);
printf("\n***\n");
for(n = 2, m = 6; n < m; n *= 2, m+= 2)
printf("%d %d\n", n , m);
printf("\n***\n");
for(n = 5; n > 0; n--)
{
for(m = 0; m <= n; m++)
printf("=");
printf("\n");
}
return 0;
}
答案:
31|32|33|30|31|32|33|
***
1
5
9
13
***
2 6
4 8
8 10
***
======
=====
====
===
==
10、考虑下面的声明:
double mint[10]
a、数组名是什么?
b、该数组有多少个元素?
c、每个元素可以储存什么类型的值?
d、下面的哪一个 scanf() 的用法正确?
i、scanf("%lf", mint[2])
ii、scanf("%lf", &mint[2])
iii、scanf("%lf", &mint)
答案:a、mint;b、10个;c、double;d、ii
11、Noah 先生喜欢以 2 计数,所以编写了下面的程序,创建了一个储存 2、4、6、8 等数字的数组。这个程序是否有错误之处?如果有,请指出。
#include <stdio.h>
#define SIZE 8
int main(void)
{
int by_twos[SIZE];
int index;
for(index = 1; index <= SIZE; index++)
by_twos[index] = 2 * index;
for(index = 1; index <= SIZE; index++)
printf("%d ", by_twos);
printf("\n");
return 0;
}
答案:1、index 的范围应该是 0 ~ SIZE - 1;2、by_twos[index] = 2 * (index + 1)
12、假设要编写一个返回 long 类型值的函数,函数定义中应包含什么?
答案:将函数的返回值类型定义为 long,并添加返回一个 long 类型数字的 return 语句。
13、定义一个函数,接受一个 int 类型的参数,并以 long 类型返回参数的平方值。
答案:将函数的返回值类型定义为 long,将函数接收参数类型定义为 int 类型,将该 int 值强制转换为 long 类型(如果计算平方的 int 值过大,计算后的值将超过 int 范围,会丢失精度),计算平方值,并添加返回一个 long 类型数字的 return 语句。
14、下面的程序打印什么内容?
#include <stdio.h>
#define SIZE 8
int main(void)
{
int k;
for(k = 1, printf("%d: Hi!\n", k); printf("k = %d\n", k), k*k < 26; k += 2, printf("Now k is %d\n", k))
printf("k is %d in the loop\n", k);
return 0;
}
答案:
1: Hi!
k = 1
k is 1 in the loop
Now k is 3
k = 3
k is 3 in the loop
Now k is 5
k = 5
k is 5 in the loop
Now k is 7
k = 7
6.15 编程练习
1、编写一个程序,创建一个包含 26 个元素的数组,并在其中储存 26 个小写字母。然后打印数组的所有内容。
答案:
#include <stdio.h>
int main(void)
{
char ch[] = {'a','b','c','d','e','f','g','g','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
for(int i = 0,length = sizeof(ch); i < length; i++)
{
printf("%2c", ch[i]);
}
return 0;
}
2、使用嵌套循环,按下面的格式打印字符:
$
$$
$$$
$$$$
$$$$$
答案:
#include <stdio.h>
int main(void)
{
for(int i = 0; i < 5; i++)
{
for(int j = 0; j <= i; j++){
printf("$");
}
printf("\n");
}
return 0;
}
3、使用嵌套循环,按下面的格式打印字符:
F
FE
FED
FEDC
FEDCB
FEDCBA
注意:如果你的系统不使用 ASCII 或其他以数字顺序编码的代码,可以把字符数组初始化为字母表中的字母:
char lets[26] = “ABCDEFGHIJKLMNOPQRSTUVWXYZ”;
然后用数组下标选择单独的字母,例如 lets[0] 是 ‘A’ ,等等。
答案:
#include <stdio.h>
int main(void)
{
for(char i = 'F'; i >= 'A'; i--)
{
for(char j = 'F'; j >= i; j--){
printf("%c", j);
}
printf("\n");
}
return 0;
}
4、使用嵌套循环,按下面的格式打印字符:
A
BC
DEF
GHIJ
KLMNO
PQRSTU
如果你的系统不使用一数字顺序编码的代码,请参照练习 3 的方案解决。
答案:
#include <stdio.h>
int main(void)
{
char lets[26] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int index = 0;
for(int i = 0; i < 6; i++)
{
for(int j = 0; j <= i; j++){
printf("%c", lets[index]);
index++;
}
printf("\n");
}
return 0;
}
5、编写一个程序,提示用户输入大写字母。使用嵌套循环以下面金字塔型的格式打印字母:
A
ABA
ABCBA
ABCDCBA
ABCDEDCBA
打印这样的图形,要根据用户输入的字母来决定。例如,上面的图形是用户输入 E 后的打印结果。提示:用外层循环处理行,每行使用 3 个内层循环,分别处理空格、以升序打印字母、以降序打印字母。如果你的系统不使用一数字顺序编码的代码,请参照练习 3 的方案解决。
答案:
#include <stdio.h>
int main(void)
{
char lets[26] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int index = 0;
for(int i = 0; i < 5; i++)
{
for(int j = 5; j > i; j--){
printf(" ");
}
for(int k = 0; k <= i; k++){
index = k;
printf("%c", lets[k]);
}
for(int l = index - 1; l >= 0; l--){
printf("%c", lets[l]);
}
printf("\n");
}
return 0;
}
6、编写一个程序打印一个表格,每一行打印一个整数、该数的平方、该数的立方。要求用户输入表格的上下限。使用一个 for 循环。
答案:
#include <stdio.h>
int main(void)
{
int start,end;
printf("Please input start number!\n");
scanf("%d", &start);
printf("Please input end number!\n");
scanf("%d", &end);
for(; start <= end; start++){
printf("%2d %2d %2d\n", start, start * start, start * start * start);
}
return 0;
}
7、编写一个程序把一个单词读入一个字符数组中,然后倒序打印这个单词。提示:strlen() 函数可用于计算数组最后一个字符的下标。
答案:
#include <stdio.h>
#include <string.h>
int main(void)
{
char ch[20];
printf("Please input words!\n");
scanf("%s", ch);
int len = strlen(ch);
for(int i = len - 1; i >= 0; i--){
printf("%2c", ch[i]);
}
printf("\n");
return 0;
}
8、编写一个程序,要求用户输入两个浮点数,并打印两数之差除以两数乘积的结果。在用户输入非数字之前,程序应循环处理用户输入的每对值。
答案:
#include <stdio.h>
int main(void)
{
float a, b;
printf("Please input two num!\n");
while(scanf("%f %f", &a, &b) == 2)
printf("%f\n", (a - b) / (a * b));
return 0;
}
9、修改练习 8 ,使用一个函数返回计算的结果。
答案:
#include <stdio.h>
float compute(float a, float b);
int main(void)
{
float a, b;
printf("Please input two num!\n");
while(scanf("%f %f", &a, &b) == 2)
printf("%f\n", compute(a,b));
return 0;
}
float compute(float a, float b)
{
return (a - b) / (a * b);
}
10、编写一个程序,要求用户输入一个上限整数和一个下限整数,计算从上限到下限范围内所有整数的平方和,并显示计算结果。然后程序继续提示用户输入上限和下限整数,并显示结果,直到用户输入的上限整数小于下限整数为止。程序的运行示例如下:
Enter lower and upper integer limits: 5 9
The sums of the squares form 25 to 81 is 255
Enter next set of limits: ** 3 25**
The sums of the squares form 9 to 625 is 5520
Enter next set of linits: ** 5 5**
Done
答案:
#include <stdio.h>
int main(void)
{
int start, end, sum;
printf("Enter lower and upper integer limits:");
while(scanf("%d %d", &start, &end) == 2 && start < end)
{
sum = 0;
for(int i = start; i <= end; i++)
{
sum += i * i;
}
printf("The sums of the squares form %d to %d is %d\n", start * start, end * end, sum);
printf("Enter next set of limits:");
}
printf("Done\n");
return 0;
}
11、编写一个程序,在数组中读入 8 个整数,然后按倒序打印这 8 个整数。
答案:
#include <stdio.h>
int main(void)
{
int size = 8;
int it[8];
for(int i = 0; i < size; i++)
{
scanf("%d", &it[i]);
}
for(int i = size - 1; i >= 0; i--)
{
printf("%2d", it[i]);
}
return 0;
}
12、考虑下面两个无限序列:
1.0 + 1.0 / 2.0 + 1.0 / 3.0 + 1.0 / 4.0 + …
1.0 - 1.0 / 2.0 + 1.0 / 3.0 - 1.0 / 4.0 + …
编写一个程序计算这两个无限序列的总和,直到到达某次数。提示:奇数个 -1 相乘得 -1,偶数个 -1 相乘得 1。让用户交互地输入指定的次数,当用户输入 0 或负值时结束输入。查看运行 100 项、1000 项、10000项后的总和,是否发现每个序列都收敛于某值?
答案:
#include <stdio.h>
int main(void)
{
printf("100 times\n");
float sum1 = 0;
float sum2 = 0;
for(float i = 1.0; i < 101; i++)
{
sum1 += (1.0 / i);
if((int)i % 2 == 0)
{
sum2 -= (1.0 /i);
}
else
{
sum2 += (1.0 / i);
}
}
printf("%f\n",sum1);
printf("%f\n",sum2);
printf("1000 times\n");
float sum3 = 0;
float sum4 = 0;
for(float i = 1.0; i < 1001; i++)
{
sum3 += (1.0 / i);
if((int)i % 2 == 0)
{
sum4 -= (1.0 /i);
}
else
{
sum4 += (1.0 / i);
}
}
printf("%f\n",sum3);
printf("%f\n",sum4);
printf("10000 times\n");
float sum5 = 0;
float sum6 = 0;
for(float i = 1.0; i < 10001; i++)
{
sum5 += (1.0 / i);
if((int)i % 2 == 0)
{
sum6 -= (1.0 /i);
}
else
{
sum6 += (1.0 / i);
}
}
printf("%f\n",sum5);
printf("%f\n",sum6);
return 0;
}
13、编写一个程序,创建一个包含 8 个元素的 int 类型数组,分别把数组元素设置为 2 的前 8 次幂。使用 for 循环设置数组元素的值,使用 do while 循环显示数组元素的值。
答案:
#include <stdio.h>
int power(int count);
int main(void)
{
int ar[8];
for(int i = 1; i < 9; i++)
{
ar[i - 1] = power(i);
}
int i = 0;
do
{
printf("%4d", ar[i]);
i++;
}while(i < 8);
printf("\n");
return 0;
}
int power(int count)
{
int sum = 2;
int base = 2;
for(int i = 1; i < count; i++)
{
sum *= 2;
}
return sum;
}
14、编写一个程序,创建两个包含 8 个元素的 double 类型数组,使用循环提示用户为第一个数组输入 8 个值。第二个数组元素的值设置为第一个数组对应元素的积累之和。例如,第二个数组的第 4 个元素的值是第一个数组前 4 个元素之和,第二个数组的第 5 个元素的值是第一个数组前 5 个元素之和(用嵌套循环可以完成,但是利用第二个数组的第 5 个元素是第二个数组的第 4 个元素与第一个数组的第 5 个元素之和,只用一个循环就能完成任务,不需要使用嵌套循环)。最后,使用循环显示两个数组的内容,第一个数组显示成一行,第二个数组显示在第一个数组的下一行,而且每个元素都与第一个数组各元素相对应。
答案:
#include <stdio.h>
int main(void)
{
double ar1[8];
double ar2[8];
for(int i = 0; i < 8; i++)
{
printf("Please input integer\n");
scanf("%lf", &ar1[i]);
}
int sum = 0;
for(int i = 0; i < 8; i++)
{
sum += ar1[i];
ar2[i] = sum;
}
for(int i = 0; i < 8; i++)
{
printf("%10.2lf", ar1[i]);
}
printf("\n");
for(int i = 0; i < 8; i++)
{
printf("%10.2lf", ar2[i]);
}
printf("\n");
return 0;
}
15、编写一个程序,读取一行输入,然后把输入的内容倒序打印出来。可以把输入储存在 char 类型的数组中,假设每行字符不超过 255。回忆一下,根据 %c 转换说明,scanf() 函数一次只能从输入中读取一个字符,而且在用户按下 Enter 键时 scanf() 函数会生成一个换行字符(\n)。
答案:
#include <stdio.h>
#include <string.h>
int main(void)
{
char ch[255];
printf("please input a line words!\n");
scanf("%s",ch);
for(int i = strlen(ch) - 1; i >= 0; i--)
{
printf("%c", ch[i]);
}
printf("\n");
return 0;
}
16、Daphne 以 10% 的单利息投资了 100 美元(也就是说,每年投资获利相当于原始投资的 10%)。Deirdre 以 5% 的复合利息投资了 100 美元(也就是说,利息是当前余额的 5%,包含之前的利息)。编写一个程序,计算需要多少年 Deirdre 的投资额才会超过 Daphne,并显示那时两人的投资额。
答案:
#include <stdio.h>
int main(void)
{
float daphneMoney = 100;
float daphneInterest = 0.1;
float deirdreMoney = 100;
float deirdreInterest = 0.05;
int years = 1;
do
{
daphneMoney += 100 * daphneInterest;
deirdreMoney = deirdreMoney + deirdreMoney * deirdreInterest;
years++;
}while(daphneMoney > deirdreMoney);
printf("need %d years Deirdre's money more than Daphne, Deirdre's money is %0.2f, Daphne's money is %0.2f\n", years, deirdreMoney, daphneMoney);
return 0;
}
17、Chuckie Lucky 赢得了 100 万美元(税后),他把奖金存入年利率 8% 的账户。在每年的最后一天。Chuckie 取出 10万美元。编写一个程序,计算多少年后 Chuckie 会取完账户的钱?
答案:
#include <stdio.h>
int main(void)
{
float money = 100;
int years = 1;
do
{
money += (money * 0.08);
money -= 10;
years++;
}while(money > 0.0);
printf("after %d years Chuckie doesn't have any money %f", years, money);
return 0;
}
18、Rabnud 博士加入了一个社交圈。起初他有 5 个朋友。他注意到他的朋友数量以下面的方式增长。第 1 周少了 1 个朋友,剩下的朋友数量翻倍;第 2 周少了 2 个朋友,剩下的朋友数量翻倍。一般而言,第 N 周少了 N 个朋友,剩下的朋友数量翻倍。编写一个程序,计算并显示 Rabnud 博士每周的朋友数量。该程序一直运行,直到超过邓巴数(Dunbar’s number)。邓巴数是粗略估算一个人在社交圈中有稳定关系的成员的最大值,该值大约是 150。
答案:
#include <stdio.h>
int main(void)
{
int friends = 5;
int weeks = 1;
do
{
friends = (friends - weeks) * (friends - weeks);
weeks++;
printf("%d week Rabnud has %d friends\n", weeks, friends);
}while(friends < 150);
return 0;
}