C语言梦开始的地方3

文章目录

C语言梦开始的地方3

上一章节C语言梦开始的地方2 我们了解C语言用于存储生活中的各种数据的类型,整数类型,字符类型,浮点数类型等这些。本章节我们了一下C语言提供各种的操作符,是如何使用。

算术操作符

在我们日常写代码的时候,一定是会涉及计算的

C语言为了方便运算提供了一系列的操作符,其中有一组操作符叫:算术操作符。分别是: + - * / % ,这些操作符都是双目操作符。

双目操作符的意思就是要有两个操作数比如:c = a + b; 那么当前的操作数就是a和b这两个变量。

加、减、乘、除、取余。整数除会截断,% 只能用于整数。

c 复制代码
int main()
{
    int a = 3,b = 2;


    printf("加法操作:%d\n",a + b);

    printf("减法操作:%d\n",a - b);

    printf("乘法操作:%d\n",a * b);

    printf("除法操作:%d\n",a / b);

    printf("取余操作:%d\n",a % b);
    return 0;
}
  1. 这里我们需注意的是%的两个操作数一定要是整数,如果是非整数就会报错。
  2. 不要用unsigned进行小-大这种操作除了是你代码需要这样,因为unsigned 小-大出现的数并不是负数,小-大是一个很大的数比如:2 - 3 unsigned的结果是4294967295d。但是有的人进行这个操作时得出的结果和signed2 - 3是一样的,是因为你使用的printf格式符是signed而不是unsigned的,signed%d,%ld这种 unsigned是:%u这样printf输出的才是正确计算的值。
  3. C99 起整数除法是向零取整(截断)。正数时两者相同(3/2=1),但负数不同:C 中 -3/2 是 -1,向下取整则是 -2。建议改成"截断小数部分/向零取整"。顺带可补充:% 取余结果的符号与被除数相同,-3 % 2 = -1。

位操作符

我们知道计算机存储的是二进制即0和1,而位操作符就是C语言提供给我们来进行二进制运算的。

分别是& | ^ >> << ~

c 复制代码
int main()
{
    int a = 2, b = 3; // 2 = 010, 3 = 011

    printf("a & b  = %d\n", a & b);  // 010 & 011 = 010 = 2
    printf("a | b  = %d\n", a | b);  // 010 | 011 = 011 = 3
    printf("a ^ b  = %d\n", a ^ b);  // 010 ^ 011 = 001 = 1
    // 对 a 按位取反(注意 ~ 是单目操作符)取反就是0取1,1取0
    printf("~a     = %d\n", ~a);      
    printf("a << 1 = %d\n", a << 1); // 010 左移1位 = 100 = 4
    printf("a >> 1 = %d\n", a >> 1); // 010 右移1位 = 001 = 1
    return 0;
}

注意 : ~2 在 %d 下输出 -3(int 按补码对含符号位取反)。但是这是signed而unsigned取反是0转1,1转0的操作。计算机的计算是通过原码,反码和补码进行的后面我们会深入了解

现在我们只需要了解signed的原码左边第一个是符号位;

正数的原码,反码和补码是一样的;

负数的原码取反是反码,反码 + 1是补码

赋值操作符

C语言提供的赋值操作符有:=和复合赋值比如:+=,-=这种

注意:在变量创建的时候给一个初始值叫初始化,在变量创建好后,再给一个值,这叫赋值。

c 复制代码
int main()
{
    //初始化:在变量创建的同时赋初值
    int a = 10;
    //赋值:先创建变量,之后再给它赋值
    int b;
    b = 10;

    //======== 复合赋值 与 普通赋值 的对比 ========
    a = 10;      // 重置
    b = 2;
    a += b;      // 等价于 a = a + b;
    printf("a += b  =>  %d\n", a);

    a = 10;
    a -= b;      // 等价于 a = a - b;
    printf("a -= b  =>  %d\n", a);

    a = 10;
    a *= b;      // 等价于 a = a * b;
    printf("a *= b  =>  %d\n", a);

    a = 10;
    a /= b;      // 等价于 a = a / b;
    printf("a /= b  =>  %d\n", a);

    a = 10;
    a %= b;      // 等价于 a = a % b;
    printf("a %%= b  =>  %d\n", a);

     a = 1;
    a <<= b;     // 等价于 a = a << b;  即 1<<2 = 4
    printf("a <<= b  =>  %d\n", a);

    a = 16;
    a >>= b;     // 等价于 a = a >> b;  即 16>>2 = 4
    printf("a >>= b  =>  %d\n", a);

    a = 5;
    a &= b;      // 等价于 a = a & b;   即 101 & 010 = 0
    printf("a &= b  =>  %d\n", a);

    a = 5;
    a |= b;      // 等价于 a = a | b;   即 101 | 010 = 111 = 7
    printf("a |= b  =>  %d\n", a);

    a = 5;
    a ^= b;      // 等价于 a = a ^ b;   即 101 ^ 010 = 111 = 7
    printf("a ^= b  =>  %d\n", a);
    return 0;
}

