C语言——操作符

目录

前言

一算术操作符

二移位操作符

2.1左移位操作符

2.2右移位操作符

三位操作符

 3.1变态的笔试题

3.2练习

四赋值操作符 

4.1复合操作符

五单目操作符

5.1单目操作符介绍

六关系操作符

七逻辑操作符

7.1笔试题

八条件操作符

8.1练习

九逗号表达式

十下标引用,函数调用和结构体成员操作符

10.1下标引用操作符[]

10.2函数调用操作符()

10.3结构体成员操作符

十一表达式求值

11.1隐式类型转换

11.2算术转换

11.3操作符的属性

11.4问题表达式

相关练习

最后


前言

在C语言中,操作符的分类可以说是五花八门,但对于我们日常写代码时又非常重要。

下面,一起来认识操作符的分类:

1算术操作符

2移位操作符

3位操作符

4赋值操作符

5单目操作符

6关系操作符

7逻辑操作符

8条件操作符

9逗号表达式

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

一算术操作符

+    -   *   /   %(取余数)

1. 除了 % 操作符之外,其他的几个操作符可以作用于整数和浮点数

2. 对于 / 操作符如果两个操作数都为整数,执行整数除法,而只要有浮点数执行的就是浮点数除法.

3. % 操作符的两个操作数必须为整数.

二移位操作符

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

注:移位操作符的操作数只能是整数

2.1左移位操作符

规则:左边抛弃,右边补0

2.2右移位操作符

它分2种情况:算术右移与逻辑右移

算术右移:左边用0填充,右边丢弃

逻辑右移:左边用原该值的符号位填充,右边丢弃

在VS中,选择的时逻辑右移,如下:

三位操作符

& 按位与          | 按位或          ^按位异或

注:他们的操作数也必须是整数 

 3.1变态的笔试题

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

#include <stdio.h>
int main()
{
 int a = 10;
 int b = 20;
 a = a^b;
 b = a^b;//b=a^b^b
 a = a^b;//a=a^b^a
 printf("a = %d b = %d\n", a, b);
 return 0;
}

在平常中写代码中,我们要写出的代码要不仅逻辑清晰,看代码也要清晰。上面这种仅仅是出现在笔试题中,平常尽量避免以上这种代码。

3.2练习

编写代码实现:求一个整数存储在内存中的二进制中1的个数。

int print1(unsigned int n)//这种思路接收的参数必须时无符号的整数,避免传入-1计算错误
{
	int count = 0;
	while (n)
	{
		if(n % 2==1)
			count++;
		n /= 2;
	}
	return count;
}
int print2(int n)
{
	int count = 0;
	for (int i = 0; i < 32; i++)
	{
		if ((n >> i)&1 == 1)
			count++;
	}
	return count;
}
int print3(int n)//妙解
{
	int count = 0;
	while (n)
	{
		n=n& (n - 1);//带入具体数据更好理解
		count++;
	}
	return count;
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	printf("%d", print3(n));
	return 0;
}

四赋值操作符 

赋值操作符是一个很棒的操作符,他可以让你得到一个你之前不满意的值。也就是你可以给自己重新赋值。

int weight = 120;//体重
weight = 89;//不满意就赋值
double salary = 10000.0;
salary = 20000.0;//使用赋值操作符赋值。

4.1复合操作符

+=

-=

*=

/=

%=

>>=

<<=

&=

|=

^= 

举例:

int x = 10;
x = x+10;
x += 10;//复合赋值
//其他运算符一样的道理。使得更加简便

五单目操作符

5.1单目操作符介绍

!           逻辑反操作

-           负值

+           正值

&           取地址

sizeof      操作数的类型长度(以字节为单位)

~           对一个数的二进制按位取反

--          前置--(先--,在使用)、后置--(先使用,在--)

++          前置++(先++,在使用)、后置++(先使用,在++)

*           间接访问操作符(解引用操作符)

