C语言操作符详解(上)

简介: C语言操作符详解(上)

前言

在C语言中,C标准提供了丰富的操作符,被用来对数据进行操作和计算,常用数学计算、比较、逻辑运算等操作。操作符是编程语言中非常重要的一部分,它们可以使程序更加简洁、高效,同时也可以增强代码的可读性和可维护性。本文将详细系统介绍C语言操作符,希望能帮读者全面理解C语言操作符!

1. 算术操作符

算术操作符分为以下5种,虽然简单,但还是有一些细节需要注意。

(+)、(-)、(*)、(/)、(%)

  • 除了%(取余)操作符之外,其他几个操作符可以作用于整数和浮点数。
  • 对于/操作符,如果两个操作数都为整数,执行整数除法。而只要有一个浮点数就执行浮点数除法。
  • %操作符的两个操作数必须为整数。返回的是整除之后的余数。

2. 移位操作符

在C语言中,移位操作符分为以下两种

  • <<左移操作符
  • >>右移操作符

相关知识补充:

#include <stdio.h>
int main()
{
  int a = 15;
  //00000000000000000000000000001111 - 原码
  //00000000000000000000000000001111 - 反码
  //00000000000000000000000000001111 - 补码

  int b = -15;
  //10000000000000000000000000001111 - 原码
  //11111111111111111111111111110000 - 反码
  //11111111111111111111111111110001 - 补码
  return 0;
}

Tips:

  • 位移操作符的操作数只能是整数。
  • 计算机能处理的是二进制的信息。而整数的二进制表示形式分为三种:原码、反码、补码。
  • 正整数的原码、反码、补码是相同的。负整数的反码是原码符号位不变,其他未按位取反、反码在加1就得到补码。

2.1 左移操作符(<<)

移位规则:

左边抛弃、右边补0

例子:

#include <stdio.h>
int main()
{
  int a = 15;
  //00000000000000000000000000001111 - (a)补码

  int b = a << 1;
  //对a的补码右移一位得到b的补码,左边抛弃,右边补0
  //00000000000000000000000000011110 - (b)补码
  //00000000000000000000000000011110 - (b)反码
  //00000000000000000000000000011110 - (b)原码
  
  printf("b=%d\n", b); //b得值为:30
  return 0;
}

2.2 右移操作符(>>)

移位规则:

C语言中,右移运算分为两种:

  1. 逻辑右移:左边用0填充,右边丢弃。
    2. 算术右移:左边用原该值的符号位填充,右边丢弃。

上述两种运算方式,C语言没有明确规定到底是算术右移还是逻辑右移。但一般编译器上采用的是算术右移。

例子:

int main()
{
  int a = -15;
  //10000000000000000000000000001111 - 原码
  //11111111111111111111111111110000 - 反码
  //11111111111111111111111111110001 - 补码

  int b = a >> 1;
  //左边用原该值的符号位填充,右边丢弃
  //11111111111111111111111111111000 - 补码
  //11111111111111111111111111110111 - 反码
  //10000000000000000000000000001000 - 原码
  
  printf("b=%d\n", b); //b的值为:-8
  return 0;
}

警告:

对于移位运算符,不要移动负位数,这个行为C标准未定义的。

int num=10;
num>>-1; //error

3. 位操作符

在C语言中,位操作符有以下三种:&(按位与)、|(按位或)、^(按位异或)。

Tips:位操作符的操作数必须是整数,同时也是操作二进制位的。

3.1 按位与(&)

& — 补码对应的二进制位有0则为0,两个同时为1才是1.

例子:

int main()
{
  int a = 3;
  //00000000000000000000000000000011 - 补码
  int b = -5;
  //10000000000000000000000000000101 - 原码
  //11111111111111111111111111111010 - 反码
  //11111111111111111111111111111011 - 补码

  int c = a & b;
  //&补码对应的二进制位有0则为0,两个同时为1才是1.
  //00000000000000000000000000000011 - 补码(a)
  //11111111111111111111111111111011 - 补码(b)
  //00000000000000000000000000000011 - 补码(c)

  printf("c=%d\n", c); //c的值为:3
  return 0;
}

3.2 按位或(|)

| — 补码对应的二进制位有1则为1,两个同时为0才是0.

