云计算百科
云计算领域专业知识百科平台

我从零开始学习C语言(9)- 表达式Part2

4.3 自增运算符和自减运算符

变量最常用的两种运算是“自增1“和“自减1”。可以用下面代码表示:

i = i + 1;
j = j – 1;

复合赋值运算符表示可以把语句缩短:

i += 1;
j -= 1;

C语言允许使用++(自增)和–(自减)运算符把语句缩得更短。

但是,自增/减运算符仅仅是用来缩短语句的吗?Of Course NOT!

实际上++、–运算符可以作为前缀(prefix)运算符(++i、–i),也可以作为后缀(postfix)运算符使用(i++、i–)使用,而且使用它们都会改变操作数本身的值。

比如说++i,结果就是i+1,但是它有个副作用是i自身会增加1。比如说:

i = 1;
printf("%d", ++i); // 输出2
printf("%d", i); // 输出2

算i++时,结果是i,但是随后引发i进行自增。比如说:

i = 1;
printf("%d", i++); // 输出1
printf("%d", i); // 输出2

++i意味着立即自增i,而i++意味着“先取i的原来值”,稍后再自增i。稍后是多久呢?一般是在执行下一条语句执行前进行自增。

–运算符同理可得。

i = 1;
printf("i is %d\\n", –i); //输出0
printf("i is %d\\n", i); //输出0

i = 1;
printf("i is %d\\n", i–); //输出1
printf("i is %d\\n", i); //输出0

如果同一个表达式中多次使用++或–运算符,结果会很难理解。

例如:

i = 1;
j = 2;
k = ++i + j++;

执行上述语句后,i, j, k分别是多少呢?

上面的语句等价为:
 

i = i + 1;
k = i + j;
j = j + 1;

最终i = 2, j = 3,k =4;

如果:

i = 1;
j = 2;
k = i++ + j++;

最终i = 2, j = 3,k = 3;

要记住:后缀++/–比一元正负号优先级高,左结合。

前缀++/–与一元正负号优先级相同,右结合。

练习题

只做了两个~

1. 给出下列程序片段的输出结果。假设i 、j 和k 都是int 型变量。

(a)

i = 5; j = 3;
printf("%d %d", i / j, i % j);

分析:5 / 3,除号两边操作数都是整数,所以结果也是整数,所以5 / 3 = 1

5 % 3,余数是2。

所以结果是1 2。

验证:

#include <stdio.h>

int main()
{
int i = 5, j = 3;
printf("%d %d", i / j, i % j);
return 0;
}

(b)

i = 2; j = 3;
printf("%d", (i + 10) % j);

分析:i + 10的结果是2+10=12,j的值是3。所以最后算式等价于12 % 3 为0,能被3整除。

所以输出0。

验证:

#include <stdio.h>

int main()
{
int i = 2, j = 3;
printf("%d", (i + 10) % j);
return 0;
}

(c)

i = 7; j = 8; k = 9;
printf("%d", (i + 10) % k / j);

分析:将变量值一次带入,得到(7 + 10) % 9 / 8。化简17 % 9 / 8,这里是先算%还是先算/呢?经过查询优先级,是先算%再算/。所以得到8 / 8 = 1。

最后输出 1。

验证:

#include <stdio.h>

int main()
{
int i = 7, j = 8, k = 9;
printf("%d", (i + 10) % k / j);
return 0;
}

(d)

i = 1; j = 2; k = 3;
printf("%d", (i + 5) % (j + 2) / k);

分析:直接变量值带入,(1 + 5) % (2 + 2) / 3 = 6 % 4 / 3,算得2 / 3 = 0

输出 0

验证:

#include <stdio.h>

int main()
{
int i = 1, j = 2, k = 3;
printf("%d", (i + 5) % (j + 2) / k);
return 0;
}

*2. 如果i 和 j 都是正整数,(-i) / j 的值和-(i / j) 的值是否总一样?验证你的答案。

如果i,j都为int类型,它们的运算跟数学上是一致的,都是一样的。

若i或j为unsignd int类型,一个可能为负值,另一个变成很大的正数,就不一样了。

编程题

1. 编写一个程序,要求用户输入一个两位数,然后按数位的逆序打印出这个数。程序会话应类似下面这样:

Enter a two-digit number: 28
The reversal is: 82

用%d 读入两位数,然后分解成两个数字。提示 :如果n 是整数,那么n % 10 是个位数,而n / 10 则是移除个位数后剩下的数。

分析:n%10保留数字n的第一个尾数,n/10去掉数字n的第一个尾数。

那么推得:n%10^a保留数字n的a个尾数,n/10^a去掉数字n的a个尾数。

而且数字的组合abc(十进制) = 100 * a + 10 * b + c。

那么可以写得代码:

#include <stdio.h>

int main()
{
int n, a, b, i;
printf("Enter a two-digit number: ");
scanf("%d", &n);
a = n / 10;
b = n % 10;
i = 10 * b + a;
printf("The reversal is: %d", i);

return 0;
}

2. 扩展上题中的程序使其可以处理3位数。

分析:先去尾数再保留尾数,或先保留尾数再去尾数。

