打卡:4.16和4.17 C语言篇 -初识C语言 - 操作符

Posted 小奔同学

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了打卡:4.16和4.17 C语言篇 -初识C语言 - 操作符相关的知识,希望对你有一定的参考价值。

C语言篇 -(1)初识C语言 - (8)操作符

前言

🎸C语言是非常灵活的
🎸C语言提供了非常丰富的操作符,使得使用起来就比较灵活,我们这篇来简单了解一下操作符
下面的有些操作符会不介绍,以后再说




🎸算术操作符🎸
⭐+    ⭐-    ⭐*    ⭐/    ⭐%
加      减      乘     除      取模

下面会重点讲一下⭐/和⭐%
🎸移位操作符🎸(涉及二进制的运算,学到这里再讲)
⭐>>          ⭐<<
右移操作符     左移操作符
🎸位操作符🎸(涉及二进制的运算,学到这里再讲)
⭐&      ⭐^         ⭐|
按位与    按位异或     按位或
🎸赋值操作符🎸
⭐=    ⭐+=    ⭐-=    ⭐*=    ⭐/= 

⭐&=   ⭐^=    ⭐|=    ⭐>>=   ⭐<<=

(后五个涉及二进制的运算,学到这儿再讲)
🎸单目操作符🎸
⭐!        ⭐-       ⭐+       ⭐&  
逻辑反操作  负值       正值       取地址

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

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

⭐--            ⭐++      
前置、后置--     前置、后置++

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

⭐(类型)       
强制类型转换
🎸关系操作符🎸
⭐>
⭐>=
⭐<
⭐<=
⭐!=       用于测试“不相等”
⭐==       用于测试“相等”
🎸逻辑操作符🎸
⭐&&          逻辑与

⭐||          逻辑或
🎸条件操作符🎸
⭐exp1 ? exp2 : exp3
🎸逗号表达式🎸
⭐exp1, exp2, exp3, …expN
🎸下标引用、函数调用和结构成员🎸
⭐[]     ⭐()     ⭐.     ⭐->



🎸算术操作符🎸

⭐+ ⭐- ⭐*就不介绍了,比较简单,就是你们理解的那样
我们来说一下⭐/和⭐%

int main()

	int a = 7 / 2;//除
	int b = 7 % 2;//取模
	printf("%d\\n", a);
	printf("%d\\n", b);

	return 0;

运行的结果:🔥
3(应为变量a是整型,不会四舍五入,只会取小数点前面的整数)
1(取模就是取余数)

我们定义a是一个浮点型变量,/左右的操作数必须要有一个是浮点型,或者都是浮点型,我们来看一下不是浮点型的情况

🎸浮点型变量,整型操作数

int main()

	float a = 7 / 2;//除
	int b = 7 % 2;//取模
	printf("%f\\n", a);
	printf("%d\\n", b);

	return 0;

运行的结果:
3.000000(操作数没有一个是浮点型,就会导致3.500000变成3.000000)
1

🎸浮点型变量,浮点型操作数

int main()

	float a = 7 / 3.0;//除
	int b = 7 % 2;//取模
	printf("%f\\n", a);
	printf("%d\\n", b);

	return 0;

运行的结果:🔥
2.333333
1

如果要保留浮点型前几位,那就在%f中间加上.保留位数
例如%.2f,保留两位

int main()

float a = 7 / 3.0;//除
int b = 7 % 2;//取模
printf("%.2f\\n", a);
printf("%d\\n", b);

return 0;

运行的结果:🔥
2.33
1

取模的操作数一个都不可以是浮点数,否则就会报错

int main()

	float a = 7 / 2.0;//除
	float b = 7 % 2.0;//取模
	printf("%.2f\\n", a);
	printf("%f\\n", b);

	return 0;

运行的结果:🔥




🎸赋值操作符🎸

⭐=

int main()

	int a = 0;//像这个创建一个变量的时候给它一个值叫做初始化
    a = 20;//赋值=
    
	return 0;


⭐+=
⭐-=