例子:

int main()
{
  int a = 3;
  //00000000000000000000000000000011 - 补码
  int b = -5;
  //10000000000000000000000000000101 - 原码
  //11111111111111111111111111111010 - 反码
  //11111111111111111111111111111011 - 补码

  int c = a | b;
  //&补码对应的二进制位有1则w为1,两个同时为0才是0.
  //00000000000000000000000000000011 - 补码(a)
  //11111111111111111111111111111011 - 补码(b)
  //11111111111111111111111111111011 - 补码(c)

  //11111111111111111111111111111010 - 反码(c)
  //10000000000000000000000000000101 - 原码(c)

  printf("c=%d\n", c);//c的值为:-5
  return 0;
}

3.4 按位异或(^)

|^— 补码对应的二进制位不相同则为1,两个相同则为0.

int main()
{
  int a = 3;
  //00000000000000000000000000000011 - 补码
  int b = -5;
  //10000000000000000000000000000101 - 原码
  //11111111111111111111111111111010 - 反码
  //11111111111111111111111111111011 - 补码

  int c = a ^ b;
  //^ 补码对应的二进制位不相同则为1,两个同时为1或0时才是0.

  //00000000000000000000000000000011 - 补码(a)
  //11111111111111111111111111111011 - 补码(b)
  //11111111111111111111111111111000 - 补码(c)

  //11111111111111111111111111110111 - 反码(c)
  //10000000000000000000000000001000 - 原码(c)

  printf("c=%d\n", c);//c的值为:-8
  return 0;
}

3.5 一道变态的面试题

不能创建临时变量(第三个变量),实现两个数的交换。

int main()
{
  int a = 10;
  int b = 20;
  //交换,按位异或是支持交换律的
  a = a ^ b;
  b = a ^ b;
  a = a ^ b;
  printf("a=%d b=%d\n", a, b);
  return 0;
}
  • 按位异或是支持交换律的。

4. 关系操作符

这些关系运算符比较简单,没什么可介绍的。

5. 单目操作符

单目操作符介绍:

5.1 单目操作符(!)

(!)逻辑反操作,顾名思义就是把真变成假,把假变成真。

int main()
{
  int flag = 0;//下面两种判断flag为0就执行语句的方法,效果一样
  //方法1:
  if (flag == 0)
  {
    //语句;
  }

  //方法2:flag为0,则为假。!flag则为真,执行语句
  if (!flag)
  {
    //语句;
  }
  return 0;
}

5.2 单目操作符(~)

单目操作符(~)是按补码二进制位全部取反.(包括符号位)

例子:

int main()
{
  int a = 0;
  //00000000000000000000000000000000 - 补码

  int b = ~a;
  //~a--对a的补码全部取反
  //11111111111111111111111111111111 - 补码
  //11111111111111111111111111111110 - 补码
  //10000000000000000000000000000001 - 原码

  printf("%d\n", b); //b的值位:-1
  return 0;
}

5.3 单目操作符(&、*)

单目操作符(&、*)都运用于指针。

int main()
{
  int a = 0;
  //pa是指针变量
  int* pa = &a; //&—取地址操作符—取出a的地址
  
  //解引用操作符(间接访问操作符)—通过pa中存放的地址,找到指向的空间(内容)
  *pa = 20;
  return 0;
}

5.4 单目操作符(++、–)

单目单目操作符++(- -),分为前置++(- -)和后置++(–)

前置++(–): 先++(- -),在使用。

后置++(–): 先使用,在++(- -)。

例子1:

int main()
{

  int a = 2;
  int b = --a; //前置--,先--,在使用
  //a=a-1,b=a
  printf("a=%d b=%d\n", a, b);//a,b的值都为:1 
  return 0;
}

例子2:

int main()
{
  int a = 2;
  int b = a--; //后置--,先使用,在--
  //b=a,a=a-1
  printf("a=%d b=%d\n", a, b);//a的值为1,b的值为2
  return 0;
}

前置++和后置++同理。

5.5 单目操作符(sizeof)和数组

单目操作符(sizrof)用于计算操作数的类型长度。(单位字节)

#include <stdio.h>
void test1(int arr[])
{
  printf("%d\n", sizeof(arr));
}