(类型)       强制类型转换 

#include <stdio.h>
int main()
{
 int a = -10;
 printf("%d\n", sizeof(a));
 printf("%d\n", sizeof(int));
 printf("%d\n", sizeof a);//这样写行不行?
 printf("%d\n", sizeof int);//这样写行不行?
 return 0;
}

sieof在使用的时候,后面可以直接加变量名(不能时类型)来使用,说明sizeof是一个操作符。我们在日常使用时通常加括号来使用,会误以为它是函数,要注意。 

六关系操作符

=

>=

<=

!=      (有来测试不相等)

==      (用来测试相等) 

 注意:在写表达式时,经常会把==写成=导致程序的崩溃。

解决之一:把变量名写在之后.如if(a==10)写成if(10==a)即使漏写一个=,编译器直接报错.(好修改)

七逻辑操作符

&&      逻辑与

||         逻辑或

区分逻辑操作符与算术操作符:

1&2----->0(计算的结果)

1&&0---->0(结果为假)

1|2----->3(计算的结果)

1||0---->1(结果为真)

7.1笔试题

#include <stdio.h>
int main()
{
    int i = 0,a=0,b=2,c =3,d=4;
    i = a++ && ++b && d++;//结果a=1 b=2 c=3 d=4
    //i = a++||++b||d++;//结果a=1 b=3 c=3 d=4
    printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
    return 0;
}
//程序输出的结果是什么?

解决上面的问题,要注意的是:逻辑操作符会从左向右依次执行,&&只要一个为假就结束,||只要有一个为真就结束。 

八条件操作符

exp1(表达式) ? exp2(表达式为真执行) : exp3(表达式为假执行) 

8.1练习

if (a > 5)
        b = 3;
else
        b = -3;
转换成条件表达式,是什么样?
a > 5 ? b = 3 : b = -3;//一句搞定

在通常写代码时,只有if else 这些简单的判断句时就可以使用它来达到简便。

九逗号表达式

exp1, exp2, exp3, …expN

逗号表达式,从左向右依次执行。整个表达式的结果是最后一个表达式的结果。 

//代码1
int a = 1;
int b = 2;
int c = (a>b, a=b+10, a, b=a+1);//c=13

//代码2
if (a =b + 1, d=a / 2, d > 0)//最后的表达式才会起作用,但前面的表达式执行可能会对最后的结果产生影响

//代码3
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.1下标引用操作符[]

int arr[10];//创建数组

arr[9] = 10;//实用下标引用操作符。

[ ]的两个操作数是arr和9。

10.2函数调用操作符()

接受一个或者多个操作数:第一个操作数是函数名,剩余的操作数就是传递给函数的参数。

但函数调用操作符也可以什么都不传

#include <stdio.h>
 void test1()
 {
 printf("hehe\n");
 }
 void test2(const char *str)
 {
 printf("%s\n", str);
 }
 int main()
 {
 test1();            //实用()作为函数调用操作符。
 test2("hello bit.");//实用()作为函数调用操作符。
 return 0;
 }

10.3结构体成员操作符

.      使用,结构体.成员名

->    使用,结构体指针->成员名

#include <stdio.h>
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;
 set_age1(stu);
 set_age2(pStu);
 return 0;
}

十一表达式求值

表达式求值的顺序一部分是由操作符的优先级和结合性决定。

有些表达式的操作数在求值的过程中可能需要转换为其他类型,一般是转化为高字节类型计算。

11.1隐式类型转换

C的整型算术运算总是至少以缺省整型类型的精度来进行的。

为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升

例子:


int main()
{   
	char a = 3;  //char a=00000011<-存储在char类型中a=00000000000000000000000000000011
	char b = 127;//cahr b=01010111<-存储在char类型中b=00000000000000000000000001111111
	char c = a + b;      //char a与char b相加发生整形提升来进行计算
                         //计算结果:00000000000000000000000010000010存储在char类型中
                         //char c=10000010
	printf("%d\n", c);//以整形形式打印c
//进行整形提升,高位补符号位->11111111111111111111111110000010->是高位是1,是负数,结果转化为源码
//                       ->11111111111111111111111110000001
//                       ->10000000000000000000000001111110->-126
	return 0;
}

