第5章 操作符和表达式

学习笔记

  • 移位操作符。右移位操作有两种选择方案:一种是逻辑移位,左边移入的位用0填充;另一种是算数移位,左边移入的位由原先该值的符号位决定,符号位为1则移入的位均为1,符号位为0则移入的位均为0,这样能够保持原数的正负形式不变。算数左移和逻辑左移是相同的,右边空出来的位用0补齐
  • 标准说明无符号值执行的所有移位操作都是逻辑移位,但对于有符号值,到底是采用逻辑移位还是算术移位取决于编译器。有符号值的右移位操作是不可移植的
  • 编译器只要不违背优先级和结合性规则,它可以自由决定复杂表达式的求值顺序。表达式的结果如果依赖于求值的顺序,那么它在本质上就是不可移植的,应该避免使用
  • static 修饰函数中的局部变量,初始化只在第一次调用函数时进行初始化。后续调用时,该变量使用前一次函数调用完成之后保存的值

书后练习

问题2

下面这个程序的结果是什么

int 
func( void )
{
	static int counter = 1;
	return ++counter;
}

int 
main()
{
	int answer;
	answer = func() - func() * func();
	printf( "%d\n", answer );
}

根据上述学习到的知识点:编译器只要不违背优先级和结合性规则,它可以自由决定复杂表达式的求值顺序
所以该程序可能有三种结果,在gcc编译器上结果为-10

2 - 3 * 4 = -10
3 - 2 * 4 = -5
4 - 2 * 3 = -2

问题4

条件操作符在运行时较之if语句是更快还是更慢?试比较下面两个代码段

if( a > 3 )
	i = b + 1;
else
	i = c * 5;
i = a > 3 ? b + 1 : c * 5;

一样快,都需要先判断a与3的值,然后再对i进行赋值

问题6

哪些操作符具有副作用?它们具体有什么副作用

操作符副作用
++,–不论是前缀还是后缀形式,这些操作符都会修改它们的操作数
=包括所有其他的复合赋值符,它们都修改作为左值的左操作数

编程练习1

编写一个程序,从标准输入读取字符,并把它们写道标准输出中。除了大写字母字符要转换为小写字母之外,所有字符的输出形式应该和它的输入形式完全相同。

#include <stdio.h>
#include <stdlib.h>

int main( int argc, char *argv[] ){
#if 1
    /* 从标准输入读取字符并写到标准输出中 */
    char ch;
    while( 1 ) {
        scanf( "%c", &ch );
        /* 如果是大写字母,则转换为小写字母 */
        if( ch >= 'A' && ch <= 'Z' ) {
            ch += 32;
        }
        printf( "%c", ch );
    }

#endif
#if 0
    char x = 'a', y = 'A';
    printf( "%d\n", x - y );
#endif
    return EXIT_SUCCESS;
}

标准答案

#include <stdio.h>
#include <ctype.h>

int main( void ) {
    int ch;
    /* 提倡使用的转换字母大小写的方法是使用tolower库函数 */
    while( (ch = getchar()) != EOF )
        putchar( tolower( ch ) );
}

编程练习3

请编写函数

unsigned int reverse_bits( unsigned int value );

这个函数的返回值是把value的二进制位模式从左到右变换一下后的值。例如,在32位机器上,25这个值包含下列各个位

0000 0000 0000 0000 0000 0000 0001 1001

函数的返回值应该是2550136832,它的二进制位模式是

1001 1000 0000 0000 0000 0000 0000 0000

编写函数时要注意不要让它依赖于你的机器上整型值的长度

#include <stdio.h>
#include <stdlib.h>

/* 把value的二进制位模式从左到右变换一下后的值 */
unsigned int reverse_bits( unsigned int value ) {
    unsigned int res = 0;
    /* 计算存储value使用的字节数,并转换为相应的位数 */
    int len = sizeof(value) * 8;
    /* 把value的二进制位模式翻转 */
    for( int i = 0; i < len; i++ ) {
        /* 得到value值最低位的数值 */
        unsigned int num = value & 1;
        /* 将value逻辑右移 */
        value >>= 1;
        /* 将res结果值逻辑左移 */
        res <<= 1;
        /* 将value值最低位的数值保存到res中 */
        res |= num;
    }
    return res;
}

int main( int argc, char *argv[] ) {
    unsigned int res = reverse_bits(25);
    printf( "%u\n", res );
    return EXIT_SUCCESS;
}

标准答案

unsigned int i;
/* 只要i不是0就可以继续进行,使得循环与机器字长无关,从而避免了可移植性的问题 */
for( i = 1; i != 0; i <<= 1 ) {
	...
}
  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值