int main()

	int a = 0;
	int b = 5;
	//像这个创建一个变量的时候给它一个值叫做初始化
	
    a=a+3;
    a+=3;//就相当于a=a+3;
  
    a=a-3;
    a-=3;//就相当于a=a-3;
	return 0;




🎸单目操作符🎸

 a  +  b;
    +   //操作符有两个操作数的就是双目操作符
 + a;
 +      //操作符只有一个操作数的就是单目操作符

在c语言中,我们用0表示假,非0表示真
!就是把假变成真,把真变成假,就像下面这样

int main()

	int flag = 0;//flag假
	if (!flag)//!flag真
		printf("真");
	else
		printf("假");
	return 0;

运行的结果:🔥


⭐-
负号
把符号颠倒,把正的变成负的,把负的变成正的

int main()

	int a = -10; //只有一个操作数的就是单目操作符
	int b = -a; //只有一个操作数的就是单目操作符
	printf("%d", b);
	return 0;

运行的结果:🔥
10


⭐+
加号
+a与a是等同的,不会令负数变成一个正数


⭐sizeof
sizeof是操作符,是单目操作符,可以计算变量和类型所占内存的大小,单位是字节

int main()

	int a = 10;
	printf("%zu\\n", sizeof(a));
	printf("%zu\\n", sizeof(int));

	return 0;


运行的结果:🔥
4
4

如果用来计算数组的大小,我们来看一下:

int main()

	int arr[] =  1,2,3,4,5 ;
	printf("%zu\\n", sizeof(arr));
	
	return 0;

运行的结果:🔥
很明显是4×5=20(在c语言中,是没有这些×÷符号的,要用c语言可以识别出来的符号*/)

也可以用这个sizeof(arr)/sizeof(arr[0])来计算数组中有几个元素

int main()

	int a = 10;
	int arr[] =  1,2,3,4,5 ;
	printf("%zu\\n", sizeof(arr) / sizeof(arr[0]));
	return 0;


运行的结果:🔥
20(数组占20个字节大小)
5 (数组里面有五个元素)

sizeof不是函数,所以也可以把sizeof(a)变成sizeof a括号是可以省去的,这一点可以证明sizeof不是函数
但对于类型来说,括号是不可以省略掉的


⭐- -和⭐++
分前置和后置

i++;//后置++,先使用,后++
++i;//后置++,先++,后使用
i--;//后置++,先使用,后++
--i;//后置++,先--,后使用

看一下下面的代码,小奔只举一个++的例子,或者自己动手操作一下

int main()

	int a = 0;
	int b = a++;
	printf("一%d %d\\n", a, b);
	//b先使用了a=0这个值,然后a再++变成1
	int c = ++a;
	printf("二%d %d\\n", a, c);
	//a先++变成2,c再使用a=2这个值

	return 0;

运行的结果:🔥
一1 0
二2 2


⭐(类型)

int main()

	//int a = 3.14;
	int a = (int)3.14;
	//3.14  字面浮点数,编译器默认理解为double,我们用(int)来把它强制认为是int类型
	printf("%d", a);
	return 0;

运行的结果:🔥
3




🎸关系操作符🎸

关系操作符是用来判断关系的,举一个例子

a < 10;
a <= 10;
a == 10;

判断a10的关系,成立就是真,不成立就是假
在这里我们来说一下===两个的区别,非常容易错

int main()

	int a = 10;

	if (a = 3)
		printf("%d", a);

	return 0;

你认为它输出的结果是什么?
运行一下🔥
结果是3

哎,你看到,你明明输入的a10,为啥打印的是3呢?
在这里小奔告诉你,=是赋值操作符,是给变量一个值的作用,而==是关系操作符,它才是判断是否相等的操作符

应该这样

int main()

	int a = 10;

	//if (a = 3)
	if (a == 3)
		printf("%d", a);

	return 0;

运行的结果:🔥

可以看出来,a不等于3,所以为假,不执行if下面的操作,也就是不打印a的值




🎸逻辑操作符🎸

再来讲一下&&||的关系
哎,你有两只手,有一个桌子&&,和一个椅子||,桌子&&要两只手才能搬动,椅子||一只手就可以搬动
同理,
&&真,就是真
&&假,就是假
&&假,就是假

