【C语言】入门必看 - 操作符详解

本文详细讲解了算术、移位、位、赋值、单目、关系、逻辑、条件、逗号表达式及下标引用等编程操作符,涵盖整数、浮点数和指针操作,适合提升程序员基础技能。

目录

  • 操作符

1.算术操作符

2.移位操作符

3.位操作符

4.赋值操作符

5.单目操作符

6.关系操作符

7.逻辑操作符

8.条件操作符

9.逗号表达式

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


  • 操作符

1.算术操作符+(加)  -(减)  *(乘)  /(除)  %(取余)

  1. 除了%操作符之外,其他的几个操作符均可作用于整数和浮点数。
  2. 对于 / 操作符如果两个操作数都为整数,执行整数除法,此时的结果也是整数,只保留正常结果的整数部分。而只要有浮点数执行的就是浮点数除法,结果正常。
  3. % 操作符的两个操作数必须为整数。返回的是整除之后的余数。

2. 移位操作符>>(右移操作符)  <<(左移操作符)

左移操作符 - 左边抛弃,右边补零

先将十进制数转换为二进制数,例如10,它的二进制数是1010,实际上,二进制数共有32位,在进行左移操作时,其首位被抛弃,空出来的最后一位补0。所以对10进行左移操作后,其二进制数变为10100,转换为十进制数是20。

右移操作符 - 算术右移和逻辑右移

(1)算术右移 - 右边抛弃,左边补原符号位

还是以10为例,算术右移之后其二进制数变为101,转换为十进制数是10。而对其右边空出来的一位,由于它原来是正数,所以该位置补它的原符号位,即0。

(2)逻辑右移 - 右边抛弃,左边补零

对于负数来说,对其进行算术右移后,其符号不变,仍然是负数。而对其进行逻辑右移后,由于左边补零,所以它的符号会改变。

这里再拓展一下整数的二进制表示形式,一共有三种:

  1. 原码:直接根据数值写出的二进制序列就是原码
  2. 反码:原码的符号位不变,其他位按位取反就是反码。对于正数来说,它的反码与补码相同,而负数则会发生改变。
  3. 补码:反码+1,就是补码(-1的补码全是1)。值得注意的是,计算机中所有数都是以补码形式存储的。

3.位操作符: &(按位与)  |(按位或)  ^(按位异或)

& - 对应的二进制位按位与

例如3和5,他们的二进制数分别是011和101,3&5就相当于他们的二进制数对应的每一位都按位与,最后变为001,也就是3&5=1。

| - 对应的二进制位按位或

还是以3和5举例,他们的二进制数对应的每一位都按位或,最后变为111,也就是3&5=7。

^ - 对应的二进制位按位异或

还是3和5,他们对应的二进制数对应的每一位都按位异或,即相同为0、相异为1,所以二进制数最后变为110,也就是3^5=6。

注:它们的操作数只能是整数

//求一个整数存储在内存中的二进制中1的个数。
#include <stdio.h>
int main()
{
 int num = -1;
 int i = 0;
 int count = 0;//计数
 for(i=0; i<32; i++)
 {
     if( num & (1 << i) )
     count++; 
 }
 printf("二进制中1的个数 = %d\n",count);
 return 0; }

4.赋值操作符(主要讲复合赋值符):

+=:a=a+100 等价于 a+=100

-=:a=a-100 等价于 a-=100

*=:a=a*100 等价于 a*=100

/=:a=a/100 等价于 a/=100

%=:a=a%100 等价于 a%=100

>>=:a=a>>1 等价于 a>>=100

<<=:a=a<<100 等价于 a<<=100

&=:a=a&100 等价于 a&=100

|=:a=a|100 等价于 a|=100

^=:a=a^100 等价于 a^=100

5.单目操作符:只有一个操作数

!(逻辑反操作)- 假成真,真成假

-(取负值)

+(取正值)

&(取地址)

sizeof(操作数的类型长度 - 以字节为单位)- 如果sizeof的括号中有表达式,表达式是不参与运算的

~(对一个数的二进制按位取反 )- 例如:~0000=1111

++(前置加加和后置加加)

  • 后置加加 - 先使用再加加

 

  •  前置加加 - 先加加再使用

--(后置减减和前置减减)- 用法同上

*(解引用操作符/间接访问操作符)- 效果如下

 (类型) - 强制类型转换

 ↑如果不进行强制类型转换,编译就会报错

