【C语言初阶】带你轻松玩转所有常用操作符(2) ——赋值操作符,单目操作符

简介: 【C语言初阶】带你轻松玩转所有常用操作符(2) ——赋值操作符,单目操作符
  • 在正式开始之前,我们还是借助一张思维导图帮助大致简单回忆一下有关操作符的基础内容

  • 我们接着之前的内容朝下讲:

一.赋值操作符

赋值操作符是一个非常有用的操作符,它可以让你得到一个你之前不满意的值。也就是你可以给自己重新赋值

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

赋值操作符也可以连续赋值

int a = 10;
int x = 0;
int y = 20;
a = x = y+1;//连续赋值
//但是同样的语义我们也可以下面这样
x = y+1;
a = x;
//这样的写法是不是更加清晰爽朗而且易于调试。

所以我们一般都不是特别推荐连续赋值。

复合赋值符

加等于 +=

减等于 -=

乘等于 *=

除等于 /=

取余等于 %=

右移等于 >>=

左移等于 <<=

按位与等于 &=

按位或等于 |=

按位异或等于 ^=

这些运算符都可以写成复合的效果。

比如:
int x = 10;
x = x+10;
x += 10;//复合赋值与上一行意思相同
//其他运算符一样的道理。这样写更加简洁

二.单目操作符

1.单目操作符介绍

逻辑反操作 !

负值 -

正值 +

取地址 &

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

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

前置 --、后置 –

前置 ++、后置 ++

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

强制类型转换 (类型)


先举几个简单的例子带大家认识一下,然后咱们在中间挑几个比较重要的讲解一下。

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

我们来看下结果:

a96c3eb2c48147ca92818620639ddd5d.png

2.逻辑反操作符 !

printf("%d\n", !2);
printf("%d\n", !0);

这两个输出结果我们可以看到分别是“0”和“1”

也就是说!为假时(即值为0)时为真(非0),!不为假时才判为假(0)

3.求操作数的类型长度 sizeof

sizeof的基本用法是这样的

sizof(所求类型)

但是,我们通过上面这个例子的结果可以看出来:

    printf("%d\n", sizeof(a));
  printf("%d\n", sizeof(int));
  printf("%d\n", sizeof a);//这样写行不行?

对于一个变量来说,sizof的括号是可省略的,但是如果所求长度为一个类型的话,这个括号就必须要加上!

sizeof与数组

通常来说,我们的sizeof广泛用于求一个数组的长度与元素个数。

下面举一个实战例子来说明

利用二分法在某个有序数组里具体找到某个数,并打印出该数的数组下标。


二分法具体的使用方法和适用场景我已经写过详解博客,这里只是引用这个例子,具体不再展开讲,如果你感兴趣的话,请移步下方链接哦!

【C语言】带你玩转经典算法用二分法在一个有序数组中查找某个数

代码如下:

int main()
{
  int arr[] = { 1,2,3,4,5,6,7,8,9,10 };//升序
  int k = 7;
  int i = 0;
  int sz = sizeof(arr) / sizeof(arr[0]);//利用数组的总大小除以数组中一个元素的大小,得到数组中一共存放了几个元素
  //1
  int left = 0;
  int right = sz-1;//数组下标是数组元素个数-1
  int flag = 0;//flag的作用是标志是否找到了
  //2
  while (left<=right)//当左右都指向同一个数时还没找到,说明此数不存在
  {
    int mid = (left + right) / 2;
    if (arr[mid] == k)
    {
      printf("找到了,下标是:%d\n", mid);
      flag = 1;//令flag等于1
      break;
    }
    else if (arr[mid] < k)//mid就比k小,舍去比mid更小的数
    {
      left = mid + 1;
    }
    else//mid比k大,舍去比mid大的数
    {
      right = mid - 1;
    }
  }
  //1 2
  if (flag == 0)//判断是否找到k,如果找到,flag应等于1
    printf("没找到\n");
  return 0;
}

请注意这里:

int sz = sizeof(arr) / sizeof(arr[0]);//利用数组的总大小除以数组中一个元素的大小,得到数组中一共存放了几个元素

我们这里利用sizeof成功的拿到了数组元素的个数方便我们后一步进行二分法查找。

sizeof 在使用过程中常出的几种错误

我们这里还是通过代码带大家展开接下来的内容

#include <stdio.h>
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(arr);
  test2(ch);
  return 0;
}
/*问:
(1)、(2)两个地方分别输出多少?
(3)、(4)两个地方分别输出多少*/?