void test2(char ch[])
{
  printf("%d\n", sizeof(ch));
}
int main()
{
  int arr[10] = { 0 };
  char ch[10] = { 0 };
  printf("%d\n", sizeof(arr));//10X4
  printf("%d\n", sizeof(ch)); //10X1
  test1(arr);
  test2(ch);
  return 0;
}

运行结果(x64环境下):

上述前两个结果毋庸置疑,但为什么后两个都是8byte呢?

上面调用函数test1()和test2(),传过去的是指针。C语言中,在64位机器上(x64),指针大小为8byte;在32位机器上(x86)上,指针大小为4byte.

6. 逻辑操作符

C语言中,逻辑操作符分为以下两种:

&&—逻辑与

||—逻辑或

简单来说:逻辑与(&&)就是两个同时城里时为真,否则为假;逻辑或(||)则是只要有一个成立则为真,否则为假。

Tips:

  • &&操作符,左边为假,右边就不计算了。
  • ||操作符,左边为真,右边就不用计算了。

例子1:

#include <stdio.h>
int main()
{
  int i = 0, a = 0, b = 2, c = 3, d = 4;
  //后置++,先使用a,后再执行++
  //&&操作符,左边为假,右边就不计算了
  //a先使用,为0,则为假。所以&&后面所有运算都不执行
  i = a++ && ++b && d++;
  //结果:a=1 b=2 c=3 d=4
  printf("a=%d b=%d c=%d d=%d\n", a, b, c, d);
  return 0;
}

例子:

#include <stdio.h>
int main()
{
  int i = 0, a = 0, b = 2, c = 3, d = 4;
  //||操作符,左边为真,右边就不用计算了。
  //使用b时,b先++后使用,别的值为3,非0为真。所以后面所有运算都不进行
  i = a++ || ++b || d++;
  //结果:a=1 b=3 c=3 d=4
  printf("a=%d b=%d c=%d d=%d\n", a, b, c, d);
  return 0;
}

7. 条件操作符

C语言中,条件操作符如下:表达式exp1为真,则执行表达式exp2,否则执行表达式exp3.

exp1 ? exp2 : exp3

例子:

int main()
{
  int a = 0;
  int b = 0;
  //a为0小于5,执行表达式xep3。所以b=-3
  b = (a > 5) ? 3 : -3;
  return 0;
}

8. 逗号表达式

C语言中,逗号表达式就是:用逗号隔开的多个表达式。

exp1, exp2, exp3, …expN

例子:

int main()
{
  int a = 1;
  int b = 2;
  int c = (a > b, a = b + 10, a, b = a + 1);//逗号表达式
  printf("c=%d\n", c);//结果为:c=13
  return 0;
}

那在上述代码中,为什么c的值最终为13呢?

  • 逗号表达式中,从左到右依次计算。整个表达式的结果为最后一个表达式的结果。

例子:

int d=1;
if(a=a+1,c=a/2,d>0)//d大于0,结果为真,执行if后的语句块
{
}

9. 下标引用、函数调用和结构成员

9.1 [ ] 下标引用操作符

在C语言中,下标引用的操作数为:一个数组名 + 一个索引值(两个操作数满足交换律)

例子:

int main()
{
  int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };//数组的起始是有下标的,下标从0开始
  //          0 1 2 3 4 5 6 7 8 8 9
  printf("%d\n", arr[2]);// [] 下标引用操作符,arr和2是两个操作数
  printf("%d\n", 2[arr]);
  return 0;
}
  • 上述代码中2[arr]虽然看起来奇怪,但却是成立的,和arr[2]等价。[ ]和+一样,都是操作数,和两个操作数的前后顺序无关。

9.2 ( ) 函数调用操作符

( ) 函数调用操作符可以接受一个或多个操作数:第一个操作数是函数名,剩余操作数就是传递给函数的参数。

例子:

#include <stdio.h>
#include <string.h>
int Add(int x, int y)
{
  return x + y;
}

int main()
{
  int len = strlen("abc");//( )函数调用操作符
  //()的操作数是:strlrn 和 "abc
  printf("%d\n", len);

  int c = Add(3, 5);//( ) 函数调用操作符
  //()的操作数是:Add 和3 5
  //对于函数调用操作符来说,至少有一个操作数

  printf("%d\n", c);
  return 0;
}