补充:sizeof和数组

void test1(int arr[])
{
	printf("%d\n", sizeof(arr));//(2)
}

void test2(char ch[])
{
	printf("%d\n", sizeof(ch)); //(4)
}

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

上述程序的(1)(2)(3)(4)处分别会输出什么?

答案分别是40、4、10、4

(1)(3)处不难理解,计算的分别是整形数组和字符串数组的大小。而对于(2)(4)两处,由于数组传参是传递的是首元素的地址,即传过去的是指针变量所以,两个函数中sizeof计算的分别是两个指针变量的大小,而指针变量的大小始终为4/8。

 6.关系操作符

> - 判断大于

< - 判断小于

>= - 判断大于等于

<= - 判断小于等于

!= - 判断不相等

== - 判断相等(比较2个字符串相等,不能使用==)

7.逻辑操作符

&&(逻辑与) - 前后都为真才返回真

int main()
{
	int i = 0, a = 0, b = 2, c = 3, d = 4;
	i = a++ && ++b && d++; //(1)
	printf("a = %d\nb = %d\nc = %d\nd = %d\n", a, b, c, d);
	return 0;
}

思考一下,上面这个程序输出结果是多少?

 

因为(1)在运算过程中,由于a++是先使用再加加,返回值也就是0,结合&&,当前面一项返回值为假时,后面的都不在进行判断,所以b、c、d都没有进行运算,所以没有发生改变。举一反三,如果a的初始值是1,那么b、c、d最终都会+1。

||(逻辑或) - 前后有一个为真即为真

int main()
{
	int i = 0, a = 1, b = 2, c = 3, d = 4;
	i = a++ || ++b || d++; //(2)
	printf("a = %d\nb = %d\nc = %d\nd = %d\n", a, b, c, d);
	return 0;
}

那这个程序的输出结果又是多少呢?

 因为(2)在运算中,a++的返回值是1,为真。结合||,返回值这时已经确定了,所以后边就不在运行了,因此b、c、d的值没有发生改变。举一反三,如果a的初始值是0,那么返回值是多少呢?答案是1334。 

8.条件操作符/三目操作符

exp1 ? exp2 : exp3 - exp1为判断条件,如果为真,则返回exp2的结果;反之,返回exp3的结果。如果1为真,则不会计算3;如果1为假,则不会计算2。

int main()
{
	int a = 3;
	int b = 0;
	
	if (a > 5)
		b = 1;
	else
		b = -1;

	//写成三目操作符
	b = (a > 5 ? 1 : -1);

    return 0;
}

9.逗号表达式

exp1, exp2, exp3, …expN - 逗号表达式,就是用逗号隔开的多个表达式,从左向右依次执行。整个表达式的结果是最后一个表达式的结果。

下面这个例子,就是用逗号表达式优化代码:

a = get_val();
count_val(a);
while (a > 0) 
{
        //业务处理
        a = get_val();
        count_val(a);
}

//如果使用逗号表达式,改写:
while (a = get_val(), count_val(a), a>0) 
{
        //业务处理
}

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

[ ]下标引用操作符)- 操作数:一个数组名 + 一个索引值

int arr[10];//创建数组
arr[9] = 10;//实用下标引用操作符。
//[ ]的两个操作数是arr和9。
( )  (函数调用操作符)- 接受一个或者多个操作数:第一个操作数是函数名,剩余的操作数就是传递给函数的参数。
 void test1()
 {
     printf("hi\n");
 }

 void test2(const char *str)
 {
     printf("%s\n", str);
 }

 int main()
 {
     test1();                 //实用()作为函数调用操作符。
     test2("Hello, world.\n");//实用()作为函数调用操作符。
     return 0;
 }
访问一个结构的成员
. 结构体 . 成员名
-> -  结构体指针 -> 成员名
struct Stu
{
    char name[10];
    int age;
    char sex[5];
    double score;
};
 
void set_age1(struct Stu stu) 
{
    stu.age = 18; 

}
void set_age2(struct Stu* pStu) 
{
    pStu->age = 18;//结构成员访问
}

int main()
{
    struct Stu stu;
    struct Stu* pStu = &stu;//结构成员访问
 
    stu.age = 20;//结构成员访问
    set_age1(stu);
 
    pStu->age = 20;//结构成员访问
    set_age2(pStu);
    return 0; 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LeePlace

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值