指令系统的每一条指令都有一个操作符,它表示该指令应进行什么样性质的操作,不同的指令用操作符这个字段的不同编码来表示,每个编码分别代表一种指令。这篇文章主要给大家介绍了关于C语言中操作符的相关资料,需要的朋友可以参考一下。

目录

算术操作符

移位操作符

位操作符

关于位操作符和移位操作符的应用示例:

赋值操作符

单目操作符

关系操作符

逻辑操作符

条件操作符,(三目操作符)

逗号表达式

下标引用操作符

函数调用操纵符

隐式类型转换

操作符的属性

操作符应用实例:

算术操作符

主要是 ( +   -   *   /    %) 五种算数操作符。

算术操作符是比较简单的操作符,包括加减乘除(+  -  *  /)取模(%),加减乘和数学中的加减乘一样,而两个数相除我们得到的是它们的商的整数部分,取模(%)得到的是它们的余数

  • +  加法
  • -   减法
  • *   乘法
  • /   除法(取商)  7 / 2 = 3 ( …… 1)     1 / 2 --> 0
  • % 取模操作符 :计算的的整除后的余数,操作数必须为整数   7 % 2 = 1;
  1. 除了 % 操作符之外,其他的几个操作符可以作用于整数和浮点数。
  2. 对于 / 操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法。
  3. % 操作符的两个操作数必须为整数。返回的是整除之后的余数。
  4. 当除数为小数时,int类型只会截取整数部分。 6 / 2.4 = 3 (系统看成 6 / 2 = 3)

移位操作符

移位操作符涉及到整数的原反补知识:http://t.csdn.cn/HflQh

  • <<左移操作符:移动的是二进制
  • >>右移操作符:移动的是二进制
int main()
{
int a = 7;
int b = a << 1;
printf("%d\n", a);//7   111
printf("%d\n", b);//14   1110
}
//a  内存中 0000 0000 0000 0000 0000 0000 0000 0111
//b  内存中a向左移动一位 左移操作,左边丢弃,右边补0
//b  内存中 0000 0000 0000 0000 0000 0000 0000 1110   (14)
// a自身不变,b复制了a的补码再做操作。

左移操作符<<  具体规则为:

内存中向左移动一位 左移操作,左边丢弃,右边补0。

//b = -7 << 1, a = -7
//a  1111 1111 1111 1111 1111 1111 1111 1001
//b  1111 1111 1111 1111 1111 1111 1111 0010(补码)
//b  1111 1111 1111 1111 1111 1111 1111 0001(反码)
//b  1000 0000 0000 0000 0000 0000 0000 1110(原码) -14

所以无论正负,左移1,就是乘2

右移操作符
算数移位:右边丢弃,左边补原符号位
逻辑移位:右边丢弃,左边补0

是逻辑右移还是算数右移取决于编译器
基本上见过的都是算术右移。

int main()
{int a = -7;int b = a >> 1;printf("a=%d\n", a); // -7printf("b=%d", b);   // -4return 0;
}
//VS采用的是算术右移。
//对于移位运算符,不要移动负数位,也不能移动浮点数位,这是标准未定义的。

位操作符

  • & - 按(2进制)位与
  • | - 按(2进制)位或
  • ^ - 按(2进制)位异或
int main()
{int a = 3; //补码 0000 0000 0000 0000 0000 0000 0000 0011int b = -5;//原码 1000 0000 0000 0000 0000 0000 0000 0101//补码 1111 1111 1111 1111 1111 1111 1111 1011int c1 = a & b; // & : 两个同时为1才是1,否则为0int c2 = a | b; // | : 只要有1就为1,两个为0才为0int c3 = a ^ b; // ^ : 相同为0,相异为1printf("c1=%d\n", c1);  // 3printf("c2=%d\n", c2);  // -5printf("c3=%d\n", c3);  // -8return 0;
}

关于位操作符和移位操作符的应用示例:

例子1:

//不创建临时变量实现两个数的交换
//原本的方法1:(创建临时变量)
int main()
{int a = 3;int b = 5;int c = 0;c = a;a = b;b = c;return 0;
}
//不创建法2:
int main()
{int a = 3;int b = 5;int c = 0;a = a + b;b = a - b;a = a - b;return 0;
}
//因为整型的数有最大值,可能相加会溢出。
//从理论上讲是有问题的//不创建的法3
int main()
{int a = 3;int b = 5;int c = 0;a = a ^ b;b = a ^ b;a = a ^ b;return 0;
}
//在实际应用中,法1(创建临时变量)用得最广泛
//法3 只适用于 整型,处理速度较慢//两个相同的数字异或为00 ^ a = 0a ^ a = 03 ^ 3 ^ 5 = 53 ^ 5 ^ 3 = 5
//注意:异或操作符支持交换律
//所以:    a = a ^ b; b = a ^ b; a = a ^ b; -->a = 3 ^ 5  b = 3 ^ 5 ^ 5 --> 3   a = 3 ^ 5 ^ 3 = 5;
// 而且这种算法不会溢出
// 很难想,但是像加法

例子2:

//编写代码要求实现:求一个整数储存在内存中的二进制中1的个数
// ----> 求补码的二进制中1的个数// int a = 3;
// 0000 0000 0000 0000 0000 0000 0000 0011
// 2 // a & 1
// 0000 0000 0000 0000 0000 0000 0000 0011
// 0000 0000 0000 0000 0000 0000 0000 0001
//& 后 为 0000 0000 0000 0000 0000 0000 0000 0001 可以判断最后一位的是0还是1
// 只需要右移操作 第二位就变成第一位了int main()
{int a = 7;int amount = 0;for (int i = 0; i < 32; i++){if ((a & 1 )== 1)amount++;a = a >> 1;}printf("%d", amount);return 0;
}

例子3:

//编程实现:两个int(32位)整数m和n的二进制表达中,有多少个位(bit)不同?
//
//输入例子:
//
//1999 2299
//
//输出例子 : 7
#include<stdio.h>
int main()
{int a = 0;int b = 0;scanf("%d %d", &a, &b);int c = a ^ b;int count = 0;for (int i = 0; i < 32; i++){if ((c & 1) == 1)count++;c >>= 1;}printf("%d", count);return 0;
}

例子4:

//获取一个整数二进制序列中所有的偶数位和奇数位,分别打印出二进制序列
#include<stdio.h>
int main()
{                                                // 0000 0000 0000 0000 0000 0000 0000 0101 int a = 0;                                   // 1000 0000 0000 0000 0000 0000 0000 0001 scanf_s("%d", &a);int num = 1 << 30;printf("Even digit:");if (a >= 0)printf("0 ");elseprintf("1 ");for (int i = 0; i < 15; i++){int b = (a & (num >> 1))/(num>>1);printf("%d ", b);num >>= 2;}num = 1 << 30;printf("\nOdd digit: ");for (int i = 0; i < 16; i++){int b = (a & num)/num;//b = Squ2(b);printf("%d ", b);num >>= 2;}return 0;
}

例子5:

//写一个函数返回参数二进制中 1 的个数。//比如: 15    0000 1111    4 个 1
int main()
{int a = 0;scanf_s("%d", &a);int count = 0;for (int i = 0; i < 32; i++){if ((a & 1) == 1)count++;a >>= 1;}printf("count = %d", count);return 0;
}

赋值操作符

  • “ = ”
int main()
{int a = 3; //初始化a = 3;     //赋值a = x = y + 1;//连续赋值,从右往左算 y+1的值赋给x x赋给a//不建议连续赋值,无法单步进行调试,可读性较差, 建议不要用这个。return 0;
}

复合赋值符号:

  • +=
  • -=
  • *=
  • /=
  • %=
  • >>=
  • <<=
  • &=
  • |=
  • ^=

