C 语言中的递增和递减运算符
原文:https://overiq.com/c-programming-101/increment-and-decrement-operators-in-c/
最后更新于 2020 年 7 月 27 日
c 有两个特殊的一元运算符,分别叫做增量(++
)和减量(--
)运算符。这些运算符通过1
增加和减少变量值。
++x
同x = x + 1
或x += 1
--x
同x = x - 1
或x -= 1
递增和递减运算符只能用于变量。它们不能与常量或表达式一起使用。
int x = 1, y = 1;
++x; // valid
++5; // invalid - increment operator operating on a constant value
++(x+y); // invalid - increment operating on an expression
递增/递减运算符有两种类型:
- 前缀递增/递减运算符。
- 后缀递增/递减运算符。
让我们从第一个开始。
前缀递增/递减运算符
前缀递增/递减运算符会立即增加或减少变量的当前值。然后在表达式中使用该值。让我们举个例子:
y = ++x;
这里首先x
的当前值增加1
。x
的新值被分配给y
。同样,在声明中:
y = --x;
x
的当前值递减1
。x
的新值被分配给y
。
以下程序演示了前缀递增/递减运算符的作用:
#include<stdio.h>
int main()
{
int x = 12, y = 1;
printf("Initial value of x = %d\n", x); // print the initial value of x
printf("Initial value of y = %d\n\n", y); // print the initial value of y
y = ++x; // increment the value of x by 1 then assign this new value to y
printf("After incrementing by 1: x = %d\n", x);
printf("y = %d\n\n", y);
y = --x; // decrement the value of x by 1 then assign this new value to y
printf("After decrementing by 1: x = %d\n", x);
printf("y = %d\n\n", y);
// Signal to operating system everything works fine
return 0;
}
预期输出:
Initial value of x = 12
Initial value of y = 1
After incrementing by 1: x = 13
y = 13
After decrementing by 1: x = 12
y = 12
后缀递增/递减运算符
后缀递增/递减运算符使变量的当前值在表达式中使用,然后该值递增或递减。例如:
y = x++;
这里首先将x
的当前值赋给y
,然后x
递增。
同样,在声明中:
y = x--;
x
的当前值分配给y
,然后x
递减。
以下程序演示了后缀递增/递减运算符的作用:
#include<stdio.h>
int main()
{
int x = 12, y = 1;
printf("Initial value of x = %d\n", x); // print the initial value of x
printf("Initial value of y = %d\n\n", y); // print the initial value of y
y = x++; // use the current value of x then increment it by 1
printf("After incrementing by 1: x = %d\n", x);
printf("y = %d\n\n", y);
y = x--; // use the current value of x then decrement it by 1
printf("After decrementing by 1: x = %d\n", x);
printf("y = %d\n\n", y);
// Signal to operating system everything works fine
return 0;
}
预期输出:
Initial value of x = 12
Initial value of y = 1
After incrementing by 1: x = 13
y = 12
After decrementing by 1: x = 12
y = 13
优先
递增和递减运算符的优先级高于我们到目前为止讨论过的运算符(唯一的例外是括号)。此外,后缀递增/递减运算符的优先级高于前缀递增/递减运算符。
下表列出了我们到目前为止讨论过的运算符的优先级和关联性:
经营者 | 描述 | 结合性 |
---|---|---|
() |
圆括号 | 从左到右 |
++ 、-- |
后缀递增运算符、后缀递减运算符 | 从左到右 |
++ 、-- 、+ 、- |
前缀递增运算符、前缀递减运算符、一元加号、一元减号 | 从右向左 |
* 、/ 、% |
乘法、除法和模数 | 从左到右 |
+ 、- |
加法和减法 | 从左到右 |
= 、+= 、-= 、*= 、/= 、%= |
赋值运算符和复合赋值运算符 | 从右向左 |
我们取一些表达式,在运算符优先的基础上求解。
例 1 :
int x, y, z;
x = 5;
y = 8;
z = ++x + y++;
解决方案:
第一步:评估y++
。由于++
是后缀,y
的当前值将用于表达式中,然后递增。
z = ++x + 8;
第二步:评估++x
。由于++
是前缀,x
的值将立即递增。
z = 6 + 8;
第三步:评估6 + 8
。
z = 14;
例 2 :
int a, b, c;
a = 10;
b = 20;
c = 1;
c += a++ * 5 - --b;
解决方案:
第一步:评估a++
。由于++
是后缀,a
的当前值将用于表达式中,然后递增。表达式现在变成:
c += 10 * 5 - --b;
第二步:评估--b
。由于--
是前缀,b
的值将立即递减。表达式现在变成:
c += 10 * 5 - 19;
第三步:评估10 * 5
。
c += 50 - 19;
第四步:评估50 - 19
。
c += 31;
第五步:评估+=
。
c = 32;
C 语言中的关系运算符
原文:https://overiq.com/c-programming-101/relational-operators-in-c/
最后更新于 2020 年 7 月 27 日
关系运算符用于比较两个表达式的值。关系运算符是二进制运算符,因为它们需要两个操作数来操作。包含关系运算符的表达式称为关系表达式。如果关系为真,则关系表达式的结果为1
,如果关系为假,则关系表达式的结果为0
。
下表列出了关系运算符以及一些示例:
操作员 | 描述 | 例子 | 结果 |
---|---|---|---|
> |
大于 | 1 > 2 |
0 |
>= |
大于或等于 | 3 >= 2 |
1 |
< |
小于 | 10 < 5 |
0 |
<= |
小于或等于 | 6 <= 7 |
1 |
== |
等于 | 98==98 |
1 |
!= |
不等于 | 10 != 9 |
1 |
在 C 中,所有非零值被认为是真,而0
被认为是假。以下程序演示了关系运算符的作用:
#include<stdio.h>
int main()
{
int x = 12, y = 13;
printf("x = %d\n", x);
printf("y = %d\n\n", y);
// Is x is greater than y?
printf("x > y : %d\n", x > y);
// Is x is greater than or equal to y?
printf("x >= y : %d\n", x >= y);
// Is x is smaller than y?
printf("x < y : %d\n", x < y);
// Is x is smaller than or equal to y?
printf("x <= y : %d\n", x <= y);
// Is x is equal to y?
printf("x == y : %d\n", x == y);
// Is x is not equal to y?
printf("x != y : %d\n", x != y);
// Signal to operating system everything works fine
return 0;
}
预期输出:
x = 12
y = 13
x > y : 0
x >= y : 0
x < y : 1
x <= y : 1
x == y : 0
x != y : 1
优先
<
、<=
、>
和>=
操作符的优先级相同,从左到右关联。然而,==
和!=
的优先级比其他关系运算符低,它们从左到右关联。关系运算符的优先级低于算术运算符。
为了清楚起见,让我们评估一些涉及关系运算符的表达式:
例 1 :
4 + 2 * 3 > 12 - 2
第一步:评估2 * 3
。
4 + 6 > 12 - 2
第二步:评估4 + 6
,然后是12 - 2
。
10 > 10
第三步:10
不大于10
,所以上面的表达式计算为假(0
)。因此整个表达式的结果是0
。
结果:
4 + 2 * 3 > 12 - 2 => 0
例 2 :
(4 % 2 == 0) <= (8 * 2)
步骤 1:括号操作符具有最高的优先级,它从左向右关联。所以表达式(4 % 2 == 0)
将首先被求值。%
运算符的优先级高于等于==
运算符。因此,首先应用%
运算符,然后应用==
运算符。表达式现在变成:
(4 % 2 == 0) <= (8 * 2)
=> (0 == 0) <= (8 * 2)
=> 1 <= (8 * 2)
第二步:评估(8 * 2)
。
1 <= (8 * 2)
=> 1 <= 16
第三步:1
小于16
。所以上面的表达式评估为真(1
)。因此整个表达式的结果是真的。
结果:
(4 % 2 == 0) <= (8 * 2) => 0
不要将赋值运算符(=
)与等于运算符(==
)混淆。第一个用于给变量赋值,第二个用于测试两个值是否相等。
要充分利用关系运算符,您必须学习如何使用 if-else 语句。if-else 语句在 If… else 语句 C 章节中详细讨论。
C 语言中的逻辑运算符
原文:https://overiq.com/c-programming-101/logical-operators-in-c/
最后更新于 2020 年 7 月 27 日
逻辑运算符用于计算两个或多个条件。一般来说,逻辑运算符用于组合关系表达式,但它们不仅限于关系表达式,您可以使用任何类型的表达式,甚至常量。如果逻辑运算符的结果为真,则返回1
,否则返回0
。
逻辑运算符有三种类型:
操作员 | 意义 |
---|---|
&& |
逻辑积算符 |
|| |
或运算符 |
! |
“非”算符 |
AND ( &&
)和 OR ( ||
)是二元运算符,而 NOT ( !
)是一元运算符。
在我们开始解释&&
运算符之前,请记住-在 C 中,所有非零值都被认为是真(1
),而0
被认为是假。
AND (&&)运算符
如果两个操作数都为真,该运算符给出真(即1
)的净结果,否则为假(即0
)。
操作数 1 | 操作数 2 | 结果 |
---|---|---|
真实的 | 真实的 | 真实的 |
真实的 | 错误的 | 错误的 |
错误的 | 真实的 | 错误的 |
错误的 | 错误的 | 错误的 |
让我们举个例子:
int a = 12, b = 3;
假设我们有以下逻辑表达式:
(a==12) && (b<5)
在上面的表达式中,条件a == 12
和b < 5
都为真,因此整个表达式为真。因此,整个逻辑表达式的价值是1
。
为了可读性,上面的表达式添加了括号。它不会以任何方式改变操作顺序。所以这个表达:
(a<12) && (b<5)
相当于:
a < 12 && b < 5
当然,前者比后者可读性更强。
再考虑一些例子:
表示 | 中间表达 | 结果 |
---|---|---|
(a==4) && (b==2) |
false && false = > false |
0 |
(a>100) && (b<10) |
false && true = > false |
0 |
a && b |
true && true = > true |
1 |
a && 0 |
true && false = > false |
0 |
特别注意最后两个例子,如上所述,逻辑表达式中的操作数可以是任何表达式、变量或常量。
这是&&
符最重要的一点。
在&&
(与)运算符中,如果第一个操作数的计算结果为假,则第二个操作数根本不会计算。
考虑以下示例:
int a = 12;
(a==11) && (a++);
上式中a==11
为假,所以右操作数a++
根本不求值。以下程序演示了这一概念:
#include<stdio.h>
int main()
{
int a = 12, result;
printf("Initial value of a = %d\n", a);
// result of the logical expression is stored in result
result = (a==11) && (a++);
printf("Final value of a = %d\n", a);
printf("Result of logical expression = %d\n", result);
// Signal to operating system everything works fine
return 0;
}
预期输出:
Initial value of a = 12
Final value of a = 12
Result of logical expression = 0
如果条件a==11
为真,那么a
的值就会增加1
。
或(||)运算符
如果至少有一个操作数为真,该运算符给出真(即1
)的最终结果,否则为假。
操作数 1 | 操作数 2 | 结果 |
---|---|---|
真实的 | 真实的 | 真实的 |
真实的 | 错误的 | 真实的 |
错误的 | 真实的 | 真实的 |
错误的 | 错误的 | 错误的 |
让我们举个例子:
int a = 10, b = 9;
假设我们有以下逻辑表达式:
(a<12) || (b<5)
上式中a < 12
为真,b < 5
为假。因此整个表达式评估为真,逻辑表达式的值为1
。
再考虑一些例子:
表示 | 中间表达 | 结果 |
---|---|---|
(a==4) || (b==2) |
false || false = >假 |
0 |
(a>10) || (b<10) |
false || true = >真 |
1 |
a || b |
true || true = >真 |
1 |
a || 12.12 |
true || true = >真 |
1 |
请注意,上面两个表达式中使用了括号来提高可读性,当然表达式(a==4) && (b==2)
比a==4 && b==2
更易读。
请注意,在最后一条语句中,第二个操作数的类型是 double,这是完全可以接受的。
OR( ||
)运算符最重要的一点是,如果第一个操作数的计算结果为真,那么第二个操作数就不会被计算。考虑以下示例:
int a = 10;
(a==10) || (a--);
上式中a==10
为真,故表达式a--
不求值,整体表达式的结果为1
。以下程序演示了这一概念:
#include<stdio.h>
int main()
{
int a = 10, result;
printf("Initial value of a = %d\n", a);
// result of the logical expression is stored in result
result = (a==10) || (a--);
printf("Final value of a = %d\n", a);
printf("Result of logical expression = %d\n", result);
// Signal to operating system everything works fine
return 0;
}
预期输出:
Initial value of a = 10
Final value of a = 10
Result of logical expression = 1
如果条件a==10
为假,则 a 的值将减少1
。
!(非)操作员
!
(非)运算符否定条件的值。如果条件是假的,那么它就变成真的,如果它是真的,那么它就变成假的。与&&
(与)和||
(或)运算符不同,!
(非)运算符是一元运算符。
操作数 | 结果 |
---|---|
真实的 | 错误的 |
错误的 | 真实的 |
让我们举个例子:
int a = 10, b = 9;
假设我们有以下逻辑表达式。
!(a > 5)
我们可以看到,条件a > 5
是真的。而!
(NOT)运算符否定条件的值,所以整体表达式的结果为假,即0
。
以下是更多的例子:
表示 | 中间表达 | 结果 |
---|---|---|
!(a==4) |
!false = > true |
1 |
!(a || b) |
!true = > false |
0 |
!(a && b) |
!true = > false |
0 |
!(a > b) |
!true = > false |
0 |
**注意:**要充分发挥关系和逻辑的潜力,必须首先掌握 if-else 语句和循环。如果-否则语句和循环分别在和章节中详细讨论。
以下程序演示了非(!
)运算符的作用:
#include<stdio.h>
int main()
{
int a = 100, result;
printf("Initial value of a = %d\n", a);
// result of the logical expression is stored in result
result = (a>10);
printf("Is a > 10 : %d\n", result);
printf("After applying not operator\n");
printf("Is a > 10 : %d\n", !result);
// Signal to operating system everything works fine
return 0;
}
预期输出:
Initial value of a = 100
Is a > 10 : 1
After applying not operator
Is a > 10 : 0
优先
在逻辑运算符中,NOT ( !
)运算符的优先级最高,它从右向左关联。“与”(&&
)运算符的优先级高于“或”(||
)运算符,它们都从左向右关联(参见完整的优先级表)。
现在让我们解决一些涉及逻辑运算符的表达式。例 1 :
int age = 10, height = 45;
(age < 12 && height < 48) || (age > 65 && height > 72);
解决方案:这种情况下,运算符的求值顺序为圆括号(()
)、关系运算符(<
、>
)、AND ( &&
)运算符、OR ( ||
)运算符。
(age < 12 && height < 48) || (age > 65 && height > 72)
=> (10 < 12 && 45 < 48) || (10 > 65 && 45 > 72)
=> (1 && 1) || (10 > 65 && 45 > 72)
=> 1 || (10 > 65 && 45 > 72)
=> 1 || (0 && 0)
=> 1 || 0
=> 1
例 2 :
int year = 2000;
(year % 4 == 0 && year % 100 != 0 ) || (year % 400 == 0);
解决方案:在这种情况下,运算符的求值顺序将是圆括号(()
)、模除法(%
)、关系运算符(==
、!=
)和(&&
)运算符,或者(||
)运算符。
(year % 4 == 0 && year % 100 != 0 ) || (year % 400 == 0)
=> (2000 % 4 == 0 && 2000 % 100 != 0 ) || (2000 % 400 == 0)
=> (0 == 0 && 2000 % 100 != 0 ) || (2000 % 400 == 0)
=> (0 == 0 && 0 != 0 ) || (2000 % 400 == 0)
=> (1 && 0 != 0 ) || (2000 % 400 == 0)
=> (1 && 0 ) || (2000 % 400 == 0)
=> 0 || (2000 % 400 == 0)
=> 0 || (0 == 0)
=> 0 || 1
=> 1
C 语言中的条件运算符、逗号运算符和sizeof()
运算符
原文:https://overiq.com/c-programming-101/conditional-operator-comma-operator-and-sizeof-operator-in-c/
最后更新于 2020 年 7 月 27 日
条件运算符
条件运算符(?
、:
)是一种特殊的运算符,需要三个操作数。它的语法如下:
语法: expression1 ? expression2 : expression3
下面是条件运算符的工作原理。
第一个expression1
被求值,如果它是真的,那么expression2
的值成为整个表达式的结果。另一方面,如果expression1
为假,那么expression3
的值就成为整体表达式的结果。
让我们举个例子:
int a = 5, b = 3;
a > b ? a : b
在上式中,a>b
为真,因此变量a
的值成为整体条件表达式的结果。
由于a > b ? a : b
是一个表达式,我们可以将其值赋给一个变量。
max = a > b ? a : b
条件运算符有时也称为三元运算符。
下面的程序演示了如何使用条件运算符找到两个数字中最大的一个
#include<stdio.h>
int main()
{
int a, b, max;
printf("Enter a and b: ");
scanf("%d%d", &a, &b);
max = a > b ? a : b;
printf("Largest of the two numbers = %d\n", max);
// Signal to operating system everything works fine
return 0;
}
预期输出:
Enter a and b: 1993 1534
Largest of the two numbers = 1993
条件运算符的优先级远远低于算术、逻辑和关系运算符。但它比赋值和复合赋值运算符更高。条件运算符的结合性是从右向左的(参见 C 中的运算符优先级)。
考虑以下条件表达式:
x ? y : a ? b : c
在这种情况下,expression3
本身就是一个条件表达式。此外,由于条件运算符从右向左关联,因此上述表达式相当于:
x ? y : (a ? b : c)
如果x
的值为真(即非零),则整个表达式的值为y
。否则,整个表达式的值将是(a ? b : c)
。
逗点算符
逗号运算符允许我们在 C 语法只允许一个表达式的地方放置一个或多个表达式。每个表达式必须用逗号(,
)隔开,并从左到右计算。最右边表达式的值成为整个表达式的值。举个例子就能说明一切。
a=2, a++, a+10
这里我们结合了三个表达式,让我们看看它是如何工作的。首先2
被分配给变量a
,然后a
的值增加1
。最后对a+10
进行了评价。所以整体表达的价值是13
。
我们再举一个例子。
sum = (a=3, b=4, c=5, a+b+c);
这里首先将3
赋给变量a
,然后将4
赋给变量b
,5
赋给变量c
。最后a+b+c
被求值,并且整个表达式的结果(即最右边的表达式)被分配给sum
。
逗号运算符(,
)的优先级最低,从左向右关联(参见中的运算符优先级和关联性)。因此,上面表达式中的括号是必要的,否则,变量sum
将被赋予一个值3
。
逗号运算符(,
)帮助我们使代码更加简洁。如果不使用逗号运算符,上述任务至少需要 2 条语句。
a=3, b=4, c=5;
sum = a+b+c;
以下程序演示了逗号运算符(,
)的作用:
#include<stdio.h>
int main()
{
int a, b, c, sum;
sum = (a=3, b=4, c=5, a+b+c);
printf("Sum = %d\n", sum);
// Signal to operating system everything works fine
return 0;
}
预期输出:
Sum = 12
操作符的大小
sizeof
是一元运算符,用于确定其操作数的大小。sizeof
运算符的一般形式是:
sizeof(object)
其中对象可以是数据类型关键字,如int
、float
、double
或表达式或变量。
例如,sizeof(int)
给出了一个int
数据类型所占的大小。sizeof
运算符以字节为单位返回大小。
下面的程序演示了如何使用sizeof()
操作符检查系统中基本类型的大小。
#include<stdio.h>
int main()
{
printf("Size of short = %lu\n", sizeof(short));
printf("Size of int = %lu\n", sizeof(int));
printf("Size of unsigned int = %lu\n", sizeof(unsigned int));
printf("Size of char = %lu\n", sizeof(char));
printf("Size of float = %lu\n", sizeof(float));
printf("Size of double = %lu\n", sizeof(double));
printf("Size of long double = %lu\n", sizeof(long double));
// Signal to operating system everything works fine
return 0;
}
预期输出:
Size of short = 2
Size of int = 4
Size of unsigned int = 4
Size of char = 1
Size of float = 4
Size of double = 8
Size of long double = 16
因为 C 在存储需求方面相当灵活。上述程序的输出可能因您的机器而异。
sizeof
运算符的优先级与前缀递增/递减运算符相同,从右向左关联(参见中的运算符优先级和关联性)。
C 语言中的隐式类型转换
原文:https://overiq.com/c-programming-101/implicit-type-conversion-in-c/
最后更新于 2020 年 7 月 27 日
c 允许我们在表达式中混合基本类型。在 C 的算术运算符一章中讨论混合模式算术时,我们已经看到了这种行为的一瞥。在这样的表达式中,一种类型的操作数被转换成另一种类型。这个过程称为类型转换。
有两种类型的类型转换:
- 隐式类型转换。
- 显式类型转换。
在本章中,我们将讨论隐式类型转换。
隐式类型转换
这种类型的转换由编译器根据以下规则完成:
- 如果一个操作数是类型
long double
,那么另一个操作数将被转换为long double
,然后运算的结果将是一个long double
。 - 否则,如果一个操作数的类型为
double
,那么另一个操作数将被转换为double
,运算结果将是double
。 - 否则,如果一个操作数的类型为
float
,那么另一个操作数将被转换为float
,运算结果将是float
。 - 否则,如果一个操作数的类型为
unsigned long int
,那么另一个操作数将被转换为unsigned long int
,运算结果将是unsigned long int
。 - 否则,如果一个操作数的类型为
long int
,另一个操作数的类型为unsigned int
,则有两种可能:- 如果
long int
可以表示一个unsigned int
的所有值,那么类型unsigned int
的操作数将被转换为long int
,结果将是一个long int
。 - 否则,如果
long int
不能代表一个unsigned int
的所有值,则两个操作数的操作数都转换为unsigned long int
,结果为unsigned long int
。
- 如果
- 否则,如果一个操作数的类型为
long int
,那么另一个操作数将被转换为long int
,运算结果将是long int
。 - 否则,如果一个操作数的类型为
unsigned int
,那么另一个操作数将被转换为unsigned int
,运算结果将是unsigned int
。 - 否则,如果一个操作数的类型为
int
,那么另一个操作数将被转换为int
,运算结果将是int
。
我们举几个例子把事情说清楚。
例 1:
int a = 100;
double b = 12.5;
a + b;
这里一个操作数是类型int
,另一个是类型double
。因此根据规则 3,变量a
将被转换为double
,整体运算的结果将是一个double
,即112.500000
。
例 2:
char ch = 'a';
int a = 10;
a + c;
根据规则 8,在任何操作之前,char
将被转换为int
,并且整体操作的结果将是int
。因为ch
的整数值是97
(即字符'a'
的 ASCII 值)。因此,97 + 10 = 107
。
例 3:
char ch = 'A';
unsigned int a = 10;
a * b;
这里根据规则 7,类型为char
的变量ch
将首先转换为unsigned int
,即65
(ASCII 值为'A'
,然后进行加法运算,整体运算结果为unsigned int
。因此,65 + 10 = 75
。
下面是更多的例子:
char ch;
short int si;
int i;
unsigned int ui;
float f;
long double ld;
i = ch + si; // both ch and si will be converted to int before addition - rule 8
i = si + i; // si will be converted to int before addition - rule 8
ui = i + ui; // i will be converted to unsigned int before addition - rule 7
f = ui + f; // ui will be converted to float before addition - rule 3
ld = f + ld; // f will be converted to long double before addition - rule 1
通过给每种类型分配一个等级,可以简化上述所有规则。以下是它的工作原理。
每当表达式中涉及两个不同数据类型的操作数时,较低等级的操作数将被转换为较高等级的数据类型。这个过程叫做型的提升。
注:为简单起见,图中省略了规则 5。
分配中的类型转换
如果赋值表达式中的操作数类型不同,那么右边的操作数将根据以下规则转换为左边的操作数类型。
-
如果右侧操作数的等级较低,则它将被提升到左侧操作数的等级。这里有一个例子:
int i = 'z';
这里右操作数
'z'
是类型char
,右操作数是类型int
。根据规则——较低等级的操作数(在本例中为char
)将被提升到较高等级(在本例中为int
)。所以赋值前'z'
即122
(ASCII 值)会提升到int
再赋值到i
。 -
否则,如果右侧操作数的等级较高,则它将被降级为左侧操作数的等级。例如:
float a = 120.33;
回想一下,默认情况下浮点常量的类型是
double
。在这种情况下,右侧操作数即120.33
为double
类型,左侧操作数为float
类型。因此在赋值操作之前120.33
将被降级为float
类型,然后赋值将会发生。
赋值中类型转换的一些结果是:
-
当
long int
转换为int
或int
转换为short int
或int
转换为char
时,高阶位可能会丢失。让我们举个例子来清楚地理解这一点。假设我们有以下陈述:unsigned char ch = 257;
这里我们试图将
257
(int
类型)分配给一个char
变量。根据类型转换规则 2:如果右手操作数的等级较高,那么它将被降级为左手操作数的等级。但是有一个问题,回想一下unsigned char
型只能取0
到255
的数值。Cleary,257
超出变量ch
的范围。在这种情况下,从范围的另一侧拾取适当的值并存储在ch
中。所以最终存储在ch
变量中的是一个带有 ASCII 值2
的笑脸字符。 -
从浮点类型(如
double
、float
)转换为int
类型时,小数部分将被截断。 -
当
double
类型转换为float
类型时,数字四舍五入。 -
当
int
转换为float
或float
转换为double
时,精度没有增加。 -
当
signed
类型变为unsigned
类型时,标志可能会掉落。
下面的示例演示了如何进行类型转换。
#include<stdio.h>
int main()
{
float f_val1 = 97.12, f_val2;
int i_val1, i_val2;
char ch_val1, ch_val2;
// float is demoted to int, only 97 is assigned to i_val1
i_val1 = f_val1;
// int is demoted to char,
ch_val1 = i_val1;
// float is demoted to int, only 12 is assigned to i_val2
i_val2 = 12.45f;
// char is promoted to int, now
// i_val1 contains ASCII value of character 'e' i.e 101
i_val2 = 'e';
/*
double is demoted to float, since by
default floating point constants
are of type double
*/
f_val2 = 12.34;
// Print the value of i
printf("Value of i_val1 = %d\n", i_val1);
// Print the character corresponding to ASCII value 97
printf("Value of ch_val1 = %c\n", ch_val1);
// Print the ASCII value of character 'e'
printf("Value of i_val2 = %d\n", i_val2);
// Print f_val2 with 2 digits of precision
printf("Value of f_val2 = %.2f\n", f_val2);
// Signal to operating system everything works fine
return 0;
}
预期输出:
Value of i_val1 = 97
Value of ch_val1 = a
Value of i_val2 = 101
Value of f_val2 = 12.34
C 语言中的显式类型转换
原文:https://overiq.com/c-programming-101/explicit-type-conversion-in-c/
最后更新于 2020 年 7 月 27 日
上一章讨论的隐式类型转换是由编译器自动完成的。在某些情况下,我们可能希望对转换如何发生有更多的控制。举个例子吧。
float f;
int a = 20, b = 3;
f = a/b
f
的值将是6.000000
而不是6.666666
,因为两个整数之间的运算会产生一个整数值。当然解决这个问题的一个方法是使用混合模式算法,并将a
或b
的类型更改为double
或float
。改变变量的类型并不总是可行的,当然也不是一个好的编程。在 c 中输入显式类型转换。
演职人员
强制转换运算符是一元运算符,用于将常量、变量或表达式临时转换为特定类型。强制转换运算符的语法是:
语法: (datatype)expression
其中datatype
指您希望表达式转换成的类型。所以如果我们把上面的陈述写成:
f = (float)a/b;
然后我们会得到正确的答案,即6.666666
。
以下是演职人员的工作方式。
首先,它将类型为int
的变量a
临时转换为类型为float
。我们已经知道float
和int
操作数之间的运算会产生float
结果,这就是为什么答案是6.666666
而不是6.000000
。
请注意,在上面的陈述中,cast 运算符仅适用于变量a
,而不适用于b
或a/b
。
另一个需要注意的要点是,变量a
的数据类型是float
,直到语句执行为止。之后,将被视为int
。
在我们离开这个话题之前,请考虑以下声明:
f = (float)(a/b);
你可能会认为这个说法和上一个(即f = (float)a/b;
)是一样的,但其实不是,这里是为什么。
这里首先对表达式a/b
进行求值,然后由于类型转换,其结果被转换为float
,并最终分配给f
。
以下程序演示了 cast 运算符的作用:
#include<stdio.h>
int main()
{
int a = 25, b = 13;
float result;
result = a/b;
// display only 2 digits after decimal point
printf("(Without typecasting) 25/13 = %.2f\n", result );
result = (float)a/b;
// display only 2 digits after decimal point
printf("(With typecasting) 25/13 = %.2f\n", result );
// signal to operating system everything works fine
return 0;
}
预期输出:
(Without typecasting) 25/13 = 1.00
(With typecasting) 25/13 = 1.92
C 语言中的控制语句
C 语言中的if-else
语句
原文:https://overiq.com/c-programming-101/if-else-statements-in-c/
最后更新于 2020 年 7 月 27 日
C 语言中的控制语句
到目前为止,在我们编写的所有程序中,语句按照它们出现的顺序依次执行。但是有时我们希望只有在某些条件为真时才执行语句。例如,如果银行余额超过七位数,购买一辆新车,否则续订公共汽车月票。为了做出这样的决定,C 提供了一种称为控制语句的工具。
控制语句用于改变程序的流程。它们用于指定语句的执行顺序。它们通常用于定义控制如何从程序的一部分转移到另一部分。
C 语言有以下控制语句:
- 如果…否则
- 转换
- 环
- 为
- 正在…
- 做…正在…
复合语句
复合语句是使用大括号({}
)组合在一起的语句块。在复合语句中,所有语句都是按顺序执行的。复合语句也称为块。它采用以下形式:
{
statement1;
statement2;
statement3;
...
statementn;
}
我们了解到所有语句都以分号(;
)结尾,但复合语句是这一规则的例外。另一个需要理解的重要事情是,复合语句在语法上等同于单个语句,这意味着我们可以将复合语句放在允许单个语句的地方。这意味着下面的代码完全有效。
#include<stdio.h>
int main()
{
int i = 100;
printf("A single statement\n");
{
// a compound statement
printf("A statement inside compound statement\n");
printf("Another statement inside compound statement\n");
}
// signal to operating system everything works fine
return 0;
}
预期输出:
A single statement
A statement inside compound statement
Another statement inside compound statement
如果语句
If 语句用于测试条件并采取两种可能的操作之一。if 语句的语法是:
语法:
if (condition)
{
// if block
statement1;
statement2;
}
条件可以是任何常量、变量、表达式、关系表达式、逻辑表达式等等。请记住,在 C 中,任何非零值都被认为是真,而0
被认为是假。
工作原理:
if 块内的语句(即statement1
和statement2
)只有在条件为真时才执行。如果为假,则跳过 If 块内部的语句。当条件为真时,当您想要执行多个语句时,大括号({}
)总是必需的。此外,请注意 if 块中的语句略有缩进。这样做是为了提高可读性,语法上不需要缩进。
如果您想在条件为真时只执行一条语句,那么可以省略大括号({}
)。通常,即使只有一条语句要执行,也不应该省略大括号。
if (condition)
statement1;
如果用户输入的数字是偶数,下面的程序将打印一条消息。
#include<stdio.h>
int main()
{
int n;
printf("Enter a number: ");
scanf("%d", &n);
if(n % 2 == 0)
{
printf("%d is even", n);
}
// signal to operating system everything works fine
return 0;
}
第一次运行:
运行程序并输入一个偶数,您将获得以下输出:
预期输出:
Enter a number: 46
46 is even
第二次运行:
再次运行程序,但这次输入一个奇数。
预期输出:
Enter a number: 21
这一次,条件(n % 2 == 0
)的计算结果为 false,因此 if 块中的语句被跳过。
哪种说法属于 if?
if (condition)
statement1;
statement2;
statement3;
如果条件为假,你能找到哪个语句将被省略吗?
如果 If 语句后面没有大括号({}
),那么只有下一个立即语句属于 if 语句。else 和 else-if 子句也是如此(else 和 else-if 子句将在本章后面讨论)。
因此,只有statement1
属于 if 语句。因此,如果条件为假,则仅省略statement1
。无论条件如何,statement2
和statement3
将始终被执行。以下示例说明了这一事实:
#include<stdio.h>
int main()
{
if(0)
printf("statement 1\n");
printf("statement 2\n");
printf("statement 3\n");
// signal to operating system everything works fine
return 0;
}
预期输出:
statement 2
statement 3
这里的条件是假的,这就是为什么只执行最后两个语句。这验证了第 6 行中的语句只属于 if 语句的事实。乍看之下,确定哪个语句属于 if 语句有点混乱,这就是为什么建议总是使用大括号({}
)来包装要用 if 语句执行的语句。
#include<stdio.h>
int main()
{
if(0)
{
printf("statement 1\n");
}
printf("statement 2\n");
printf("statement 3\n");
// signal to operating system prgram ran fine
return 0;
}
现在您可以清楚地看到,只有第一个语句属于 if 语句。
else 子句
else
子句允许我们为if
条件添加一个替代路径。只有当if
条件为假时,才会执行else
块下的语句。
语法:
if (condition)
{
// if block
statement1;
statement2;
}
else
{
// else block
statement3;
statement4;
}
通常,如果 else 块中只有一条语句,那么大括号({}
)可以省略。虽然,不推荐。
if (expression)
statement1;
else
statement2;
如前所述,缩进不是必需的,因此上面的代码也可以写成:
if (expression)
statement1;
else
statement2;
但是为什么要抹杀可读性呢?做一个好的程序员,总是缩进我们的代码。
现在,让我们在之前编写的程序中添加一个else
子句。
#include<stdio.h>
int main()
{
int n;
printf("Enter a number: ");
scanf("%d", &n);
if(n % 2 == 0)
{
printf("%d is even", n);
}
else
{
printf("%d is odd", n);
}
// signal to operating system everything program ran fine
return 0;
}
**第一次运行:**运行程序并输入一个偶数。
Enter a number: 44
44 is even
第二次运行:
再次运行程序,但这次输入一个奇数。
Enter a number: 91
91 is odd
再考虑一个例子。以下程序确定两个输入数字中较大的一个:
#include<stdio.h>
int main()
{
int a, b;
printf("Enter two numbers: ");
scanf("%d %d", &a, &b);
if(a > b)
{
printf("%d is greater than %d", a, b);
}
else
{
printf("%d is greater than %d", b, a);
}
// signal to operating system everything works fine
return 0;
}
预期输出:
第一次运行:
Enter two numbers: 344 200
344 is greater than 200
第二次运行:
Enter two numbers: 99 999
999 is greater than 99
嵌套 if… else
我们可以添加if
…else
声明在if
街区或else
街区内。这叫做【T4 的筑巢】…else
。语法:
if(condition1)
{
if(condition2)
{
statement1;
statement2;
}
else
{
statement3;
statement4;
}
}
else
{
if(condition3)
{
statement5;
statement6;
}
else
{
statement7;
statement8;
}
}
我们可以筑巢if
…else
陈述到任何深度。
工作原理:
首先检查condition1
,如果为真,则检查condition2
,如果为真,则执行if
块内的语句(第 4-7 行)。
否则,执行else
块(第 10-13 行)中的语句。否则,如果condition1
为假,则检查condition3
,如果为真,则执行第 19-22 行 if 块下的语句。否则,执行else
块(第 25-28 行)中的语句。
以下程序使用两个嵌套的 if-else 语句来确定三个数字中较大的一个:
#include<stdio.h>
int main()
{
int a, b, c, larger;
printf("Enter three numbers: ");
scanf("%d %d %d", &a, &b, &c);
if(a > b)
{
if(a > c)
{
larger = a;
}
else
{
larger = c;
}
}
else
{
if(b > c)
{
larger = b;
}
else
{
larger = c;
}
}
printf("Largest number is %d", larger);
// signal to operating system everything works fine
return 0;
}
预期输出:
第一次运行:
Enter three numbers: 12 35 54
Largest number is 54
第二次运行:
Enter three numbers: 77 23 871
Largest number is 871
匹配 if…其他部分
有时将 else 子句与if
语句联系起来会变得令人困惑。考虑以下示例:
if(a<10)
if (a % 2 ==0)
printf("a is even and less than 10\n");
else
printf("a is greater than 10");
哪个if
语句与else
块相关联?根据代码缩进的方式,您可能会认为else
属于第一个if
语句,但事实并非如此。编译器不会根据缩进将if
和else
语句关联起来,而是将 else 部分与最接近的不匹配的if
部分进行匹配。所以else
语句与第二个if
语句相关联。
使用牙套({}
)我们总能避免这样的并发症。
if(a < 10)
{
if (a % 2 ==0)
{
printf("a is even and less than 10\n");
}
else
{
printf("a is greater than 10");
}
}
现在一切都清楚了。
else if 子句
if-else
是一个双向语句,用于测试一个条件并采取两个可能的动作之一。如果我们要进行一系列测试呢?检查多个条件的一种方法是使用嵌套的if-else
语句。我们在本章前面已经看到了这种技术的一个例子。实现这一点的另一种方法是使用 else-if 子句。else-if 子句扩展了基本的 if-else 语句,并允许我们执行一系列测试。if-else 语句的更新语法如下所示:
if(condition1)
{
statement1;
}
else if(condition2)
{
statement2;
}
else if(condition3)
{
statement3;
}
...
else
{
statement4;
}
这里,逐一检查每个条件。一旦发现一个条件为真,则执行对应于该块的语句。if-else 语句的其余部分中的条件和语句被跳过,程序控制从if-else
语句中出来。如果所有条件都不成立,则执行else
块中的语句。
使用else-if
子句,我们可以以更紧凑的形式编写嵌套的if-else
语句。
让我们重写程序,使用 else-if 子句来确定这两个数字中最大的一个。
#include<stdio.h>
int main()
{
int a, b, c, larger;
printf("Enter three numbers: ");
scanf("%d %d %d", &a, &b, &c);
if(a > b && a > c)
{
larger = a;
}
else if(b > a && b > c)
{
larger = b;
}
else
{
larger = c;
}
printf("Largest number is %d", larger);
// signal to operating system everything works fine
return 0;
}
这个版本的程序在功能上等同于使用嵌套 if-else 语句的程序。但它避免了深缩进,使代码更易读。
C 语言中的while
循环
原文:https://overiq.com/c-programming-101/the-while-loop-in-c/
最后更新于 2020 年 7 月 27 日
循环用于重复执行语句或语句块。例如,假设我们想写一个程序打印"Hello"
5 次。实现这一点的一种方法是将下面的语句写 5 遍。
printf("hello\n");
但是如果我们想打印100
或1000
次呢。当然,把同样的语句写 100 次或 1000 次是疯狂的。使用循环我们可以很容易地解决这类问题。c 提供了三种类型的循环。
- while 循环
- 边循环边做
- for 循环
while 循环
语法:
while(condition)
{
// body of while loop
statement 1;
statement 2;
}
就像 if-else 语句一样,while 循环以一个条件开始。首先,评估condition
,如果为真,则执行 while 主体中的语句。在执行 while 循环的主体后,再次检查条件,如果条件仍然为真,则再次执行 while 主体中的语句。这个过程一直重复,直到condition
变为假。因此,你必须始终包含一个改变condition
价值的陈述,这样它最终会在某个时候变成假的。循环体的每次执行都被称为迭代。
以下程序使用 while 循环打印1
到100
之间的所有偶数:
例 1:
#include<stdio.h>
int main()
{
int i = 1;
// keep looping while i < 100
while(i < 100)
{
// if i is even
if(i % 2 == 0)
{
printf("%d ", i);
}
i++; // increment i by 1
}
// signal to operating system everything works fine
return 0;
}
预期输出:
2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50
52 54 56 58 60 62 64 66 68 70 72 74 76 78 80 82 84 86 88 90 92 94 96
98
工作原理:
在第 5 行,我们已经声明了一个变量i
,并将其初始化为1
。首先,检查条件(i < 100)
,如果是真的。控制在 while 循环的主体内传递。在循环体内部,如果条件(i % 2 == 0
)被检查,如果它为真,那么 if 块内部的语句被执行。然后使用表达式i++
增加i
的值。由于在 while 循环的主体中没有更多的语句可以执行,因此第一次迭代就完成了。再次检查条件(i < 100
),如果它仍然为真,则再次执行循环主体。只要i
的值小于100
,这个过程就会重复。当i
到达100
时,循环终止,控制脱离 while 循环。
再考虑一个例子:
例 2:
以下程序计算用户输入的数字的十进制位总和。
#include<stdio.h>
int main()
{
int n, num, sum = 0, remainder;
printf("Enter a number: ");
scanf("%d", &n);
num = n;
// keep looping while n > 0
while( n > 0 )
{
remainder = n % 10; // get the last digit of n
sum += remainder; // add the remainder to the sum
n /= 10; // remove the last digit from n
}
printf("Sum of digits of %d is %d", num, sum);
// signal to operating system everything works fine
return 0;
}
**预期输出:**第一次运行:
Enter a number: 222
Sum of digits of 222 is 6
第二次运行:
Enter a number: 456
Sum of digits of 456 is 15
工作原理:
假设用户输入了123
,那么下面是求位数之和的步骤。
第一次迭代
n = 123
第一步:
通过评估123 % 10
取出123
的最后一位数字,并将结果存储在变量remainder
中。
remainder = n % 10;
remainder = 123 % 10
remainder = 3
第二步:
将最后一步得到的数字加到变量sum
中。
sum += remainder
sum = sum + remainder
sum = 3
第三步:
现在不需要123
的最后一位数字了,通过评估123 / 10
去掉。
n /= 10
n = 123 / 10
n = 12
第二次迭代
n = 12
第一步:
remainder = n % 10;
remainder = 12 % 10
remainder = 2
第二步:
sum += remainder
sum = sum + remainder
sum = 3 + 2
sum = 5
第三步:
n /= 10
n = 12 / 10
n = 1
第三次迭代
n = 1
第一步:
remainder = n % 10;
remainder = 1 % 10
remainder = 1
第二步:
sum += remainder
sum = sum + remainder
sum = 5 + 1
sum = 6
第三步:
n /= 10
n = 1 / 10
n = 0
当n
到达0
时,while 条件变为假,并且控制脱离 while 循环。因此123
的十进制位总和为6
。
C 语言中的do-while
循环
原文:https://overiq.com/c-programming-101/the-do-while-loop-in-c/
最后更新于 2020 年 7 月 27 日
做…同时循环
语法:
do{
// body of do while loop
statement 1;
statement 2;
}while(condition);
在 do while 循环中,首先执行主体中的语句,然后检查条件。如果条件为真,则再次执行正文中的语句。这个过程一直重复,直到条件变为假。通常,如果 do while 循环的主体只包含一个语句,那么可以省略大括号({}
)。请注意,与 while 循环不同的是,在 do while 中,条件后会放置一个分号(;
)。
do while 循环与 while 循环有很大的不同,因为在 do while 循环中,即使条件为假,主体中的语句也至少执行一次。在 while 循环的情况下,首先检查条件,如果条件为真,则只执行循环体中的语句。
以下程序使用 do while 循环打印1
和100
之间的数字,它们是3
的倍数:
#include<stdio.h> // include the stdio.h
int main()
{
int i = 1; // declare and initialize i to 1
do
{
// check whether i is multiple of 3 not or not
if(i % 3 == 0)
{
printf("%d ", i); // print the value of i
}
i++; // increment i by 1
}while(i < 100); // stop the loop when i becomes greater than 100
// signal to operating system everything works fine
return 0;
}
预期输出:
3 6 9 12 15 18 21 24 27 30 33 36 39 42 45 48 51 54 57 60 63 66 69 72 7
5 78 81 84 87 90 93 96 99
工作原理:
在第 5 行,我们已经声明并初始化了变量i
。然后,控件进入 do while 循环的主体。在循环体内部,测试 if 条件(i%3==0)
,如果为真,则执行 if 块内部的语句。声明i++
将i
的值增加1
。最后,检查边做边条件(i<100)
。如果为真,则循环体内部的语句将再次执行。只要i
的值小于100
,这个过程就一直重复。
我应该在哪里使用 do while 循环?
大多数时候你会用 while 循环代替 do while。然而,在一些场景中,while loop 最适合。考虑以下问题。
假设你想创建一个程序来寻找一个数的阶乘。你可能知道阶乘只对0
和正数有效。这里有一种方法可以解决这个问题。
假设用户输入了一个负数,与其显示错误消息并退出程序,不如再次要求用户输入一个数字。你要一直问,直到用户输入一个正数或者0
。一旦输入正数或0
,计算阶乘并显示结果。
让我们看看如何使用 while 和 do while 循环来实现它。
使用 while 循环
#include<stdio.h> // include the stdio.h
int main()
{
int num;
char num_ok = 0;
// keep asking for numbers until num_ok == 0
while(num_ok==0)
{
printf("Enter a number: ");
scanf("%d", &num);
// if num >= 0 set num_ok = 1 and stop asking for input
if(num>=0)
{
num_ok = 1;
}
}
// calculate factorial
}
使用 do while 循环
#include<stdio.h> // include the stdio.h
int main()
{
int num;
do
{
printf("Enter a number: ");
scanf("%d", &num);
}while(num<0); // keep asking for numbers until num < 0
// calculate factorial
}
请注意,使用 while 循环的解决方案更加复杂,为了实现同样的目的,我们必须创建一个额外的变量num_ok
,以及一个额外的 if 语句。另一方面,do while 循环实现了同样的事情,没有任何欺骗,它更优雅和简洁。
在我们离开 do while 循环之前,让我们再举一个例子。
以下程序计算简单利息:
/******************************************
Program to calculate the Simple interest
*
* SI = (Principal * Rate * Time) / 100
*
******************************************/
#include<stdio.h> // include stdio.h
int main()
{
float p, r, t;
char ch = 'y';
do
{
printf("Enter principal: ");
scanf("%f", &p);
printf("Enter rate: ");
scanf("%f", &r);
printf("Enter t: ");
scanf("%f", &t);
printf("SI = %.2f", (p *r * t)/100 );
printf("\n\nCalculate SI one more time ? ('y' for Yes, 'n' for no ) : ");
scanf(" %c", &ch); // notice the preceding white space before %c
}while(ch == 'y'); // keep asking for P, R and T til the input is 'y'
// signal to operating system everything works fine
return 0;
}
预期输出:
Enter principal: 15000
Enter rate: 4.5
Enter t: 3
SI = 2025.00
Calculate SI one more time ? ('y' for Yes, 'n' for no ) : y
Enter principal: 20000
Enter rate: 5.4
Enter t: 4
SI = 4320.00
Calculate SI one more time ? ('y' for Yes, 'n' for no ) : n
C 语言中的for
循环
最后更新于 2020 年 7 月 27 日
在前两章中,我们已经学习了 while 和 do while loop 。在本章中,我们讨论 for 循环:for 循环的语法如下:语法:
for(expression1; expression2; expression3)
{
// body of for loop
statement1;
statement2;
}
expression1
是初始化表达式。
expression2
是测试表达式或条件。
这个expression3
就是更新表情。
工作原理:
首先执行初始化表达式(即expression1
)初始化循环变量。当循环开始时,expression1
只执行一次。然后检查条件(即expression2
,如果是真的,则执行循环的主体。在执行循环体之后,程序控制被转移到更新表达式(expression3
)。expression3
修改循环变量。然后再次检查条件(即expression2
)。如果条件仍然为真,则再次执行循环体。这个过程一直持续到expression2
变为假。
如果 for 循环的主体只包含一条语句,那么大括号({}
)可以省略。
for(expression1; expression2; expression3)
statement1;
// The above for loop is equivalent to:
for(expression1; expression2; expression3)
{
statement1;
}
以下程序计算从1
到100
的数字总和。
#include<stdio.h>
int main()
{
int i; // loop variable
int sum = 0; // variable to accumulate sum
for(i = 1; i <= 100; i++)
{
sum += i;
}
printf("Sum = %d", sum);
// return 0 to operating system
return 0;
}
预期输出:
Sum = 5050
工作原理:
在第 5 行,我们声明了一个名为i
的循环变量。在第 6 行,我们将名为sum
的变量声明并初始化为0
。然后程序控制进入 for 循环。首先执行初始化语句(i=1
)初始化循环变量i
。然后检查条件(i<100)
,如果为真,则执行 for 循环体内部的语句。在执行循环体之后,程序控制转移到更新表达式(i++
),并且i
的值增加1
。然后再次检查条件(i<100)
,如果仍然为真,则执行循环体。只要变量i
小于或等于100
,该过程就会继续。当i
到达101
时,条件(i<100)
变为假,控制从 for 循环中出来,执行后面的语句。
while 和 for 循环有什么区别吗?
while 和 for 循环本质上是以不同的方式做同样的事情。事实上,除了在极少数情况下,for 循环总是可以被 while 循环替换,反之亦然。
expression1;
while(expression2)
{
expression3;
}
在上面的片段中,expression1
可以被视为初始化表达式,因为它在 while 循环的开始只执行一次。expression2
是测试表达式,expression3
是更新表达式。将这个模式应用到我们前面的 for 循环示例中,让我们使用 while 循环重写它。
#include<stdio.h>
int main()
{
int i = 1, sum = 0;
while(i <= 100)
{
sum += i;
i++;
}
printf("Sum = %d", sum);
// return 0 to operating system
return 0;
}
for 循环中的表达式是可选的
for 循环中的所有三个表达式都是可选的,但两个分号必须始终存在。
- 如果初始化是在 for 循环之外完成的,我们可以省略
expression1
。 - 如果省略
expression2
,那么条件总是真的,导致无限循环的产生——一个永不停止执行的循环。为了避免无限循环,您应该在循环体中包含一个中断或返回语句。我们将在接下来的章节中详细讨论break
和return
陈述。 - 如果 for 循环体中存在更新表达式,我们可以省略
expression3
。
以下是基于省略表达式的 for 循环的一些简单变体:
例 1: 省略expression1
。
/*
1st variation - expression1 is omitted
*/
#include<stdio.h>
int main()
{
int i = 1, sum = 0;
//expression 1 is omitted
for( ; i <= 100; i++)
{
sum += i;
}
printf("Sum = %d", sum);
// return 0 to operating system
return 0;
}
预期输出:
Sum = 5050
在这种情况下,expression1
被省略,因为循环变量的初始化是在 for 循环之外执行的(第 9 行)。请注意,虽然省略了expression1
,但分号(;
)必须存在。
例 2: 省略expression2
。
/*
2nd variaton - expression2 is omitted
*/
#include<stdio.h>
int main()
{
int i, sum = 0;
for(i = 1 ; ; i++) // expression 2 is omitted
{
if(i > 100)
{
/* the break statement causes the loop to terminate.
We will discuss the break statement in detail
in later chapters.
*/
break;
}
sum += i;
}
printf("Sum = %d", sum);
// return 0 to operating system
return 0;
}
预期输出:
Sum = 5050
这里省略了条件。为了补偿这种情况,我们添加了 if 语句。当控制进入 for 循环的主体时,检查条件(i>100)
,如果为假,则省略 if 块中的语句。当i
到达100
时,条件(i>100)
变为真,执行break
语句,导致循环终止,程序执行随循环后的语句恢复。
**注意:**语句导致退出循环。在章节中的中断和continue
语句中有详细讨论。
例 3: 省略expression3
。
/*
3rd variation - expression3 is omitted
*/
#include<stdio.h>
int main()
{
int i, sum = 0;
// expression3 is omitted
for(i = 1 ; i <= 100 ; )
{
sum += i;
i++; // update expression
}
printf("Sum = %d", sum);
// return 0 to operating system
return 0;
}
预期输出:
Sum = 5050
这里省略了第三个表达式。为了补偿第三个表达式,我们在sum += i;
语句后添加了i++;
。
例 4:
/*
4th variation - all the expressions are omitted
*/
#include<stdio.h>
int main()
{
int i = 0; // initialization expression
int sum = 0;
for( ; ; )
{
if(i > 100) // condition
{
break; // break out of the for loop
}
sum += i;
i++; // update expression
}
printf("Sum = %d", sum);
// return 0 to operating system
return 0;
}
预期输出:
Sum = 5050
循环的嵌套
正如 if-else 语句可以嵌套在另一个 if-else 语句中一样,我们可以将任何类型的循环嵌套在任何其他类型的循环中。例如,一个 For 循环可以嵌套在另一个 for 循环中,或者嵌套在 while 或 do while 循环中。同样,while 和 do while 也可以嵌套。
以下程序使用嵌套 for 循环打印半金字塔图案:
#include<stdio.h>
int main()
{
int row = 0, col = 0;
for(row = 0; row < 10; row++) // number of lines
{
for(col = 0; col < row; col++) // num of * in each lines
{
printf(" * ");
}
printf("\n");
}
// return 0 to operating system
return 0;
}
预期输出:
*
* *
* * *
* * * *
* * * * *
* * * * * *
* * * * * * *
* * * * * * * *
* * * * * * * * *
工作原理:
在第 5 行,我们已经声明并初始化了两个整数变量row
和col
。
在第 7-14 行,我们有一个嵌套的 for 循环。外部 for 循环控制要打印的行数,内部 for 循环控制每行要打印的*
数。
当执行外部 for 循环时,row
变量的值被初始化为0
,然后条件(row<10)
被测试,因为它是真的(0<10
)控制进入外部 for 循环的主体,这是另一个 for 循环。在内部 for 循环中,变量col
被初始化为0
,然后检查条件(col<=row
),因为它是真的(0<=0
)。执行内部循环体内部的语句,即printf(" * ")
。然后,使用更新表达式col++
将col
增加1
(现在col
的值为1
)。再次测试条件(col<=row
),因为它是假的(1<=0
)。控件脱离内部 for 循环。第 13 行的printf()
语句打印一个换行符(\n
)。由于没有更多的语句可以执行,控制转移到外部 for 循环的更新表达式。row
的值增加1
(现在row
是1
)。测试条件(row<10)
,因为它是真的(1<10
)。再次执行外部 for 循环的主体。这个过程会一直重复直到row<10
。当row
到达10
时,条件row < 10
变为假,控制从外环出来。