来看结果:


46a02ede52c14154b92931423bab457d.png

怎么回事?我两个明明计算的是同一个数组的大小,怎么结果不一样呢?


这里就是数组以及指针的知识啦,我来说明一下原因:


1.数组在被当作参数在函数之间传递时,传过去的其实是首元素的地址,因此在计算的是首元素地址的大小!

2.对于一个int整型数据来说占四个字节,10个就是40个字节,而一个char型数据只占1个字节,10个就是10个字节,这就是出现上面答案的原因。

到这里,可能还有小可爱要问了,这里的char型为啥占4个字节啊?你不是说一个char型只占1个字节吗?


嗯…

765eefd206444b6b91b7e4a97f5e293d.png


注意了,这里如果你是这么认为的话,那么说明你还是没有理解我上面的解释哈,建议再多看看指针相关内容哦!


我们这里虽然写的传入形式是两个数组


void test1(int arr[])
void test2(char ch[])

但实际我们说了,传进去的是首元素的地址,实际上是指针,因此我们也可以这么写:

void test1(int *arr)
void test2(char *ch)

9060f9ed914b42b589673e03a6635413.png


结果依然是对的。

而对于指针的大小来说,在相同操作系统下,所有指针类型的大小都是相同的,我们这里采用的是32位操作系统,指针变量的大小统一都是4个字节,而64位则统一都是8个字节。

6a1353cda8ae4413b2ad6d0985a71863.png


现在,我想你应该明白上述结果出现的原因了吧!

4.前置++与前置- -

其实这一块没啥好讲的,我们唯一需要注意的是,在使用时,是先执行++或- -操作再进行下一步。


举例说明:

//前置++和--
#include <stdio.h>
int main()
{
  int a = 10;
  int x = ++a;
  //先对a进行自增,然后对使用a,也就是表达式的值是a自增之后的值。x为11。
  int y = --a;
  //先对a进行自减,然后对使用a,也就是表达式的值是a自减之后的值。y为10;
  return 0;
  }

5.后置++与后置- -

与前置++和前置- -相反,后置的++ - -是等表达式执行完后,再执行++或- -操作


//后置++和--
#include <stdio.h>
int main()
{
  int a = 10;
  int x = a++;
  //先对a先使用,再增加,这样x的值是10;之后a变成11;
  int y = a--;
  //先对a先使用,再自减,这样y的值是11;之后a变成10;
  return 0;
  }

举例证明前置后置的优先级

下面我们来通过一个具体例题来证明一下我上面讲述的内容

#include <stdio.h>
int main()
{
  int a, b, c;
  a = 5;
  c = ++a;
  b = ++c, c++, ++a, a++;
  b += a++ + c;
  printf("a = %d b = %d c = %d\n:", a, b, c);
  return 0;
}

来判断一下上面这段代码的输出结果

这里就不卖关子了直接公布答案:

e6ae7515ebc14ee394060a4a8a0d2193.png

和你想的结果一样吗?

我们来具体讲解一下

int main()
{
  int a, b, c;
  a = 5;
  c = ++a;//前置++ c=6
  b = ++c, c++, ++a, a++;//逗号表达式整个表达式的结果是最后一个表达式的结果,这里先记住这个结论,具体解释我们后面再说
  //此时b=a++,由于后置这里就是a,但是前面执行了++a,此时a的值为7所有b就等于7
  //执行完b表达式后,开始执行后置的++,此时c等于8,a也等于8
  b += a++ + c;//这句话写清楚点就是b=b+a++ +c,此时b=7+8+8=23
  //最后再执行一次a后置++,a的值变为9
  printf("a = %d b = %d c = %d\n:", a, b, c);
  return 0;
}

我这样分析,输出的结果是不是就与我们打印在屏幕上的结果对上啦!看完这个例子,有加深你对前置后置++(- -)的理解吗?

6. ~ 按补码二进制位取反

我们前面就说了,整型在内存中是以二进制补码的形式存储的,你如果对这个概念不太了解,可以看看这篇博客:【C语言进阶】纳尼?这样学数据在内存中的存储竟然如此简单(1)?

而~就是用来对某个整型进行二进制取反的

代码如下:

//~ 按补码二进制位取反
int main()
{
  int a = 0;
  printf("%d\n", ~a);//?
  //00000000000000000000000000000000 -a的补码
  //11111111111111111111111111111111 - ~取反后的补码
  //11111111111111111111111111111110
  //10000000000000000000000000000001 -1//打印时打印的是该数的原码
  return 0;
}

c119f8ecb98449c8bfb8f57cb24fc1e1.png

7.取地址操作符&和解引用操作符*

这俩大多出现的地方在指针中,其实是没啥好讲的,我就不展开了,之后会出有关指针的相关博客的。

8.强制类型转换()

我们在引用某个库函数或者别的什么函数时,可能会出现输入的数据类型与使用该函数定义的数据类型不太符合,这时候我们就需要吧我们输入的数据强制类型转换成所需的数据类型,但是俗话说强扭的瓜不甜,在某些情况下,使用强制类型转换是可能出现bug的。


举例说明:

int main()
{
  int a = (int)3.14;//强制
  printf("%d\n", a);
  return 0;
}

988253e6a4814f9bba5b8ad5ef41c4c2.png


我们把一个浮点数强制类型转换为int型。

但是我们也明显的看出来这段代码的缺陷,它把我们小数点后面的数据给丢了,也就是说在强制类型转换的过程中是很容易造成数据的丢失的!

在函数中的应用

我们在直接三子棋生成随机数中,曾经见过这样一段代码:

srand((unsigned int)time(NULL));//把时间函数置空传给srand同时由于srand要求参数必须为unsigned int型,把time(NULL)强制类型转换一下

感兴趣随机数生成方法的可以去看看这篇博客:

【C语言】三子棋详解(包教包会的那种)

这就是在实际使用函数时对强制类型转换的应用。

总结

今天的内容暂时讲到这里就结束了,我们今天讲了赋值操作符,单目操作符的具体使用,如果你还有所困惑不妨自己动手实操一下,这方面的知识是稍微有点抽象,需要咱们反复的练习熟悉起来才行。

以上就是关于操作符的第二部分内容,后面其他的操作符应用详解会在近期分批次更新,敬请期待!!

好了,如果你有任何疑问欢迎在评论区或者私信我提出,大家下次再见啦!

新人博主创作不易,如果感觉文章内容对你有所帮助的话不妨三连一下这个新人博主再走呗。你们的支持就是我更新的动力!!!


**(可莉请求你们三连支持一下博主!!!点击下方评论点赞收藏帮帮可莉吧)**


20fa3306e76244de9879742c165c792a.gif

目录
相关文章
|
12天前
|
C语言
C语言操作符(补充+面试)
C语言操作符(补充+面试)
23 6
|
7天前
|
存储 编译器 C语言
十一:《初学C语言》— 操作符详解(上)
【8月更文挑战第12天】本篇文章讲解了二进制与非二进制的转换;原码反码和补码;移位操作符及位操作符,并附上多个教学代码及代码练习示例
19 0
十一:《初学C语言》—  操作符详解(上)
|
1天前
|
存储 C语言 索引
【C语言篇】操作符详解(下篇)
如果某个操作数的类型在上⾯这个列表中排名靠后,那么⾸先要转换为另外⼀个操作数的类型后执⾏运算。
|
1天前
|
程序员 编译器 C语言
【C语言篇】操作符详解(上篇)
这是合法表达式,不会报错,但是通常达不到想要的结果, 即不是保证变量 j 的值在 i 和 k 之间。因为关系运算符是从左到右计算,所以实际执⾏的是下⾯的表达式。
|
1月前
|
编译器 C语言
【C语言初阶】指针篇—下
【C语言初阶】指针篇—下
|
1月前
|
存储 C语言
【C语言初阶】指针篇—上
【C语言初阶】指针篇—上
|
1月前
|
搜索推荐 程序员 C语言
指针赋值与引用传递:C语言的基础知识与实践技巧
指针赋值与引用传递:C语言的基础知识与实践技巧
|
6天前
|
存储 C语言
【C语言函数】static和extern关键字修饰
【C语言函数】static和extern关键字修饰
|
1天前
|
编译器 程序员 C语言
【C语言篇】从零带你全面了解函数(包括隐式声明等)(下篇)
⼀般情况下,企业中我们写代码时候,代码可能⽐较多,不会将所有的代码都放在⼀个⽂件中;我们往往会根据程序的功能,将代码拆分放在多个⽂件中。
|
22小时前
|
C语言
【C语言】字符串及其函数速览
【C语言】字符串及其函数速览
11 4