单目操作符

  • ! 逻辑反操作

    int main()
    {int flag = 3;//如果flag 为真(非0),if成立,进入条件语句if(flag){ }//如果flag 为假(0),!flag为真,if成立,进入条件语句if (!flag){ }return 0;
    }
  • -负值

  • +正值

  • &取地址

     int main(){int a = 30;printf("%p\n", &a); //取的是变量在内存中的起始地址int n = sizeof(a); //计算的是a所占内存的大小,单位是字节int * p = &a; //p 就是指针变量 存储地址return 0;
    }
    
  • sizeof ,注意:是一个操作符,不是函数。计算的是变量、数组所占内存空间的大小,而strlen 是库函数,是用来求字符串的长度。

  • “ ~ ” 二进制位取反,包括符号位

  • //eg.
    int main()
    {int a = 0;// 0000 0000 0000 0000 0000 0000 0000 0000 printf("%d\n", ~a);// 1111 1111 1111 1111 1111 1111 1111 1111 补码// 1111 1111 1111 1111 1111 1111 1111 1110 反码// 1000 0000 0000 0000 0000 0000 0000 0001 原码//     -----> -1// 把其中几位变成1 可以这一位(1 << 几位) 或1 // 把其中几位变成0 可以 0 按位与上去,其余全为1(a & ~(1<<4) ) 就可以return 0;
    }
    
  • 前置++  先++ 后使用

  • 后置++  先使用,后++

  • * 取地址操作符

    // 如 p 是存放 &a中a的地址,如果通过要通过p的地址找到a的地址,就是解引用p
    // *p  --> 通过p里面的值找到 这个地址的所在的空间,就是 a  
    void test1(int arr[])
    {printf("%d\n", sizeof(arr)); //打印了一个指针的大小 4个字节(x86)/8个字节(x64)
    }
    void test2(int ch[])
    {printf("%d\n", sizeof(ch)); //打印了一个指针的大小 4个字节(x86)/8个字节(x64)
    }
    int main()
    {int arr[10] = { 0 };char ch[10] = { 0 };printf("%d\n", sizeof(arr)); //40printf("%d\n", sizeof(ch));  //10test1(arr);test2(ch);return 0;
    }

    关系操作符

  • >

  • >=

  • <

  • <=

  • !=

  • ==

注意:赋值与判断相等的区别
注意:
int main()
{if ("abc" == "abcdefg") //字符串这样比是在比较首字符的地址{                       //需要用strcmp};return 0;
}

逻辑操作符

  • &&逻辑与
  • ||逻辑或
int main()
{int a = 3;int b = 5;int c = a && b;printf("%d\n", c);//1int d = 0;c = a && d;  //有一个0就为0printf("%d\n", c);//0c = a || b; //只要有一个为真则为真printf("%d\n", c);//1c = a || d;//1printf("%d\n", c);//1c = 0 || d;// 两个为0才为0printf("%d\n", c);//0return 0;
}

请看以下两个例子:

int main()
{                 int i = 0, a = 0, b = 2, c = 3, d = 4;//i = a++ && ++b && d++; //只有a++算了,因为先使用a为0 不用算了i = a++ || ++b || d++;  // 0 || 要算第二个,如果第二个为真,不用算了printf("a = %d\nb = %d\nc = %d\nd = %d\n", a, b, c, d);//  &&1 2 3 4     ||:1 3 3 4return 0;
}
int main()
{int i = 0, a = 1, b = 2, c = 3, d = 4;i = a++ && ++b && d++; // 无论前后置都++了// i = a++||++b||d++;  //1 为真 后面根本不用算了,算到为真就好了printf("a = %d\nb = %d\nc = %d\nd = %d\n", a, b, c, d);// &&2 3 3 5  ||:1 2 3 5return 0;
}

可以得出结论:

  • &&左边为假,右边不计算
  • ||左边为真,右边不计算

条件操作符,(三目操作符)

表达式1?表达式2:表达式3
真         算        不算 
假         不算      算

int main()
{int a = 3;int b = 0;int max = (a > b ? a : b);if (a > 3)b = 3;elseb = -3;b = (a > 3 ? 3 : -3);return 0;
}

逗号表达式

从左往右依次计算,整个表达式的结果是最后一个表达式的结果。

int main()
{int a = 3;int b = 5;int c = (a > b, a + b + 10, a, b = a + 1);//前面的计算不可以忽略return 0;
}

下标引用操作符

  • [ ]
int main()
{int arr[10] = { 0 };arr[7] = 8;   //[]为下标引用操作符 []操作数为 arr 和 7 return 0;
}
//arr[7] --->  *(arr+7) arr+7就是跳过7个元素,指向了第八个元素,就是第八个元素
// ---->*(7+arr)  ---> 7[arr]  