系统内部真的有整形提升吗?

//实例1
int main()
{
 char a = 0xb6;
 short b = 0xb600;
 int c = 0xb6000000;
 if(a==0xb6)
 printf("a");
 if(b==0xb600)
 printf("b");
 if(c==0xb6000000)
 printf("c");
 return 0;
}

如果有,实例1中的a,b要进行整形提升,但是c不需要整形提升 a,b整形提升之后,变成了负数,所以表达式 a==0xb6 , b==0xb600 的结果是假,但是c不发生整形提升,则表达式 c==0xb6000000 的结果是真,打印c。

11.2算术转换

如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数的转换为另一个操作数的类 型,否则操作就无法进行。(一般低类型转换为高类型计算)

long double > double > float > unsigned long > int > long int > unsigned int > int 

 但算术转换也要合理,不然会有精度丢失!

float f = 3.14;
int num = f;//隐式转换,会有精度丢失

11.3操作符的属性

复杂表达式求值有以下几个因素:

第一考虑优先级

如果优先级相同则考虑结合性

控制求值顺序只有特殊的三个(逻辑与,逻辑或,条件操作符)

11.4问题表达式

由于操作符的属性由多方面元素影响,由此会产生问题表达式,大都是编译器对于操作符的顺序各有各的"见解",造成计算结果的不同.

//表达式1
a*b + c*d + e*f

第一种: 

 

第二种: 

 

你或许会说:上面两种方法计算出来的不也一样的吗?那你有没有想过:如果前面先*完后对后面的变量有影响呢?(++a) 

//表达式2
c + --c;

像这个就很清楚的展现出问题来了,想进行--c势必对前者的c产生影响.

//表达式3
int main()
{
 int i = 10;
 i = i-- - --i * ( i = -3 ) * i++ + ++i;
 printf("i = %d\n", i);
 return 0;
}

在不同的编译器上的不同结果:

//表达式4
int fun()
{
     static int count = 1;
     return ++count;
}
int main()
{
     int answer;
     answer = fun() - fun() * fun();
     printf( "%d\n", answer);//输出多少?
     return 0;
}

这个代码有没有问题?

乍一看,没问题.实际上,有问题. 

尽管在其它编译器上的结果都相同,但问题是:编译器要先调用那个我们并不清楚...

函数的调用先后顺序无法通过操作符的优先级确定

//表达式5
#include <stdio.h>
int main()
{
 int i = 1;
 int ret = (++i) + (++i) + (++i);
 printf("%d\n", ret);
 return 0;
}

在VS中,它认为的计算顺序是这样的: 结果是:12=4+4+4

但别的编译器不认为,在Linux环境编译的结果:10=3+3+4 ,它所认为的顺序:

原因:这段代码中的第一个 + 在执行的时候,第三个++是否执行,这个是不确定的,单依靠操作符的优先级和结合性是无法决定第一个 + 和第三个前置 ++ 的先后顺序.所以有不同的结果.

总结:我们写出的表达式如果不能通过操作符的属性确定唯一的计算路径,那这个表达式就是存在问题的.

相关练习

写代码,打印整数二进制的奇数位和偶数位

i=0移到第一个bit位
int main()
{
	int n = 0;
	scanf("%d", &n);
	printf("奇数位:");
	for (int i = 30; i >= 0; i -= 2)
	{
		int ret = (n >> i) & 1;
		printf("%d ", ret);
	}
	printf("\n偶数位:");
	for (int i = 31; i >= 1; i -= 2)
	{
		int ret = (n >> i) & 1;
		printf("%d ", ret);
	}
	return 0;
}
#include <stdio.h>
int i;//0
int main()
{
    i--;
    //i是int类型,要转化成无符号整形 sizeof(i)计算的结果是size_t是无符号整形
    if (i > sizeof(i))
    {
        printf(">\n");
    }
    else
    {
        printf("<\n");
    }
    return 0;
}
//打印的结果:>

 BC100-有序序列合并