单目操作符

前面介绍的操作符都是双目操作符(除了~),有2个操作数的。C语言中还有一些操作符只有一个操作数,被称为单目操作符。++、--、+(正)、-(负) 就是单目操作符的。

  • 和 -在C语言中是符号位的意思比如:+10 等价于 10,-10 就是负数10
    ++ 和 -- 也分前置和后置,我们通过代码来进行了解
c 复制代码
int main()
{
    // 前置++ 和 后置++的区别
    int i = 3;
    printf("i++ = %d, 之后 i = %d\n", i++, i); // i++ 先用后加:3
    int j = 3;
    printf("++j = %d, 之后 j = %d\n", ++j, j); // ++j 先加后用:4
    // 谭浩强 《C语言程序设计》中对++的错误使用
    i = 5, j = 5;
    int p, q; 
    p = (i++) + (i++) + (i++);
    q = (++j) + (++j) + (++j);
    printf("%d, %d, %d, %d\n", p, q, i, j); // 书里写的结果是 15, 22, 8, 8
    
    // C语言对应的标准用法
    i = 5; j = 5;
    i++; i++; i++;          // 等价于原例中的 (i++)+(i++)+(i++)
    p = i;                  // p = 8
    ++j; ++j; ++j;          // 先自增
    q = j;                  // q = 8
    printf("%d, %d, %d, %d\n", p, q, i, j); // 任何编译器都输出 8, 8, 8, 8
    return 0;
}

虽然谭浩强老师写的代码在如今的编译器中存在二义性,但是谭浩强老师在《C语言程序设计》中的思路与套路依旧能打,主要还是谭浩强老师在写这本书时年纪已经很大了。而且这本书在如今的ai时代是一本完全可以作为入门级的C语言书籍来看的。

强制类型转换

在操作符中还有一种特殊的操作符是强制类型转换。

强制类型转换我们通过下面代码进行了解强制类型转换的用法:

  • (类型)变量
c 复制代码
int main()
{
    int a = 3, b = 2;
    // 不转:3/2 得 1;强制把 a 转 float 再除,结果 1.5
    printf("%f\n", (float)a / b);

    double d = 3.99;
    int e = (int)d;      // 截断小数部分:e = 3,不是四舍五入
    printf("%d\n", e);

    int f = 65;
    char g = (char)f;    // 65 是 'A' 的 ASCII 码
    printf("%c\n", g);

    // 强制转换只产生临时值,原变量 a 的类型和值不变
    printf("%d\n", a);   // 仍是 3
    return 0;
}

隐式转换:int + float 时 int 自动提升为 float。这里提升是因为float能表达的范围更精确

显式转换语法 (类型)表达式,如 (float)a。

注意:(int)3.99 是截断不是四舍五入;double→int 大数会溢出;(float)a / b 等价 ((float)a) / b,括号位置要看清楚。

俗话说,强扭的瓜不甜,我们使用强制类型转换都是万不得已的时候使用,如果不需要强制类型转化就能实现代码,这样自然更好的。

本章我们把 C 语言最基础的"算账工具"都过了一遍------算术、位运算、赋值、单目、强制类型转换。其实操作符不难,难的是细节:整数除法会截断、% 只能用在整数上、unsigned 不能随便小减大、~ 和补码的关系、强制转换要小心截断和丢失。

但是本章节仍有一些操作符没有介绍到,下一章节我们就配套这选择和循环语句进行讲解。

相关推荐
Bonnie_12151 小时前
08-JUC并发基础-AQS-补充共享锁
java·开发语言
qq_401700411 小时前
Qt 程序启动太乱?重新设计你的 Application 生命周期
开发语言·qt
A_cainiao_A1 小时前
【ggml系列】【第四篇】ggml_graph_compute 多线程计算引擎与算子分发源码深度解析
开发语言·c++·矩阵
90后小陈老师1 小时前
从“打开就卡“到“秒开“:一次 PHP GD 动态海报生成的性能优化实战
开发语言·性能优化·php
小白学大数据2 小时前
基于Python的抖音网页版视频点赞数增长趋势追踪系统设计与实现
开发语言·爬虫·python·搜索引擎·音视频
木由里予2 小时前
TEE(Trusted Execution Environment)技术详解
java·linux·开发语言·网络·嵌入式硬件·android-studio
JckOLF04Z2 小时前
C#客户端的异步操作
开发语言·c#
曹牧2 小时前
C#:注释嵌套
开发语言·c#
中国搜索直付通2 小时前
游戏车机端支付通道,会是下一个被低估的合规战场吗?
java·大数据·开发语言·人工智能·游戏