函数调用操纵符

  • ( )
int Add(int x, int y)
{return x + y;
}
int main()
{int a = 10;int b = 20;int c = Add(a, b);//调用了,操作数为Add, a, b.return 0;
}

访问一个结构的成员

  • .    结构体 . 成员名
  • ->     结构体指针->成员名
struct Stu
{char name[20];int age;double score;
};
void set_stu(struct Stu*ps)
{// 不行,ss.name是一个地址,不能把字符串放到地址里。ss.name = "zhangsan";//strcpy((*ps).name, "zhangsan");//(*ps).age = 20;//(*ps).score = 100.0;strcpy(ps->name, "zhangsan");ps->age = 20;ps->score = 100.0;
}
void print_stu(struct Stu *ps)
{printf("%s %d %.1f\n", (*ps).name, (*ps).age, (*ps).score);
}int main()
{struct Stu s = { 0 };set_stu(&s);print_stu(&s);return 0;
}
//实参传给形参的时候,形参是实参的一份临时拷贝。
//当你把s传过去的时候,只传递的是实参的值,然后对形参进行改变
//我们应该传递s的地址过去
// 然后 *ps 找到s的地址 后面用 (*ps).name 找到成员name
// 也可以用 ps -> name 找到
//-> 拿到了结构体指针—>成员名   ->不需要解引用
//如果拿到了结构体对象用. 成员名     ps->age 等价于 (*ps).age

隐式类型转换

整型提升:C语言得整形算术运算总是至少以缺省整型类型的精度都来计算的。
为了获得这个精度,表达式中的字符和短整型操作数在使用之前都会变成整型。
整型提升的意义
表达式的整形运算要在CPU的相应运算期间内执行,CPU内整型运算器(ALU)的操作数的字节长度一般就是int的字节长度,同时也是CPU的通用寄存器的长度。
因此,即使两个char类型的相加,
在CPU执行时实际上也要先转换为CPU内整形操作数的标准长度。
通用CPU(general-purpose CPU)是难以直接实现两个8byte字节直接相加运算
(虽然机器指令中可能有这种直接相加指令)。
所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigend int
然后才能送入CPU中去执行。

如何进行整型提升呢?
整型提升是按照变量的数据类型的符号位来提升的。

int main()
{char c = -1; //-1是整数,32个比特位//1000 0000 0000 0000 0000 0000 0000 0001//1111 1111 1111 1111 1111 1111 1111 1110//1111 1111 1111 1111 1111 1111 1111 1111 ->  -1 的 补码//因为char类型只有一个字节,8比特位//1111 1111//把第一个看成是符号位,高位补充符号位。char d = 1;//0000 0000 0000 0000 0000 0000 0000 0001//0000 0001;//高位补符号位0//如果为无符号数,直接补0return 0;
}
int main()
{char a = 5;// 0000 0000 0000 0000 0000 0000 0000 0101// 0000 0101char b = 126;// 0000 0000 0000 0000 0000 0000 0111 1110// 0111 1110char c = a + b;//整型提升// 0000 0000 0000 0000 0000 0000 0000 0101// 0000 0000 0000 0000 0000 0000 0111 1110// 0000 0000 0000 0000 0000 0000 1000 0011//回退 八个比特位// 1000 0011printf("%d", c);//整型提升// 1111 1111 1111 1111 1111 1111 1000 0011// 1111 1111 1111 1111 1111 1111 1000 0010// 1000 0000 0000 0000 0000 0000 0111 1101// -125!!return 0;
}
// char -128 - 127
int main()
{char a = 0xb6;//整型提升了//可能会改变值,因为符号位可能为1short b = 0xb600;//整型提升了//可能会改变值,因为符号位可能为1int c = 0xb60000;return 0;
}
//放在表达式中,整型就会提升,比如 +c
int main()
{char c = 1;printf("%d", sizeof(c)); //1printf("%d", sizeof(+c)); //4printf("%d", sizeof(-c));//4return 0;
}

比如float 和 double 一起运算,会向上转换
int 和double 遇到了 ,int 会提升成double,
都是向上转换。

操作符的属性