9.3 访问一个结构的成员

在C语言中,访问一个结构的成员有两种方式:

. — 结构体 . 成员名

-> — 结构体 -> 成员名

例子1:

#include <stdio.h>
//定义一个struct Book类型
struct Book
{
  char name[30];
  char author[20];
  float price;
};

int main()
{
  struct Book b= { "C primer Plus","Stephen Prate",47.8f };//创建一个变量b
  //结构体.成员名,答应相关信息
  printf("%s %s %.1f\n", b.name, b.author, b.price);
  return 0;
}

例子2:

struct Book
{
  char name[30];
  char author[20];
  float price;
};
//定义过程
void print(struct Book* b)
{
  //结构指针->成员名,访问成员
  printf("%s %s %.1f\n", b->name, b->author, b->price);
}

int main()
{
  struct Book b= { "C primer Plus","Stephen Prate",47.8f };//创建一个变量b
  //封装print()函数,打印信息
  print(&b);
  return 0;
}

10. 结尾

本篇文章到此就结束了!在C语言操作符详解(上)已经将C语言中所有操作全部详细系统的介绍完了,接下来将在C语言操作符详解(下)中详细介绍编译器执行这些代码背后所做的事情、操作符优先级、结合性以及求值顺序!

创作不易,如果对你有帮助,记得点赞加关注哦!感谢您的支持,同时也欢迎读者发表自己的见解!

C语言操作符详解(下)


相关文章
|
14天前
|
存储 网络协议 C语言
【C语言】位操作符详解 - 《开心消消乐》
位操作符用于在位级别上进行操作。C语言提供了一组位操作符,允许你直接操作整数类型的二进制表示。这些操作符可以有效地处理标志、掩码、位字段等低级编程任务。
58 8
|
14天前
|
C语言
【C语言】逻辑操作符详解 - 《真假美猴王 ! 》
C语言中有三种主要的逻辑运算符:逻辑与(`&&`)、逻辑或(`||`)和逻辑非(`!`)。这些运算符用于执行布尔逻辑运算。
55 7
|
4月前
|
存储 C语言 索引
【C语言篇】操作符详解(下篇)
如果某个操作数的类型在上⾯这个列表中排名靠后,那么⾸先要转换为另外⼀个操作数的类型后执⾏运算。
81 0
|
4月前
|
程序员 编译器 C语言
【C语言篇】操作符详解(上篇)
这是合法表达式,不会报错,但是通常达不到想要的结果, 即不是保证变量 j 的值在 i 和 k 之间。因为关系运算符是从左到右计算,所以实际执⾏的是下⾯的表达式。
287 0
|
2月前
|
存储 缓存 C语言
【c语言】简单的算术操作符、输入输出函数
本文介绍了C语言中的算术操作符、赋值操作符、单目操作符以及输入输出函数 `printf` 和 `scanf` 的基本用法。算术操作符包括加、减、乘、除和求余,其中除法和求余运算有特殊规则。赋值操作符用于给变量赋值,并支持复合赋值。单目操作符包括自增自减、正负号和强制类型转换。输入输出函数 `printf` 和 `scanf` 用于格式化输入和输出,支持多种占位符和格式控制。通过示例代码详细解释了这些操作符和函数的使用方法。
45 10
|
2月前
|
存储 编译器 C语言
【C语言】简单介绍进制和操作符
【C语言】简单介绍进制和操作符
176 1
|
2月前
|
存储 编译器 C语言
初识C语言5——操作符详解
初识C语言5——操作符详解
185 0
|
4月前
|
C语言
C语言操作符(补充+面试)
C语言操作符(补充+面试)
46 6
|
4月前
|
存储 编译器 C语言
十一:《初学C语言》— 操作符详解(上)
【8月更文挑战第12天】本篇文章讲解了二进制与非二进制的转换;原码反码和补码;移位操作符及位操作符,并附上多个教学代码及代码练习示例
62 0
十一:《初学C语言》—  操作符详解(上)
|
5月前
|
C语言
五:《初学C语言》— 操作符
本篇文章主要讲解了关系操作符和逻辑操作符并附上了多个代码示例
45 1
五:《初学C语言》—  操作符