||真,就是真
||假,就是真
||假,就是假

写个代码试一下:

int main()

	int a = 10;
	int b = 20;
	
	if (a <= 20 && b >= 10)
		printf("真");
	else
		printf("假");

	return 0;

运行的结果:🔥


其他的自己试一试,在这里就不写了




🎸条件操作符🎸

⭐exp1 ? exp2 : exp3
它有三个操作数,所以是三目操作符
它的意思是判断exp1是否为真,是真的话输出exp2的值,是假的话输出exp3的值
举例来使用一下

int main()

	int a = 10;
	int b = 20;
	//求最大值
	int r = a > b ? a : b;
//a>b是假,输出b的值,所以r=b=20
	printf("%d", r);
	return 0;

运行的结果:🔥
20

int r = a > b ? a : b;

上面的代码就类似于下面的代码

	if (a > b)
		r = a;
	else
		r = b;



🎸逗号表达式🎸

⭐exp1,exp2,exp3…expN
特点:从左到右依次计算,整个表达式的结果是最后一个表达式的结果
用法直接用代码来演示一下

int main()

	int a = 10;
	int c = 0;
	int b = (a = a + 2, c = a - 3, c - 3);
//b最后等于的是最后面的表达式
//a = a + 2 = 12
//c = a - 3 = 9
//c - 3 = 6
//b = 6
	printf("%d", b);
	return 0;

运行的结果:🔥




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

⭐[ ]
在代码里面解释

int main()

	int arr[10] =  1,2,3,4,5,6,7,8,9,10 ;
//定义数组大小的时候是不可以在[]里用变量的

	arr[5];//[]就是下标引用操作符
	//arr和5都是操作数

	int n = 5;
	arr[n];//这里是可以用变量的
	//这里的n是来访问下标是n的元素,在定义数组大小的时候是不可以用变量的

	return 0;

⭐()
函数调用操作符

int Add(int x)

	return x + 5;


int main()

	int a = 10;

	a = Add(a);
//()函数调用操作符,Add,a都是()的操作数
//sizeof的()是可以省掉的,所以它不是函数
//函数是不可以省去()

	printf("%d", a);
	return 0;

今天结束了,写了两天,太多了,下一篇介绍关键字

Java实习生每日面试题打卡——操作系统篇

  • 临近秋招,备战暑期实习,祝大家每天进步亿点点!Day15
  • 本篇总结的是 操作系统 相关的面试题,后续会每日更新~

在这里插入图片描述


1、请分别简单说一说进程和线程以及它们的区别?

  • 根本区别:进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位。
  • 包含关系:一个进程最少由一条线程组成。
  • 所处环境区别:在操作系统中能同时运行多个进程(程序);而在同一个进程中有多个线程同时执行(通过CPU调度,在每个时间片中只有一个线程执行)。
  • 内存分配:系统在运行的时候会为每个进程分配不同的内存空间;而对线程而言,除了CPU外,系统不会为线程分配内存(线程所使用的资源来自其所属进程的资源),线程组之间只能共享资源。

2、进程间的通信方式有哪些?

  • 管道:管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
  • 命名管道FIFO:未命名的管道只能在两个相关的进程之间通信,通过命名管道FIFO,不相关的进程也能交换数据。
  • 消息队列
    • 消息队列是消息的链表,具有特定的格式,存放在内存中并由消息队列标识符标识。
    • 消息队列允许一个或多个进程向它写入与读取消息。
    • 管道和命名管道的通信数据都是先进先出原则,消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取,比FIFO更有优势。
  • 共享内存:共享内存是允许一个或多个进程共享的一块内存区域。
  • 信号量:信号量是一个计数器,可以用来控制多个进程对共享资源的访问。通常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。

3、线程同步的方式有哪些?

  • 互斥量:采用互斥对象机制,只有拥有互斥对象的线程才有访问公共资源的权限。因为互斥对象只有一个,所以可以保证公共资源不会被多个线程同时访问。
  • 信号量:它允许同一时刻多个线程访问同一资源,但是需要控制同一时刻访问此资源的最大线程数量。
  • 事件(信号):通过通知操作的方式来保持多线程同步,还可以方便的实现多线程优先级的比较操作。

