当前位置: 首页 > news >正文

C语言基础要素(010):复合赋值

赋值运算的右结合性

对于运算符的右结合性,我们从初始化与赋值开始。

int width = 2 * 3;      // 使用表达式初始化
width = 3 + 2;          // 使用表达式赋值

代码极其简单,但有两个问题需要你回答。

  • 定义width变量时,它的初始值是多少?
  • 给width变量赋值后,它的值又是多少?

相信你会随口说出,width的值分别是6与5(表达式的结果),而不是2与3("="右边的第一个数值)。稍加思索,你会发现自己先计算了赋值运算符右侧的整个表达式,然后将结果赋予width变量,我们称这类运算符具有右结合性。

double x, y, z, w;
x = y = z = w = 1.0;

// 等同上面的代码
double x, y, z, w;
w = 1.0f;
z = w;
y = z;
x = y;

左值与右值

我们曾以盒子类比了变量的存储特性,同样的我们也可以查看盒子中的物品,即读取变量的值。只要变量一直存在,我们就可以对其无限次读取,而且其值始终是存在的。

int a = 65;
printf("%d\n", a);  // 输出65
printf("%d\n", a);  // 输出65,这不会因为上面查看a的值而使盒子为空。
int b = a;          // 使用a的值初始化b
printf("%d\n", a);  // 输出65,这不会因为上次初始化b而使盒子a为空。

可以看出,一个变量(如这里的变量a)在不同的语义环境下其意义不同:

  • 赋值时:变量取盒子的存储功能这一概念
  • 读取时:变量取查看盒子中数据的概念

从赋值运算符的角度讲,变量在左侧时代表着写入操作,此时变量是个左值(lval),左值在程序中有一个确切的内存地址以用于写数据;在右侧时代表着读取操作,称为右值(rval)。下面的例子展示了可能的左值与右值表现方式。

//                 左值  |  右值
//===================== | ================
int a = 3;      // 变量a |  常数3
int b = a;      // 变量b |  变量a
int c = a + b;  // 变量c |  a+b的结果

我们不能将一个变量赋值给一个常数(它不是一个盒子),但是,同一个变量却可以出现在赋值运算符的左右两侧,在左边取盒子存储的概念,在右边取读取盒中数值的概念。

int a = 3;
3 = a;      // err
a = a;      // ok
a = a + 3;  // ok

复合赋值语句

像 a=a; 这种做法你几乎不会用,但让a自身发变化是可行的。比如说有一个记录英雄血量的hp变量,当角色获得能量后hp值增加,我们可以这样编写:

int hp = 9;
int food_hp = 10;
hp = hp + food_hp;

对于这种实现,C语言也提供了一种简化的语法,称为复合赋值运算。

int hp = 9;
int food_hp = 10;
hp += food_hp;    // 少输几个字符

这里,我们使用 += 运算符完成了等同的操作,当使用这种简写形式时,不论右侧表达式多复杂,始终要将它们看作是一个整体,并与左侧变量运算求值。

int a = 2;
a += 3;     // 相当于 a = a + 3;
a *= 6 - 4; // 相当于 a = a * (6 - 4);

除了+=,*=简写形式,C语言还提供了-=、/=、%=简写运算符,再次对于/=,%=运算进行提醒:除数不能为0。

#include <stdio.h>

int main()
{
    float x, y, z, w;
    x = y = z = w = 1.0f;
    printf("x = %f\n", x);

    int a = 2;
    a = a + 3;  // 相当于 a += 3;
    printf("a = %d\n", a);

    a *= 6 - 4; // 相当于 a = a * (6 - 4);
    printf("a = %d\n", a);

    return 0;
}

在这里插入图片描述

练习

  1. 编写程序,让变量 area 存储矩形面积。
  2. 使用复合赋值运算符,让矩形面积缩小一半。
  3. 观察习题2中的程序,指出变量左右值使用情况。

相关文章:

  • Android 14 - HDMI_CEC架构分析
  • Go语言学习笔记(六)——标准库
  • 量子算法:英译名、概念、历史、现状与展望?
  • SparkStreaming之04:调优
  • WPF高级 | WPF 应用程序部署与发布:确保顺利交付到用户手中
  • 深入 PipeWire
  • Lua如何实现面向对象的三大特性?
  • Linux第五讲----gcc与g++,makefile/make
  • Halcon 算子-承接车牌识别
  • FPGA标准库-Open Logic
  • 376_C++_云透传,板端负责处理透传数据的API函数,用于实现客户端对设备内部接口的访问(VMS把数据直接传给板端内部)
  • 音频3A测试--AGC(自动增益)和NS(降噪)测试
  • 【监控】使用Prometheus+Grafana搭建服务器运维监控面板(含带BearerToken的Exporter配置)
  • 2024北京理工大学计算机复试上机真题
  • 《AJAX:前端异步交互的魔法指南》
  • 828华为云征文|使用sysbench对Flexus X实例对mysql进行性能测评
  • VirtualBox虚拟机MacOS从Big Sur升级到Sequoia(失败)
  • 软件架构师日常工作和核心技能
  • Keepalived 入门详解:高可用集群部署最佳实践!
  • 动静态库-Linux 学习
  • 建筑开发公司/百度推广seo自学
  • 党刊网站怎么做/开发一个网站的步骤流程
  • 福州优秀网站建设公司/长春百度网站快速排名
  • 淘宝做链接的网站/申请网址怎么申请的
  • 怎么快速做网站/全网整合营销推广方案
  • 专业网站设计建设服务/怎样在百度答题赚钱