复杂表达式的求值有三个影响因素
1.优先级:相邻操作符的优先级
2.结合性:相邻操作符优先级相同的时候,结合性说了算
  L-R 从左向右 R-L 从右向左
3.是否控制求值顺序,如逻辑或,算到1就不用算了

但是面对一些表达式
他们的顺序没法控制,有多种解释方法
  c + --c
    2  1 
  一定是先算右边的 --c 
 但是左边的 c 什么时候准备呢
 如果c 等于2, 先--c 后准备c 则结果为2
 如果 先准备c 后--c 则结果为3
 
 a * b + c * d + e * f

#include <stdio.h>
int i;
int main()
{i--;if (i > sizeof(i)){printf(">\n");}else{printf("<\n");}return 0;
}
// 会输出>

操作符应用实例:

KiKi学习了循环,BoBo老师给他出了一系列打印图案的练习,该任务是打印用“*”组成的X形图案。
输入描述:
多组输入,一个整数(2~20),表示输出的行数,也表示组成“X”的反斜线和正斜线的长度。
输出描述:
针对每行输入,输出用“ * ”组成的X形图案。

//找到规律是关键,看作一条正斜杠和反斜杠
#include <stdio.h>
int main()
{int n = 0;while (scanf_s("%d", &n) != EOF){for (int i = 0; i < n; i++)  //外循环为行{for (int j = 0; j < n; j++) //内循环为列{if (i == j || i + j == n - 1)//最关键的地方,正斜线为[i][i]处是*, 反斜杠为[i][n-1-j]处是*,一行打印1个或2个*printf("*");elseprintf(" ");}printf("\n"); //打印完一行,换行}}return 0;
}

描述
KiKi想获得某年某月有多少天,请帮他编程实现。输入年份和月份,计算这一年这个月有多少天。
输入描述:
多组输入,一行有两个整数,分别表示年份和月份,用空格分隔。
输出描述:
针对每组输入,输出为一行,一个整数,表示这一年这个月有多少天。

int is_leap_year(int x)
{if (x % 400 == 0)return 1;else if (x % 4 == 0 && x % 100 != 0)return 1;elsereturn 0;
}
int main()
{int year = 0;int month = 0;while (scanf_s("%d %d", &year, &month) != EOF){if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12)printf("31");else if (month == 2){int ret = is_leap_year(year);printf("%d", ret == 1 ? 29 : 28);}elseprintf("30");}return 0;
}

KiKi想知道已经给出的三条边a,b,c能否构成三角形,如果能构成三角形,判断三角形的类型(等边三角形、等腰三角形或普通三角形)。
输入描述:
题目有多组输入数据,每一行输入三个a,b,c(0 < a, b, c < 1000),作为三角形的三个边,用空格分隔。
    输出描述:
    针对每组输入数据,输出占一行,如果能构成三角形,等边三角形则输出“Equilateral triangle!”,等腰三角形则输出“Isosceles triangle!”,其余的三角形则输出“Ordinary triangle!”,反之输出“Not a triangle!”。

#include<stdio.h>
int main()
{int a = 0;int b = 0;int c = 0;while (scanf_s("%d %d %d", &a, &b, &c) != EOF){if (a + b > c && a + c > b && b + c > a){if (a == b && b == c)printf("Equilateral triangle!\n");else if (a == b || b == c || a == c)printf("Isosceles triangle!\n");elseprintf("Ordinary triangle!\n");}elseprintf("Not a triangle!\n");}return 0;
}

