C语言基础(day0424)

目录

[一. 键盘输入](#一. 键盘输入)

[1.1 grtchar()](#1.1 grtchar())

[1.2 scanf()](#1.2 scanf())

总结:

[二. 全局变量/局部变量(函数的分类)](#二. 全局变量/局部变量(函数的分类))

1.全局变量

2.局部变量

[三.C语言内存模型(堆栈内存and so on )](#三.C语言内存模型(堆栈内存and so on ))

[3.1 栈区(stack)(未完待续.....)](#3.1 栈区(stack)(未完待续.....))

[3.2 堆区](#3.2 堆区)

[3.3 全局静态区](#3.3 全局静态区)

[1. 未初始化](#1. 未初始化)

[2. 已初始化](#2. 已初始化)

[3.4 常量区](#3.4 常量区)

[3.5 代码区](#3.5 代码区)

四.基本数据类型的转换

[4.1 自动转换](#4.1 自动转换)

[4.2 强制转换](#4.2 强制转换)

[4.3 数据类型的精度](#4.3 数据类型的精度)

[五. 运算符](#五. 运算符)

[1. 算数运算符](#1. 算数运算符)

[2. 比较运算符](#2. 比较运算符)

[3. 赋值运算符](#3. 赋值运算符)

[4. 自增运算符](#4. 自增运算符)

[5. 逻辑运算符](#5. 逻辑运算符)

[6. 条件运算符(三目运算符)](#6. 条件运算符(三目运算符))

[7. 逗号运算符](#7. 逗号运算符)

[8. 运算符优先级(未完待续.....)](#8. 运算符优先级(未完待续.....))

[9. 位运算符](#9. 位运算符)

[1. 补码的核心定义](#1. 补码的核心定义)

[2. 按位取反 (~) 的本质](#2. 按位取反 (~) 的本质)

[3. 按位取反步骤(公式为~ a = -(a + 1))](#3. 按位取反步骤(公式为~ a = -(a + 1)))


一. 键盘输入

1.1 grtchar()

getchar() 函数用于从标准输入中读取一个字符,返回值为读取的字符。

getchar() 函数会等待用户输入一个字符并按下回车键,然后返回该字符的 ASCII 值。

cpp 复制代码
//  这是一个简单的 getchar()示例,getchar只能读取数据类型为字符的变量
    // getchar() 函数用于从标准输入中读取一个字符,返回值为读取的字符。
    // getchar() 函数会等待用户输入一个字符并按下回车键,然后返回该字符的 ASCII 值。
    printf("请输入一个字符:\n");
    printf("请输入一个字符:\n");
    char ch = getchar();                // 使用 getchar 获取一个字符输入,并将其存储到变量 ch 中
    printf("您输入的字符是:%c\n", ch); // 输出用户输入的字符

1.2 scanf()

  1. 使用 scanf 函数从标准输入中读取数据需要包含 stdio.h 头文件

  2. scanf() 函数用于从标准输入中读取数据,格式为 scanf("格式控制字符串", 参数列表),类似于 printf() 的格式化输出。

  3. 谨防 "空格陷阱"

cpp 复制代码
#include <stdio.h>
int main(int argc, char const *argv[])
{
    //  这是一个简单的 printf() 示例
    printf("请输入一个字符:\n");
    printf("请输入一个字符:\n");
    char ch = getchar();            // 使用 getchar 获取一个字符输入,并将其存储到变量 ch 中
    printf("您输入的字符是:%c\n", ch); // 输出用户输入的字符

    // 使用 scanf 函数从标准输入中读取数据需要包含 stdio.h 头文件
    // scanf() 函数用于从标准输入中读取数据,格式为 scanf("格式控制字符串", 参数列表),类似于 printf() 的格式化输出。
    // 常见的格式化输入符号包括:%d(整数),%f(浮点数),%c(字符),%s(字符串),%x(十六进制整数),%o(八进制整数),%p(指针地址)。
    printf("请输入一个整数:\n");
    int num = 0;                       // 定义一个整数变量 num 并初始化为 0
                                       // 使用 scanf() 函数从标准输入中读取整数并存储到 num 中
    scanf("%d", &num);                 // 使用 scanf 函数从标准输入中读取一个整数并存储到 num 中
    printf("您输入的整数是:%d\n", num); // 输出用户输入的整数

    printf("请输入一个字符类型变量:\n");
    char c1;                        // 定义一个字符变量 c1
    scanf("%c", &c1);               // 使用 scanf 函数从标准输入中读取一个字符并存储到 c1 中
    printf("您输入的字符是:%c\n", c1); // 输出用户输入的字符
    // 使用 scanf() 函数从标准输入中读取多个变量的值

    printf("请输入两个变量的值(一个整数和一个浮点数):\n");
    int a = 0;                                       // 定义一个整数变量 a 并初始化为 0
    float b = 0.0;                                   // 定义一个浮点数变量 b 并初始化为 0.0
    scanf("%d %f", &a, &b);                          // 使用 scanf 函数从标准输入中读取一个整数和一个浮点数,并存储到变量 a 和 b 中
    printf("您输入的整数是:%d,浮点数是:%f\n", a, b); // 输出用户输入的整数和浮点数

    return 0;
}
总结:
  • 空格在 scanf 中的行为:匹配输入中的任意数量空白字符(包括零个或多个)。

  • 格式字符串中的普通字符:必须严格匹配输入流中的字符。

  • 最佳实践

    • 谨慎使用格式字符串中的空格。

    • 结合 fgetssscanf 处理输入,避免缓冲区残留问题。

    • 始终检查 scanf 的返回值,确保输入符合预期。

二. 全局变量/局部变量(函数的分类)

1.全局变量

(1)即作用于代码运行全过程的变量

(2)具体演示,在下方代码

cpp 复制代码
#include <stdio.h>

// 全局变量..........所有函数都可以访问
// 全局变量如果未赋值,分配的默认值根据数据类型的不同而不同
// 全局变量耦合度高,容易引起错误,使用时要小心
/*
        int类型的全局变量默认值为0
        float类型的全局变量默认值为0.000000
        char类型的全局变量默认值为'\0'
        double类型的全局变量默认值为0.000
        char类型的全局变量默认值为'\0'
        short类型的全局变量默认值为0
        long类型的全局变量默认值为0
 */
int globalVar = 10; // 全局变量,作用域为整个文件,与函数平级

void function()
{
    // 局部变量
    int localVar = 5; // 局部变量,作用域仅限于此函数内
    printf(" 函数内 局部变量 localVar 的值: %d\n", localVar);
    printf(" 函数内 全局变量 globalVar 的值: %d\n", globalVar);
}

int main()
{

    printf("全局变量 globalVar 的值: %d\n", globalVar); // 可以访问全局变量
    function();                                         // 调用上方的函数

    // printf("局部变量 localVar 的值: %d\n", localVar); // 这行代码会报错,因为 localVar 作用域仅限于 function 函数
    return 0;
}

2.局部变量

(1)即作用于部分代码块的变量

(2)具体演示,在下方代码

cpp 复制代码
#include <stdio.h>

// 局部变量示例:演示局部变量的初始化和使用
// 局部变量未初始化时,其默认值是未定义的,因为普通局部变量存储在栈空间中,包含之前的随机数据。
int main()
{
    // 未初始化的局部变量-----------注意其默认值是未定义的
    int localVar; // 局部变量声明但未初始化
    printf("未初始化的局部变量 localVar 的值: %d\n", localVar);

    // 初始化局部变量-----------默认值为0
    localVar = 0;
    localVar = 0; // 初始化局部变量,将其值设置为0
    printf("初始化后的局部变量 localVar 的值: %d\n", localVar);

    // 在同一个函数中,局部变量可以重复使用
    // int localVar = 5; // 如果这样写会报错,因为 localVar 已经在上面声明过,并且已经使用 int 在栈中分配了空间
    // printf("在同一个函数中,局部变量可以重复使用,但需要注意不能重新声明同名变量。");

    // 在同一个函数中,可以使用同名的变量,但需要使用不同的作用域
    localVar = 5; // 修改局部变量的值为5
    printf("修改后的局部变量 localVar 的值: %d\n", localVar);

    return 0;
}

三.C语言内存模型(堆栈内存and so on )

内存分为五个模块,我们常用的int在内存开辟空间,其实就是,在内存呢的栈区开辟了空间byte为4.

3.1 栈区(stack)(未完待续.....)

  1. 先进后出(filo模式),即电梯,弹夹

  2. 表现形式为倒扣水杯,口朝下(上方闭口为栈底,开口处为栈顶,先进为高地址,反之为底)

  3. 未初始化的变量,会覆盖掉之前的栈帧(那么意思就是栈帧是不会立刻消失,在内存中仍有痕迹)

3.2 堆区

3.3 全局静态区

未完待续......

1. 未初始化

未完待续......

2. 已初始化

未完待续......

3.4 常量区

未完待续......

3.5 代码区

未完待续......

四.基本数据类型的转换

  1. 自动类型转换:当同意表达式中有不同类型的变量时,编译器会自动将低精度类型转换为高精度类型,然后进行运算。

  2. 强制类型转换:使用强制类型转换运算符将一种数据类型转换为另一种数据类型。

  3. 数据类型的转换不会影响数据本身的值,只是改变了数据在内存中的存储方式。

4.1 自动转换

cpp 复制代码
 int a = 5;
    float b = 2.5;
    double c = 3.5;
    // 自动类型转换
    double result = a + b + c;                // int -> float -> double,
    printf("自动类型转换结果: %f\n", result); // 输出结果为 11.000000,%f表示浮点数格式输出,默认保留6位小数

4.2 强制转换

cpp 复制代码
/*
      强制类型转换
      int -> float -> double
     */
    int d = 5;
    float e = 2.5;
    double f = 3.5;
    // 强制类型转换
    double result2 = (double)d + (double)e + (double)f; // int -> float -> double
    printf("强制类型转换结果: %f\n", result2);          // 输出结果为 11.000000,%f表示浮点数格式输出,默认保留6位小数
                                                        // 再转为int类型
    int result3 = (int)result2;                         // double -> int
    printf("强制类型转换结果: %d\n", result3);          // 输出结果为 11

4.3 数据类型的精度

高精度类型:double、float、long double

低精度类型:int、char、short、long

高转低精度类型:基本不会失去精度,数据不会丢失。

低转高精度类型:会失去精度,可能会导致数据丢失。

五. 运算符

1. 算数运算符

用于基本数学运算。

运算符 描述 示例 注意
+ 加法 a + b
- 减法 a - b
* 乘法 a * b
/ 除法 a / b 整数除法会丢弃小数部分
% 取模(余数) a % b 只能用于整数,结果符号与被除数相同
++ 自增 a++++a a = ( a + 1 )
-- 自减 a----a 同上
cpp 复制代码
#include <stdio.h>

// 实型是指小数的类型,整型是指整数的类型,字符型是指字符的类型
float f = 10.0; // 浮点型变量,表示小数类型
// 整形是指整数的类型,实型是指小数的类型,字符型是指字符的类型
int i = 10; // 整型变量,表示整数类型

int main(int argc, char const *argv[])
{
    // 算数运算符
    // 正数负数
    int a = 10;
    int b = -10;
    printf("a = %d, b = %d\n", a, b);

    // 基本算数运算符
    int c = 20;
    int d = 10;
    float f1 = 5.5;
    float f2 = 10.5;

    printf("c + d = %d\n", c + d);  // 加法
    printf("c - d = %d\n", c - d);  // 减法
    printf("c * d = %d\n", c * d);  // 乘法
    printf("c / d = %d\n", c / d);  // 除法,除数不能为0
    printf("c %% d = %d\n", c % d); // 取余,此处需要用%%来转义%,因为%是格式化输出的标志,取小数点后1位的值,不能对0取余,除数不能为0

    // 1. 先乘除后加减
    printf("c + d * 2 = %d\n", c + d * 2);
    // 2. 先乘除后加减,括号内的优先级最高
    printf("c + d * 2 = %d\n", (c + d) * 2); // 先加减后乘除,括号内的优先级最高
    // 3. 两个整数相除,结果是整数,取整
    printf("c / d = %d\n", c / d); // 结果是整数,取整
    // 4. 两个浮点数相除,结果是浮点数,保留小数点后6位
    printf("f1 / f2 = %f\n", f1 / f2); // 结果是浮点数,保留小数点后6位
    // 5. 整数和浮点数相除,结果是浮点数,保留小数点后6位
    printf("c / f1 = %f\n", c / f1); // 结果是浮点数,保留小数点后6位
    // 6. 取余运算符%只能用于整数之间的运算,不能用于浮点数之间的运算
    // printf("f1 %% f2 = %f\n", f1 % f2); // 错误,取余运算符%只能用于整数之间的运算,不能用于浮点数之间的运算
    // 7. 对负数取余,正整数的余数是正数,负整数的余数是负整数
    printf("b %% d = %d\n", b % d); // 结果是负整数,取余运算符%只能用于整数之间的运算,不能用于浮点数之间的运算

        return 0;
}

2. 比较运算符

比较运算符:==、!=、>、<、>=、<=

==:相等运算符,判断两个值是否相等(与赋值运算符=不同)

!=:不相等运算符,判断两个值是否不相等

>: 大于运算符,判断左边的值是否大于右边的值

<: 小于运算符,判断左边的值是否小于右边的值

>=:大于等于运算符,判断左边的值是否大于或等于右边的值

<=:小于等于运算符,判断左边的值是否小于或等于右边的值

注意:比较运算符的结果是布尔值(0或1),0表示假,1表示真。


用于比较两个值,返回 1(真)或 0(假)。

运算符 描述 示例 注意
== 等于 a == b 不要与 = 混淆
!= 不等于 a != b
> 大于 a > b
< 小于 a < b
>= 大于等于 a >= b
<= 小于等于 a <= b
cpp 复制代码
#include <stdio.h>
int main(int argc, char const *argv[])
{
    /*
    比较运算符:==、!=、>、<、>=、<=

    ==:相等运算符,判断两个值是否相等(与赋值运算符=不同)
    !=:不相等运算符,判断两个值是否不相等
    >: 大于运算符,判断左边的值是否大于右边的值
    <: 小于运算符,判断左边的值是否小于右边的值
    >=:大于等于运算符,判断左边的值是否大于或等于右边的值
    <=:小于等于运算符,判断左边的值是否小于或等于右边的值
    注意:比较运算符的结果是布尔值(0或1),0表示假,1表示真。
    */

    int a = 10, b = 20;
    printf("a == b: %d\n", a == b); // 相等(==)运算符 返回值0,表示假
    printf("a != b: %d\n", a != b); // 不相等(!=)运算符 返回值1,表示真
    printf("a > b: %d\n", a > b);   // 大于(>)运算符 返回值0,表示假
    printf("a < b: %d\n", a < b);   // 小于(<)运算符 返回值1,表示真
    printf("a >= b: %d\n", a >= b); // 大于等于(>=)运算符 返回值0,表示假
    printf("a <= b: %d\n", a <= b); // 小于等于(<=)运算符 返回值1,表示真.

    /*
      比较运算符自身的优先级低于算术运算符和位运算符,但高于逻辑运算符。
      例如:在表达式 a + b > c && d < e 中,首先计算 a + b 和 d < e,然后再进行逻辑与运算。
     */
    int c = 30, d = 40, e = 50;
    printf("a + b > c && d < e: %d\n", (a + b > c) && (d < e)); // 返回值1,表示真

    /*
        算数运算符的优先级高于比较运算符,但低于逻辑运算符。
        例如:在表达式 a + b > c && d < e 中,首先计算 a + b 和 d < e,然后再进行逻辑与运算。
     */
    printf("a + b > c && d < e: %d\n", (a + b > c) && (d < e)); // 返回值1,表示真

    return 0;
}

3. 赋值运算符

赋值运算符:=、+=、-=、*=、/=、%=、&=、|=、^=、<<=、>>=

=: 赋值运算符,将右边的值赋给左边的变量

+=: 加法赋值运算符,将右边的值加到左边的变量上,并将结果赋给左边的变量

-=: 减法赋值运算符,将右边的值减去左边的变量,并将结果赋给左边的变量

*=: 乘法赋值运算符,将右边的值乘以左边的变量,并将结果赋给左边的变量

/=: 除法赋值运算符,将左边的变量除以右边的值,并将结果赋给左边的变量

%=: 取余赋值运算符,将左边的变量除以右边的值,并将余数赋给左边的变量

&=: 按位与赋值运算符,将左边的变量和右边的值进行按位与运算,并将结果赋给左边的变量

|=: 按位或赋值运算符,将左边的变量和右边的值进行按位或运算,并将结果赋给左边的变量

^=: 按位异或赋值运算符,将左边的变量和右边的值进行按位异或运算,并将结果赋给左边的变量

<<=:左移赋值运算符,将左边的变量左移右边的位数,并将结果赋给左边的变量

>>=:右移赋值运算符,将左边的变量右移右边的位数,并将结果赋给左边的变量

注意:赋值运算符,会修改变量的原始值

用于给变量赋值。

运算符 描述 示例 等价于
= 简单赋值 a = 5
+= 加后赋值 a += 3 a = a + 3
-= 减后赋值 a -= 2 a = a - 2
*= 乘后赋值 a *= 4 a = a * 4
/= 除后赋值 a /= 2 a = a / 2
%= 取模后赋值 a %= 3 a = a % 3
cpp 复制代码
#include <stdio.h>
int main(int argc, char const *argv[])
{
    /*
     赋值运算符:=、+=、-=、*=、/=、%=、&=、|=、^=、<<=、>>=
         =: 赋值运算符,将右边的值赋给左边的变量
        +=: 加法赋值运算符,将右边的值加到左边的变量上,并将结果赋给左边的变量
        -=: 减法赋值运算符,将右边的值减去左边的变量,并将结果赋给左边的变量
        *=: 乘法赋值运算符,将右边的值乘以左边的变量,并将结果赋给左边的变量
        /=: 除法赋值运算符,将左边的变量除以右边的值,并将结果赋给左边的变量
        %=: 取余赋值运算符,将左边的变量除以右边的值,并将余数赋给左边的变量
        &=: 按位与赋值运算符,将左边的变量和右边的值进行按位与运算,并将结果赋给左边的变量
        |=: 按位或赋值运算符,将左边的变量和右边的值进行按位或运算,并将结果赋给左边的变量
        ^=: 按位异或赋值运算符,将左边的变量和右边的值进行按位异或运算,并将结果赋给左边的变量
        <<=:左移赋值运算符,将左边的变量左移右边的位数,并将结果赋给左边的变量
        >>=:右移赋值运算符,将左边的变量右移右边的位数,并将结果赋给左边的变量
        注意:赋值运算符,会修改变量的原始值
    */

    // 赋值运算符,将右边的值赋给左边的变量

    // 复合赋值运算符,将右边的值加到左边的变量上,并将结果赋给左边的变量
    double a = 888888.88;
    a += 11.11;
    printf("a += 11.11: %f\n", a); // 888899.99

    // 等价于i= i%(j-2),=后面是一个整体
    int i = 10, j = 20;
    i += i % (j - 2);                     // i = i + i % (j - 2)
    printf("i += i %% (j - 2): %d\n", i); // 10 + 10 % (20 - 2) = 10 + 10 % 18 = 10 + 10 = 20

    // 比较运算符的优先级低于算术运算符和位运算符,但高于逻辑运算符。
    printf("i + j > i && i < j: %d\n", (i + j > i) && (i < j)); // 意思是 i + j > i 和 i < j 同时成立才返回真,i + j > i 的值为真,i < j 的值为假,所以结果为假
    // 先乘除后加减,括号内的优先级最高

    return 0;
}

4. 自增运算符

自增运算符:++,自减运算符:--

++: 自增运算符,将变量的值加1,并将结果赋给变量本身

--: 自减运算符,将变量的值减1,并将结果赋给变量本身

注意:自增和自减运算符的优先级高于赋值运算符,但低于算术运算符和位运算符。

注意:不能用于常量和表达式,只能用于变量。

注意:自增和自减运算符可以放在变量的前面或后面,前缀和后缀的区别在于自增和自减的顺序。


运算符 描述 示例 区别
a++ 后置自增 int b = a++; 先使用 a 的值,再自增
++a 前置自增 int b = ++a; 先自增 a,再使用新值
a-- 后置自减 int b = a--; 同上逻辑
--a 前置自减 int b = --a; 同上逻辑
cpp 复制代码
#include <stdio.h>
int main(int argc, char const *argv[])
{
    /*
    自增运算符:++,自减运算符:--
        ++: 自增运算符,将变量的值加1,并将结果赋给变量本身
        --: 自减运算符,将变量的值减1,并将结果赋给变量本身
        注意:自增和自减运算符的优先级高于赋值运算符,但低于算术运算符和位运算符。
        注意:不能用于常量和表达式,只能用于变量。
        注意:自增和自减运算符可以放在变量的前面或后面,前缀和后缀的区别在于自增和自减的顺序。
    */

    // 自增运算符,将变量的值加1,并将结果赋给变量本身 (a++)
    int a = 10;
    int b = 20;
    a++; // a = a + 1; // 先赋值后自增
    ++b; // b = b + 1; // 先自增后赋值
    --b
        printf("a++: %d\n", a); // 11
    printf("--b: %d\n", b);
    printf("++b: %d\n", b); // 21

    // 自减运算符,将变量的值减1,并将结果赋给变量本身 (a--)
    int c = 10;
    int d = 20;
    c--;                    // c = c - 1; // 先赋值后自减
    --d;                    // d = d - 1; // 先自减后赋值
    printf("c--: %d\n", c); // 9
    printf("--d: %d\n", d); // 19

    // 自增和自减运算符高于算数运算符和位运算符,但低于赋值运算符。
    int e = 3 * ++b;              // 先处理++b,b = 21 + 1 = 22,然后再处理3*22 = 66
    printf("e = 3*++b: %d\n", e); // 66

    return 0;
}

5. 逻辑运算符

逻辑运算符:&&、||、!

逻辑与:&&,当且仅当两个操作数都为真时,结果才为真。

逻辑或:||,当至少有一个操作数为真时,结果为真

逻辑非:!,对操作数取反,真变假,假变真。

逻辑运算符的优先级:! > && > ||


用于组合或反转布尔表达式。

运算符 描述 示例 规则(短路求值)
&& 逻辑与 a && b 全为真则真,否则假
` ` 逻辑或
! 逻辑非 !a 反转布尔值
cpp 复制代码
#include <stdio.h>
int main(int argc, char const *argv[])
{
    /*
    逻辑运算符:&&、||、!
    逻辑与:&&,当且仅当两个操作数都为真时,结果才为真。
    逻辑或:||,当至少有一个操作数为真时,结果为真
    逻辑非:!,对操作数取反,真变假,假变真。
    逻辑运算符的优先级:! > && > ||

    */
    // 逻辑与运算符:&&
    //短路机制:如果第一个操作数为假,则不计算第二个操作数
    int a = 1, b = 2, c = 3;
    // 逻辑与运算符的优先级高于赋值运算符,所以先计算逻辑与运算符
    printf(a > 0 && b > 0 && c > 0 ? "a、b、c都是正数\n" : "a、b、c不是正数\n");

    // 逻辑或运算符:||
    //短路机制:如果第一个操作数为真,则不计算第二个操作数

    printf(a > 0 || b > 0 || c > 0 ? "a、b、c至少有一个是正数\n" : "a、b、c都不是正数\n");

    // 逻辑非运算符:!
    printf(a != 0 ? "a不是0\n" : "a是0\n"); // a不是0

    // 逻辑运算符的优先级:! > && > ||
    // 逻辑与运算符的优先级高于逻辑或运算符,所以先计算逻辑与运算符
    if (a > 0 && b > 0 || c > 0)
    {
        printf("a、b、c至少有一个是正数\n");
    }
    else
    {
        printf("a、b、c都不是正数\n");
    }

    return 0;
}

6. 条件运算符(三目运算符)

唯一的三元运算符,用于简化条件判断。

语法 描述
条件 ? 表达式1 : 表达式2 若条件为真,返回表达式1,否则返回表达式2
cpp 复制代码
#include <stdio.h>
int main(int argc, char const *argv[])
{
    /*
    条件运算符:?:,也称为三目运算符,语法格式为:条件表达式 ? 表达式1 : 表达式2
    条件表达式为真时,返回表达式1的值;条件表达式为假时,返回表达式2的值。

    attention:
    条件运算符的优先级低于赋值运算符,所以在使用条件运算符时,要注意括号的使用。
    条件运算符的优先级:?: > = > + - > * / %
    三目运算符返回值的类型由表达式1和表达式2决定,如果表达式1和表达式2的类型不同,则返回值的类型为更高的类型。
    条件运算符的返回值可以作为赋值语句的右值,也可以作为函数的参数。

    */

    // 条件运算符
    int a = 1, b = 2, c = 3;
    (a > b) ? printf("a大于b\n") : printf("a小于等于b\n");

    // 条件运算符的优先级低于赋值运算符,所以要加括号
    c = (a > b) ? a : b; // 如果a大于b,则b等于a,否则b等于b
    printf("b = %d\n", b);


    return 0;
}

7. 逗号运算符

用于分隔多个表达式,返回最后一个表达式的值。

语法 描述
表达式1, 表达式2 依次执行表达式1和表达式2,返回表达式2的值
cpp 复制代码
#include <stdio.h>
int main(int argc, char const *argv[])
{
    /*
    逗号运算符:,,逗号运算符的优先级最低,逗号运算符的左操作数和右操作数都要计算,返回右操作数的值。

    */
    int a = 3;
    int b = (a++, ++a, a + 5); // 逗号运算符的优先级最低,逗号运算符的左操作数和右操作数都要计算,返回右操作数的值。
    printf("a = %d\n", a);     // a = 5
    printf("b = %d\n", b);     // b = 10

    int a = 3;
    int b = ((a + a), a + 5);
    printf("a = %d\n", a);
    printf("b = %d\n", b);

    return 0;
}

8. 运算符优先级(未完待续.....)

不必理会

cpp 复制代码
#include <stdio.h>
int main(int argc, char const *argv[])
{
    /*
      逗号<赋值<逻辑(不包含非)<比较<算数
    */

    // 案例一
    int x = 0, y = 1;
    int res = x++ != !y;


    return 0;
}

9. 位运算符

按位取反:

其余的暂时不用进行描述,简单易懂,在这里只对按位取反进行描述。

1. 补码的核心定义

在计算机中,所有整数均以补码形式存储,补码规则如下:

  • 正数:补码 = 原码(二进制直接表示,符号位为0)。

  • 0111 1111 1111 1111 1111 1111 1111 1111

  • 负数:补码 = 原码取反(反码) + 1(符号位为1)。

  • 1000 0000 0000 0000 0000 0000 0000 0000


2. 按位取反 (~) 的本质
  • 操作对象:直接对整数的补码逐位取反(包括符号位)。

  • 结果类型:结果仍为补码,需转换回原码才能得到十进制值。

3. 按位取反步骤(公式为~ a = -(a + 1))
  • 取补码 (正数的补码为原码)

  • 对补码进行取反(0为1,1为0)

  • 取反过的补码转原码(负数的转换规则)

  • 补码 → 原码(符号位为1,说明是负数)

  • 符号位不变,其他位取反 → 得到原码

  • 算出结果。

cpp 复制代码
#include <stdio.h>
int main(int argc, char const *argv[])
{
    /*
    位运算
    原码:符号位+绝对值
     0:0000 0000 0000 0000 0000 0000 0000 0000
     1:0000 0000 0000 0000 0000 0000 0000 0001
    -1:1000 0000 0000 0000 0000 0000 0000 0001
    -2:1000 0000 0000 0000 0000 0000 0000 0010
     4:0000 0000 0000 0000 0000 0000 0000 0100 
    反码:符号位+绝对值的反码
     3:0000 0000 0000 0000 0000 0000 0000 0011
    -3:1111 1111 1111 1111 1111 1111 1111 1100
    补码:符号位+绝对值的补码
     3:0000 0000 0000 0000 0000 0000 0000 0011
    -3:1000 0000 0000 0000 0000 0000 0000 0011

    位运算是c语言中一种直接对二进制位进行操作的运算符,位运算符有:
    按位与:&,按位或:|,按位异或:^,按位取反:~,左移:<<,右移:>>。

    */

    // 1. 按位与:& (二进制对应位都为1时候,新结果二进制对应位才为1,否则为0)
    int a = 3;                 // 0011
    int b = 5;                 // 0101
    int c = a & b;             // 0001
    printf("a & b = %d\n", c); // 1
    /*
    示例
    */
    int a1 = 4;                   // 0100
    int b1 = 5;                   // 0101
    int c1 = a1 & b1;             // 0100
    printf("a1 & b1 = %d\n", c1); // 4
    // 0100 & 0101 = 0100

    // 2. 按位或:| (两个都为0的时候才为0,否则为1)
    c = a | b;                 // 0111
    printf("a | b = %d\n", c); // 7
     /*
    示例
        int a1 = 4;    0100             
        int b1 = 5;    0101           
    */
    c1 = a1 | b1;  // 0101
    printf("a1 | b1 = %d\n", c1); // 5


    // 3. 按位异或:^ (两个相同为0,不同为1)
    c = a ^ b;                 // 0110
    printf("a ^ b = %d\n", c); // 6
       /*
    示例
        int a1 = 4;    0100             
        int b1 = 5;    0101           
    */
    c1 = a1 ^ b1;  // 0001
    printf("a1 ^ b1 = %d\n", c1); // 1

    // 4. 按位取反:~ 
    //公式为~a = -(a + 1 );
    c = ~a;                 // 1100 ,将1100转为十进制,即1100-1=1100-1=-4
    printf("~a = %d\n", c); // -4,注意:按位取反是对补码进行操作的,所以结果是负数
         /*
    示例
        int a1 = 4;    0100   
        利用公式可得~a为-5
    */
    c1 = ~a1;  // 1011 = -5
    printf("~a1 = %d\n", c1); // -5,注意:按位取反是对补码进行操作的,所以结果是负数

    // 5. 左移:<< (左移n位,相当于乘以2^n)
    c = a << 1;                 // 原本为0011,左移之后为0110
    printf("a << 1 = %d\n", c); // 6


    // 6. 右移:>> (右移n位,相当于除以2^n)
    c = a >> 1;                 // 原本为0011,0001
    printf("a >> 1 = %d\n", c); // 1

    // 7.位运算场景,例如:交换两个数的值 (两个相同为0,不同为1)
    int x = 3, y = 5;
    printf("x = %d, y = %d\n", x, y); // x = 3, y = 5,交换前
    x = x ^ y;                        // x = 3 ^ 5 = 6,5 = 0101,3 = 0011,结果为0110
    y = x ^ y;                        // y = 6 ^ 5 = 3,6 = 0110,5 = 0101,结果为0011
    x = x ^ y;                        // x = 6 ^ 3 = 5,6 = 0110,3 = 0011,结果为0101
    printf("x = %d, y = %d\n", x, y); // x = 5, y = 3,交换成功

    return 0;
}
相关推荐
炯哈哈18 分钟前
【上位机——MFC】运行时类信息机制
开发语言·c++·mfc·上位机
好易学·数据结构43 分钟前
可视化图解算法:二叉树的最大深度(高度)
数据结构·算法·二叉树·最大高度·最大深度·二叉树高度·二叉树深度
小鹿鹿啊1 小时前
C语言编程--15.四数之和
c语言·数据结构·算法
rigidwill6662 小时前
LeetCode hot 100—最长有效括号
数据结构·c++·算法·leetcode·职场和发展
T.Ree.2 小时前
【数据结构】_树和二叉树
c语言·开发语言·数据结构
夜夜敲码2 小时前
C语言教程(十五):C 语言函数指针与回调函数详解
c语言·开发语言
Cao1234567893212 小时前
判断是否为闰年(C语言)
c语言·开发语言
是发财不是旺财3 小时前
跟着deepseek学golang--认识golang
开发语言·后端·golang
Bruce_Liuxiaowei3 小时前
基于Python+Flask的MCP SDK响应式文档展示系统设计与实现
开发语言·python·flask·mcp
chuxinweihui3 小时前
数据结构——栈与队列
c语言·开发语言·数据结构·学习·算法·链表