方法1(推荐):

#include <stdio.h>

int main()
{
int n, a, b, c, i;
printf("Enter a three-digit number: ");
scanf("%d", &n);
a = n / 100;
b = n / 10 % 10;
c = n % 10;
i = 100 * c + 10 * b + a;
printf("The reversal is: %d", i);

return 0;
}

方法2:

#include <stdio.h>

int main()
{
int n, a, b, c, i;
printf("Enter a three-digit number: ");
scanf("%d", &n);
a = n % 1000 / 100;
b = n % 100 / 10;
c = n % 10 / 1;
i = 100 * c + 10 * b + a;
printf("The reversal is: %d", i);

return 0;
}

3. 重新编写编程题2中的程序,使新程序不需要利用算术分割就可以显示出3位数的逆序。提示 :参考4.1节的upc.c 程序。

分析:这个就是利用scanf的%1d格式符,一个个的存到变量再组合。

#include <stdio.h>

int main()
{
int n, a, b, c, i;
printf("Enter a three-digit number: ");
scanf("%1d%1d%1d", &a, &b, &c);
i = 100 * c + 10 * b + a;
printf("The reversal is: %d", i);

return 0;
}

4. 编写一个程序,读入用户输入的整数并按八进制(基数为8)显示出来:

Enter a number between 0 and 32767: 1953
In octal, your number is: 03641

输出应为5位数,即便不需要这么多数位也要如此。提示 :要把一个数转换成八进制,首先将其除以8,所得的余数是八进制数的最后一位(本例中为1);然后把原始的数除以8,对除法结果重复上述过程,得到倒数第二位。

分析:经典的除R取余法。

#include <stdio.h>

int main()
{
int n, a, b, c, d, e;
printf("Enter a number between 0 and 32767: ");
scanf("%d", &n);

printf("In octal, your number is: " );
a = n % 8; n = n / 8;
b = n % 8; n = n / 8;
c = n % 8; n = n / 8;
d = n % 8; n = n / 8;
e = n % 8; n = n / 8;
printf("%d%d%d%d%d", e, d, c, b, a);
return 0;
}

5. 重写4.1节的upc.c 程序,使用户可以一次输入11位数字,而不用先录入1位,再录入5位,最后再录入5位。

Enter the first 11 digits of a UPC: 01380015173
Check digit: 5

分析:合起来就行。

/* Computes a Universal Product Code check digit */
#include <stdio.h>
int main(void)
{
int d, i1, i2, i3, i4, i5, j1, j2, j3, j4, j5, first_sum, second_sum, total;

printf("Enter the first 11 digits of a UPC: ");
scanf("%1d%1d%1d%1d%1d%1d%1d%1d%1d%1d%1d", &d, &i1, &i2, &i3, &i4, &i5, &j1, &j2, &j3, &j4, &j5);

first_sum = d + i2 + i4 + j1 + j3 + j5;
second_sum = i1 + i3 + i5 + j2 + j4;
total = 3 * first_sum + second_sum;
printf("Check digit: %d\\n", 9 – ((total – 1) % 10));
return 0;
}

6. 欧洲国家不使用北美的12位通用产品代码(UPC),而使用13位的欧洲商品编码(European Article Number, EAN)。跟UPC一样,每个EAN码的最后也有一个校验位。计算校验位的方法也类似:首先把第2位、第4位、第6位、第8位、第10位和第12位数字相加;然后把第1位、第3位、第5位、第7位、第9位和第11位数字相加;接着把第一次加法的结果乘以3,再和第二次加法的结果相加;随后,再把上述结果减去1;相减后的结果除以10取余数;最后用9减去上一步骤中得到的余数。以Güllüoglu Turkish Delight Pistachio & Coconut为例,其EAN码为8691484260008。第一个和为6+1+8+2+0+0=17,第二个和为8+9+4+4+6+0=31。第一个和乘以3再加上第二个和得到82,减1得到81。这个结果除以10的余数是1,再用9减去余数得到8,与原始编码的最后一位一致。请修改4.1节的upc.c 程序以计算EAN的校验位。用户把EAN的前12位当作一个数输入:

Enter the first 12 digits of an EAN: 869148426000
Check digit: 8

分析:这题上篇文章做过,但题目给出的算法似乎又有点不同。尝试一下写代码:

#include <stdio.h>

int main(void)
{
int i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12;
printf("请输入商品条形码(不输入最后一位):");
scanf("%1d%1d%1d%1d%1d%1d%1d%1d%1d%1d%1d%1d",
&i1, &i2, &i3, &i4, &i5, &i6, &i7, &i8, &i9, &i10, &i11, &i12);
int A, B, C, check;
A = (i12 + i10 + i8 + i6 + i4 + i2) * 3;
B = (i11 + i9 + i7 + i5 + i3 + i1);
C = (A + B – 1) % 10;
check = 9 – C;
printf("Check digit(最后一位是): %d\\n", check);
return 0;
}

明天开始学习第五章选择语句。

赞(0)
未经允许不得转载:网硕互联帮助中心 » 我从零开始学习C语言(9)- 表达式Part2
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!