【C语言】C语言操作符的分类及应用【超详细讲解】相关推荐

  1. C语言整型,浮点型数据储存的超详细讲解

    数据类型 整型 浮点型(实型) 写在最后的话 我们都知道C语言有很多数据类型,如char ,int ,double 等等,本篇博客我们来梳理分类一下这些数据类型,首先我们可以将数据类型分为两类,整型和 ...

  2. 数据结构-带头节点的单链表(C语言)超详细讲解

    前面我们学到线性表的顺序存储结构(顺序表),发现它有着明显的缺点:插入和删除元素时需要频繁的移动元素,运算效率低.必须按事先估计的最大元素个数申请连续的存储空间.存储空间估计大了,造成浪费空间:估计小 ...

  3. NLP之文本分类实战入门超详细教程

    目录 前言 一.数据加载 1.加载包 2.读取数据 二.文本处理 1.去除无用字符 2.文本分词 3.去除停用词 4.去除低频词 5.划分训练集和测试集 三.把文本转换成向量的形式 1.把文本转换成t ...

  4. C语言基础大全(基于千锋教育超详细教程)

    C语言基础 1.第一个c语言程序 #include <stdio.h> int main() {printf("hello world");return 0; } [外 ...

  5. 【C语言】用C语言实现最大公约数和最小公倍数【超详细讲解】

    最大公约数: "最大公因数,也称最大公约数.最大公因子,指两个或多个整数共有约数中最大的一个.a,b的最大公约数记为(a,b),同样的,a,b,c的最大公约数记为(a,b,c),多个整数的最 ...

  6. r语言中mpg数据_零基础生信入门第一课——R语言数据清洗,超详细讲解,建议收藏!...

    小伙伴们大家好!今天我要用一篇推文精要概括数据清洗中的最基本最关键的步骤,对于零基础的学员一定会有很大收获!数据清洗是完成一篇生信文章最基本但也是最终要的准备工作,如果不会数据清洗,就要错过很多优质数 ...

  7. C语言实现扫雷【超详细讲解】

    目录 一.实现扫雷的基本思路 二.代码实现的具体步骤 三.完整代码 1.saolei.h部分 2.saolei.c部分 3.test.c部分 扫雷和三子棋有很多相似的地方,相信大家认真学习完三子棋再将 ...

  8. 超详细讲解C语言入门函数(一)

    解析已经很详细了,可以说相当入门级别了,如果喜欢的话那就请支持一下,后续会继续更新~ 代码网上搜索,并加以更改,侵权请联系删除,谢谢~ 部分例子没有详细解释是因为前面的例子已经说过了 3×4矩阵求最大 ...

  9. C语言实现扫雷游戏(超详细讲解+全部源码)

    电子信息 工科男 一点一点努力! 文章目录 前言 一.游戏介绍 二.游戏设计思路 二.具体步骤 1.创建test.c和game.c源文件以及 game.h头文件 2.创建菜单 3.创建雷盘 4.初始化 ...

最新文章

  1. android R文件丢失解决方法
  2. clearcase 创建副本
  3. JavaScript正则表达式详解(一)正则表达式入门
  4. Java中文问题详解
  5. c 语言 文本处理范例
  6. 3_1 StrategyMode.cpp 策略模式
  7. Spring Boot log4j2 configuration example
  8. JAMstack简介:现代Web的体系结构
  9. by group 累加中文字段_EF 求和 GroupBy多个字段
  10. 自动化调参NNI学习(三):使用python启动NNI框架调整随机森林(RandomForest)模型
  11. Android面向HTTP协议发送post请求
  12. 函数和常用模块【day06】:模块特殊变量(十四)
  13. 搜狗高速浏览器主页被篡改怎么办 搜狗浏览器中恢复被篡改主页的方法
  14. llq考试 圣诞欢乐赛 (第二发)
  15. 1024程序员节日背后的神秘面纱
  16. 关于对当前大学生的痛点分析
  17. MaximalRectangle
  18. css浏览器兼容性的问题
  19. 超级账本hyperledger fabric第五集:共识排序及源码阅读
  20. git bash返回上一级目录

热门文章

  1. c语言系统通常将一个判断为真,C语言程序设计学习-习题2
  2. 【记录】Tiff图像的前处理,median blur filter 及 linear stretch
  3. 蓝懿ios技术交流和心得分享 16.1.30
  4. grep(模式匹配器)详解
  5. 七大数据陷阱之技术过失(上):数据整理中的问题
  6. 1455 B - Jumps
  7. linux smit工具,Linux安全基础 SMIT入门
  8. ffmpeg使用bsf后码流从avcc格式变成annex-b造成硬解异常
  9. 华为时间管理之仁者见仁
  10. 在java中下列说法不正确的是,【单选题】关于java中的转义字符,下列说法不正确的是 A. 是制表位 B. 可以实现换行 C. 可以在页面中显示双引号 D. \可以在页面实现注释...