4、进程的状态及其转换

进程的状态有:就绪状态、运行状态、阻塞状态。

进程状态间的转换关系为:


5、Java线程的状态

Java 线程有以下几个状态:

  • 新建状态(New)
  • 就绪状态(Runnable)
  • 运行状态(Running)
  • 阻塞状态(Blocked):
    • 等待阻塞
    • 同步阻塞
    • 其他阻塞
  • 死亡状态(Dead)

6、进程的调度算法有哪些?

  • 先来先服务算法
  • 短作业优先算法
  • 优先权调度算法
  • 时间片轮转调度算法

参考文章:几个常用的操作系统进程调度算法


7、死锁产生的原因,死锁产生的必要条件是什么,如何预防死锁,如何避免死锁?

**死锁产生的原因:**资源竞争、进程推进顺序不当。

死锁产生的四个必要条件:

  • 互斥:某个资源一次只允许一个进程访问,即该资源一旦分配给某个进程,其他进程就不能再访问了,直到该进程访问结束。
  • 不可剥夺:进程所获得的资源在未使用完毕之前,不能被其他进程强行剥夺,只能由获得该资源使用权的进程释放资源。
  • 占有且等待:一个进程请求某个资源并将其占有,即使该进程被阻塞了,也不会释放占有的资源。
  • 循环等待:若干进程之间形成一种头尾相接的环形循环等待链。

**预防死锁:**破坏产生死锁的四个必要条件之一即可。

死锁的解除:

  • 强制性地从系统中撤销一个或多个死锁的进程以断开循环等待链。
  • 强制性抢占死锁进程正在争取的资源以解除死锁。

8、进程的上下文切换

一个进程切换到另一个进程运行,称为进程的上下文切换。进程是由内核管理和调度的,所以进程的切换只能发生在内核态。


9、操作系统的内存管理机制了解吗?内存管理有哪⼏种⽅式?

  • 块式管理:远古时代的计算机操系统的内存管理⽅式。将内存分为⼏个固定⼤⼩的块,每 个块中只包含⼀个进程。如果程序运⾏需要内存的话,操作系统就分配给它⼀块,如果程序 运⾏只需要很⼩的空间的话,分配的这块内存很⼤⼀部分⼏乎被浪费了。这些在每个块中未 被利⽤的空间,我们称之为碎⽚。
  • ⻚式管理:把主存分为⼤⼩相等且固定的⼀⻚⼀⻚的形式,⻚᫾⼩,相对相⽐于块式管理的 划分⼒度更⼤,提⾼了内存利⽤率,减少了碎⽚。⻚式管理通过⻚表对应逻辑地址和物理地址。
  • 段式管理:⻚式管理虽然提⾼了内存利⽤率,但是⻚式管理其中的⻚实际并⽆任何实际意 义。 段式管理把主存分为⼀段段的,每⼀段的空间⼜要⽐⼀⻚的空间⼩很多 。但是,最重 要的是段是有实际意义的,每个段定义了⼀组逻辑信息,例如,有主程序段 MAIN、⼦程序段 X、数据段 D 及栈段 S 等。 段式管理通过段表对应逻辑地址和物理地址。

10、 CPU 寻址了解吗?为什么需要虚拟地址空间?

处理器使⽤的是⼀种称为虚拟寻址的寻址⽅式。使⽤虚拟寻址,CPU 需要将虚拟地址翻译成物理地址,这样才能访问到真实的物理内存。 实际上完成虚拟地址转换为物理地址转换的硬件是 CPU 中含有⼀个被称为内存管理单元 的硬件。


11、什么是用户态和核心态?

在计算机系统中,分两种程序:系统程序和应用程序,为了保证系统程序不被应用程序有意或无意地破坏,为计算机设置了两种状态——用户态、核心态。

  • 用户态:只能受限的访问内存,运行所有的应用程序。
  • 核心态:运行操作系统程序,CPU 可以访问内存的所有数据,包括外围设备。

12、操作系统内存管理方式,分页分段以及段页式的优缺点?