#include <stdio.h>

int main() {
    int n=0,m=0;
    scanf("%d%d",&n,&m);
    int arr1[1000]={0};
    int arr2[1000]={0};
    int arr[3000]={0};
    int i=0,j=0;
    for(i=0;i<n;i++)
    {
        scanf("%d",&arr1[i]);
    }
    for( j=0;j<m;j++)
    {
        scanf("%d",&arr2[j]);
    }
    i=0,j=0;
    int k=0;
    while(i<n&&j<m)
    {
        if(arr1[i]<arr2[j])
        {
            arr[k]=arr1[i];
            i++;
            k++;
        }
        else {
            arr[k]=arr2[j];
            j++;
            k++;
        }
    }
    if(i==n)
    {
        while(j<m)
        {
            arr[k++]=arr2[j++];
        }
    }
    else {
        while(i<n)
        arr[k++]=arr1[i++];
    }
    for(int i=0;i<n+m;i++)
    {
        printf("%d ",arr[i]);
    }
}

BC54-获得月份天数

#include <stdio.h>

int main() {
    int y, m;
    while (scanf("%d %d", &y, &m) != EOF) {
    int days[]={0,31,28,31,30,31,30,31,31,30,31,30,31};
    if(y%4==0&&y%100!=0||y%400==0)
    {
        days[2]++;
    }
    printf("%d\n",days[m]);
    }
    return 0;
}

BC38-变种水仙花数

#include <stdio.h>
// n/10 * n%10+n/100 * n%100+n/1000 * n%1000+n/10000 * n%10000
int main() {
   
    for(int i=10000;i<100000;i++)
    {
        int sum=0;
        for(int j=10;j<=10000;j*=10)
        {
            sum+=(i/j)*(i%j);
        }
        if(sum==i)
        {
            printf("%d ",i);
        }
    }
    return 0;
}

最后

感谢你的观看,能三连支持一波就更好了。 

  • 21
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
编程实现简单命令解释器,可以模拟Shell的功能,我们可以使用C语言来完成。 首先,我们需要实现一个循环,在循环中读取用户输入的命令,并为每个命令执行相应的操作。我们可以使用`while`循环来完成这个步骤。 然后,我们需要读取用户输入的命令。在C语言中,我们可以使用`scanf`函数来读取用户输入的字符串。例如,`scanf("%s", command)`可以将用户输入的字符串存储在名为`command`的字符串变量中。 接下来,我们需要解析用户输入的命令。我们可以使用字符串处理函数来拆分命令字符串为不同的参数。例如,`strtok`函数可以将字符串分割成多个子字符串,我们可以使用空格作为分隔符。 在命令解析的过程中,我们需要判断用户输入的命令,并执行相应的操作。我们可以使用`if`语句或`switch`语句来完成这个步骤。例如,如果用户输入的命令是`ls`,我们可以调用系统命令`system("ls")`来执行`ls`命令。 同时,我们可以添加一些常见命令的实现,例如`cd`命令用来改变当前工作目录,`mkdir`命令用来创建新目录,`rm`命令用来删除文件等等。我们可以使用C语言提供的文件和目录操作函数来实现这些功能。 最后,我们可以在命令解释器中实现一些其他辅助功能,例如历史记录功能,可以记录用户输入的历史命令,方便用户进行查找和重复执行。 通过以上步骤的实现,我们就可以编程实现一个简单命令解释器,模拟Shell的功能。当用户输入命令时,程序会执行相应的操作,提供类似于Shell的交互界面。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值