内存管理方式:块式管理、页式管理、段式管理、段页式管理。

分段管理:

  • 在段式存储管理中,将程序的地址空间划分为若干段(segment),如代码段,数据段,堆栈段;这样每个进程有一个二维地址空间,相互独立,互不干扰。段式管理的优点是:没有内碎片(因为段大小可变,改变段大小来消除内碎片)。但段换入换出时,会产生外碎片(比如4k的段换5k的段,会产生1k的外碎片)。

分页管理

  • 在页式存储管理中,将程序的逻辑地址划分为固定大小的页(page),而物理内存划分为同样大小的页框,程序加载时,可以将任意一页放入内存中任意一个页框,这些页框不必连续,从而实现了离散分离。页式存储管理的优点是:没有外碎片(因为页的大小固定),但会产生内碎片(一个页可能填充不满)。

段页式管理

  • 段⻚式管理机制结合了段式管理和⻚式管理的优点。简单来说段⻚式管理机制就是把主存先分成若⼲ 段,每个段⼜分成若⼲⻚,也就是说 段⻚式管理机制 中段与段之间以及段的内部的都是离散的。

13、讲一讲操作系统的I/O模型?什么是I/O多路复用?

I/O请求有两个阶段:

  • 等待资源阶段:I/O请求一般需要请求特殊的资源(如磁盘、RAM、文件),当资源被上一个使用者使用没有被释放时,IO请求就会被阻塞,直到能够使用这个资源。
  • 使用资源阶段:真正进行数据接收和发送。

在等待数据阶段,I/O分为 阻塞I/O 模型 和 非阻塞I/O 模型:

  • 阻塞I/O 模型: 资源不可用时,I/O请求一直阻塞,直到反馈结果(有数据或超时)。
  • 非阻塞I/O 模型:资源不可用时,I/O请求不会被阻塞,直接返回数据标识资源不可用。但是进程会不停的去轮询检测资源是否可用。

在使用资源阶段,I/O分为 同步I/O 模型 和 异步I/O 模型。

  • 同步I/O 模型:应用阻塞在发送或接收数据的状态,直到数据成功传输或返回失败结果。
  • 异步I/O 模型:应用发送或接收数据后立刻返回,数据写入操作系统缓存,由操作系统完成数据发送或接收,并返回成功或失败的信息给应用。

I/O多路复用(I/O复用模型):

  • I/O 多路复用可以同时阻塞多个I/O操作,而且可以同时对多个读操作,多个写操作的I/O函数进行检测,直到有数据可读或可写。

正因为阻塞I/O只能阻塞一个I/O操作,而I/O复用模型能够阻塞多个I/O操作,所以才叫做多路复用

14、什么是生产者消费者模型?

对于生产者:

  • 在操作系统中,生产者生产一条数据,首先查看缓冲区能否放入数据,有没有空的位置,如果有往下执行,否则说明缓冲区全满了,消费者还没有及时的来消费数据。这时候生产者会进入阻塞等待(会唤醒消费者去消费数据)。
  • 同样的,假设多个生产者都已经申请到执行权时,此时只能有一个生产者可以进入生产状态,所以其他几个生产者又要被阻塞一次。

对于消费者:

  • 消费者消费一条数据时,首先查看缓冲区是否有数据单元,如果有执行消费,否则消费者进入阻塞等待(会唤醒生产者去生产数据)。

总结的面试题也挺费时间的,文章会不定时更新,有时候一天多更新几篇,如果帮助您复习巩固了知识点,还请三连支持一下,后续会亿点点的更新!

在这里插入图片描述

以上是关于打卡:4.16和4.17 C语言篇 -初识C语言 - 操作符的主要内容,如果未能解决你的问题,请参考以下文章

JAVA实习生第十二次面试题打卡——Redis篇

JAVA实习生第十二次面试题打卡——Redis篇

每日打卡深圳35家公司JAVA面试真题-数据库篇

每日打卡应届生跳槽者必看JAVA面试题-数据库篇

(Java实习生)每日10道面试题打卡——JavaWeb篇

(Java实习生)每日10道面试题打卡——JavaWeb篇