C语言第十六弹---操作符(下)

news2024/10/7 20:30:32

  ✨个人主页: 熬夜学编程的小林

💗系列专栏: 【C语言详解】 【数据结构详解】

操作符

1、下标访问[]、函数调用()

1.1、[ ] 下标引用操作符

1.2、函数调用操作符

2、结构成员访问操作符

2.1、结构体

2.1.1、结构的声明

2.1.2、结构体变量的定义和初始化

2.2、结构成员访问操作符

2.2.1、结构体成员的直接访问

2.2.2、结构体成员的间接访问

3、操作符的属性:优先级、结合性

3.1、优先级

3.2、结合性

4、表达式求值

4.1、整型提升

4.2、算术转换

4.3、问题表达式解析

4.3.1、表达式1

4.3.2、表达式2

4.3.3、表达式3

4.3.4、表达式4

4.3.5、表达式5:

4.4、总结


1、下标访问[]、函数调用()

1.1、[ ] 下标引用操作符

操作数:⼀个数组名 + ⼀个索引值
int arr[10];//创建数组
arr[9] = 10;//实⽤下标引⽤操作符。
[ ]的两个操作数是arr和9。

1.2、函数调用操作符

接受⼀个或者多个操作数:第⼀个操作数是 函数名 ,剩余的操作数就是传递给函数的 参数
#include <stdio.h>
void test1()
{
 printf("hehe\n");
}
void test2(const char *str)
{
 printf("%s\n", str);
}
int main()
{
 test1(); //这⾥的()就是作为函数调⽤操作符。
 test2("hello world");//这⾥的()就是函数调⽤操作符。test2为函数名,"hello world"为参数
 return 0;
}

2、结构成员访问操作符

2.1、结构体

C语言已经提供了内置类型,如:char、short、int、long、float、double等,但是只有这些内置类
型还是不够的,假设我想描述学生,描述⼀本书,这时单⼀的内置类型是不行的。描述⼀个学生需要名字、年龄、学号、身高、体重等;描述⼀本书需要作者、出版社、定价等。C语⾔为了解决这个问题,增加了 结构体这种自定义的数据类型,让程序员可以自己创造适合的类型。
结构是⼀些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量,如:
标量、数组、指针,甚至是其他结构体。

2.1.1、结构的声明

struct tag
{
 member-list;//成员列表
}variable-list;//全局结构体变量
描述⼀个学生:
struct Stu
{
 char name[20];//名字
 int age;//年龄
 char sex[5];//性别
 char id[20];//学号
}; //分号不能丢

2.1.2、结构体变量的定义和初始化

//代码1:变量的定义
struct Point
{
 int x;
 int y;
}p1; //声明类型的同时定义全局变量p1
struct Point p2; //定义结构体变量p2 在main函数内则是局部变量,main函数外则是全局变量
//代码2:初始化。
struct Point p3 = {10, 20};
struct Stu //类型声明
{
 char name[15];//名字
 int age; //年龄
};
struct Stu s1 = {"zhangsan", 20};//初始化
struct Stu s2 = {.age=20, .name="lisi"};//指定顺序初始化
//代码3
struct Node
{
 int data;
 struct Point p;
 struct Node* next; 
}n1 = {10, {4,5}, NULL}; //结构体嵌套初始化
struct Node n2 = {20, {5, 6}, NULL};//结构体嵌套初始化

2.2、结构成员访问操作符

2.2.1、结构体成员的直接访问

结构体成员的直接访问是通过点操作符(.)访问的。点操作符接受两个操作数。
如下所示:
#include <stdio.h>
struct Point
{
 int x;
 int y;
}p = {1,2};//创建全局变量以及初始化
int main()
{
 printf("x: %d y: %d\n", p.x, p.y);//打印结构体中x y的值
 return 0;
}
使用方式:结构体变量.成员名

2.2.2、结构体成员的间接访问

有时候我们得到的不是⼀个结构体变量,而是得到了⼀个 指向结构体的指针 。如下所示:
#include <stdio.h>
struct Point
{
 int x;
 int y;
};
int main()
{
 struct Point p = {3, 4};//创建局部变量以及初始化
 struct Point *ptr = &p;//ptr位结构体类型指针变量 *代表指针符号 ptr指向p的地址 &为取地址符号
 ptr->x = 10;
 ptr->y = 20;
 printf("x = %d y = %d\n", ptr->x, ptr->y);
 return 0;
}
使用方式:结构体指针->成员名
注:结构体的间接访问只需知道这个东西即可,后面自定义类型章节还会详细讲解间接访问。
综合举例:
#include <stdio.h>
#include <string.h>
struct Stu
{
 char name[15];//名字
 int age; //年龄
};
void print_stu(struct Stu s)
{
 printf("%s %d\n", s.name, s.age);
}
void set_stu(struct Stu* ps)
{
 strcpy(ps->name, "李四");
 ps->age = 28;
}
int main()
{
 struct Stu s = { "张三", 20 };
 print_stu(s);//打印结构体
 set_stu(&s);//修改结构体值 
 print_stu(s);//打印结构体
 return 0;
}

注:修改值需要传地址,因为形参是实参的一份临时拷贝,改变形参不会影响实参。在后序指针还会详细讲解。

3、操作符的属性:优先级、结合性

C语言的操作符有2个重要的属性: 优先级、结合性,这两个属性决定了表达式求值的计算顺序。

3.1、优先级

优先级指的是,如果⼀个表达式包含多个运算符,哪个运算符应该优先执行。各种运算符的优先级是不⼀样的。
3 + 4 * 5;
上面示例中,表达式 3 + 4 * 5
里面既有加法运算符( + ),⼜有乘法运算符( * )。由于 乘法的优先级高于加法 ,所以会先计算 4 * 5 ,而不是先计算 3 + 4

3.2、结合性

如果两个运算符优先级相同,优先级没办法确定先计算哪个了,这时候就看结合性了,则根据运算符是左结合,还是右结合,决定执行顺序。大部分运算符是左结合(从左到右执行),少数运算符是右结合(从右到左执行),比如赋值运算符( = )。
5 * 6 / 2;
上面示例中, * / 的优先级相同,它们都是左结合运算符,所以从左到右执行,先计算 5 * 6
再计算 6 / 2
运算符的优先级顺序很多,下面是部分运算符的优先级顺序(按照优先级从高到低排列),建议大概记住这些操作符的优先级就行,其他操作符在使用的时候查看下面表格就可以了。
圆括号( ()
增运算符( ++ ),自减运算符( --
单目运算符( + -
乘法( * ),除法( /
加法( + ),减法( -
关系运算符( < > 等)
赋值运算符( =
由于圆括号的优先级最高,可以使用它改变其他运算符的优先级。
参考:运算符优先级

4、表达式求值

4.1、整型提升

C语言中整型算术运算总是至少以缺省整型类型的精度来进行的。( 即储存数据类型小于整型储存的32比特位时就使小于32比特位的数据类型整型提升为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型(int),这种转换称为整型提升。
整型提升的意义:
表达式的整型运算要在CPU的相应运算器件内执⾏,CPU内整型运算器(ALU)的操作数的字节长度⼀般就是int的字节长度,同时也是CPU的通用寄存器的长度。
因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度。 通用CPU(general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigned int,然后才能送入CPU去执行运算。
//实例1
char a,b,c;
...
a = b + c;
b和c的值被提升为普通整型,然后再执行加法运算。
加法运算完成之后,结果将被截断,然后再存储于a中。
如何进行整体提升呢?
1. 有符号整数提升是按照变量的数据类型的符号位来提升的
2. 无符号整数提升,⾼位补0
//负数的整形提升
char c1 = -1;
变量c1的⼆进制位(补码)中只有8个⽐特位:
1111111
因为 char 为有符号的 char
所以整形提升的时候,⾼位补充符号位,即为1
提升之后的结果是:
11111111111111111111111111111111
//正数的整形提升
char c2 = 1;
变量c2的⼆进制位(补码)中只有8个⽐特位:
00000001
因为 char 为有符号的 char
所以整形提升的时候,⾼位补充符号位,即为0
提升之后的结果是:
00000000000000000000000000000001
//⽆符号整形提升,⾼位补0

4.2、算术转换

如果某个操作符的各个操作数属于不同的类型,那么除非其中⼀个操作数的转换为另⼀个操作数的类型,否则操作就⽆法进行。下面的层次体系称为寻常算术转换。
long double
double
float
unsigned long int
long int
unsigned int
int
如果某个操作数的类型在上面这个列表中 排名靠后 ,那么 首先要转换为另外⼀个操作数的类型 后执行运算。

4.3、问题表达式解析

4.3.1、表达式1

//表达式的求值部分由操作符的优先级决定。
//表达式1
a*b + c*d + e*f
表达式1在计算的时候, 由于 * 比 + 的优先级高,只能保证 * 的计算是比 + 早 但是优先级并不
能决定第三个 * 比第⼀个 + 早执行。
所以表达式的计算机顺序就可能是:
a*b
c*d
a*b + c*d
e*f
a*b + c*d + e*f

或者

a*b
c*d
e*f
a*b + c*d
a*b + c*d + e*f

4.3.2、表达式2

//表达式2
c + --c;
同上,操作符的优先级 只能决定自减 -- 的运算在 + 的运算的前面 ,但 是我们并没有办法得知, + 操作符的左操作数的获取在右操作数之前还是之后求值 所以结果是不可预测的,是有歧义的。

4.3.3、表达式3

//表达式3
int main()
{
 int i = 10;
 i = i-- - --i * ( i = -3 ) * i++ + ++i;
 printf("i = %d\n", i);
 return 0;
}
表达式3在不同编译器中测试结果:非法表达式程序的结果

4.3.4、表达式4

#include <sdtio.h>
int fun()
{
 static int count = 1;
 return ++count;
}
int main()
{
 int answer;
 answer = fun() - fun() * fun();
 printf( "%d\n", answer);//输出多少?
 return 0;
}

这个代码有没有实际的问题?有问题!
虽然在大多数的编译器上求得结果都是相同的。
但是上述代码 answer = fun() - fun() * fun(); 中我们 只能通过操作符的优先级得知:先
算乘法,再算减法。 函数的调用先后顺序⽆法通过操作符的优先级确定。

4.3.5、表达式5:

//表达式5
#include <stdio.h>
int main()
{
 int i = 1;
 int ret = (++i) + (++i) + (++i);
 printf("%d\n", ret);
 printf("%d\n", i);
 return 0;
}
//尝试在linux 环境gcc编译器,VS2022环境下都执⾏,看结果。

VS2022运行结果:

看看同样的代码产生了不同的结果,这是为什么?
简单看⼀下汇编代码,就可以分析清楚.
这段代码中的 第⼀个 + 在执行的时候,第三个++是否执行,这个是不确定的 ,因为 依靠操作符的优先级和结合性是无法决定第⼀个 + 和第三个前置 ++ 的先后顺序。

4.4、总结

即使有了操作符的优先级和结合性,我们写出的表达式依然有可能不能通过操作符的属性确定唯⼀的计算路径,那这个表达式就是存在潜在风险的,建议不要写出特别负责的表达式。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1427787.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Rust学习之Features

Rust学习之Features 一 什么是 Features二 默认 feature三 简单的features应用示例四 可选(optional)的依赖五 依赖的特性5.1 在依赖表中指定5.2 在features表中指定 六 命令行中特性控制七 特性统一路径八 其它8.1 相互排斥特性8.2 观察启用特性8.3 [Feature resolver version…

【Java程序设计】【C00234】基于Springboot的美食生活分享平台(有论文)

基于Springboot的美食生活分享平台&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的美食生活分享平台 主要功能如下&#xff1a;用户模块管理、美食分享笔记管理、美食笔记详情管理、公告信息管理、用户评论模块管…

node 第二十四天 mongoDB shell 命令 高级方法 $where aggregate聚合

$where 数据库数据如下 使用where语法如下 等价于 2.aggregate 聚合 使用聚合管道执行聚合操作。该管道允许用户通过一系列基于阶段的操作来处理来自集合或其他源的数据。 过滤数据, 分组数据 (排除name为 AAA 的数据 按price进行分组 每匹配一组计数1) 下面我们用aggregate…

three.js CSS3DRenderer、CSS3DSprite渲染HTML标签

有空的老铁关注一下我的抖音&#xff1a; 效果: <template><div><el-container><el-main><div class"box-card-left"><div id"threejs" style"border: 1px solid red;position: relative;"></div><…

C++学习Day01之初识C++ Helloworld

目录 一、程序二、输出三、分析与总结 一、程序 #include <iostream> //标准输入输出流 i - input 输入 o - output 输出 stream 流 相当于 stdio.h using namespace std; //使用 标准 命名空间 //程序入口函数 int main() {// cout 标准输出流对象// <&l…

英语文件怎么翻译成中文?五个软件轻松应对英文文件翻译

英语文件怎么翻译成中文&#xff1f;随着全球化的发展&#xff0c;我们时常需要处理英文文件。对于非英语母语者来说&#xff0c;准确、快速地将英文文件翻译成中文变得至关重要。本文将介绍5款翻译软件&#xff0c;帮助你轻松应对英文文件的翻译工作。 1.智能翻译官 智能翻译…

【代码随想录-链表】环形链表

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学习,不断总结,共同进步,活到老学到老导航 檀越剑指大厂系列:全面总结 jav…

BetrFS: A Compleat File System for Commodity SSDs——论文阅读

EuroSys 2022 Paper 分布式元数据论文汇总 问题 在不同的工作负载下&#xff0c;没有单一的Linux文件系统在普通SSD上始终表现良好。我们将一个完备的文件系统定义为在各种微基准测试和应用程序中&#xff0c;没有一个工作负载的性能低于最佳文件系统性能的30%&#xff0c;并…

代码随想录算法训练营29期|day36任务以及具体安排

第八章 贪心算法 part05 435. 无重叠区间 class Solution {public int eraseOverlapIntervals(int[][] intervals) {Arrays.sort(intervals, (a,b)-> {return Integer.compare(a[0],b[0]);});if(intervals.length 1) return 0;int result 0;for(int i 1 ; i < interva…

Unity | YooAssetV2.1.0 + HybridCLR热更新

目录 一、项目更改 二、使用YooAsset热更 1.资源配置 2.资源构建 3.将两个文件夹下的资源上传CDN服务器 4.修改代码 5.运行效果 本文记录利用YooAssetHybridCLR来进行资源和dll的更新。YooAsset使用的是新版V2.1.0。相比于旧版&#xff0c;dll(原生文件)和资源要建两个p…

AI-数学-高中-17-三角函数的定义

原作者视频&#xff1a;三角函数】4三角函数的定义&#xff08;易&#xff09;_哔哩哔哩_bilibili 初中&#xff1a; 高中&#xff1a;三角函数就是单位圆上的点的横纵坐标(x0,y0)。 示例1&#xff1a; 规则&#xff1a; 示例2&#xff1a; 示例3.1&#xff1a; 示例3.2 示例4…

VBA数据库解决方案第八讲:SQL语句及打开记录集

《VBA数据库解决方案》教程&#xff08;版权10090845&#xff09;是我推出的第二套教程&#xff0c;目前已经是第二版修订了。这套教程定位于中级&#xff0c;是学完字典后的另一个专题讲解。数据库是数据处理的利器&#xff0c;教程中详细介绍了利用ADO连接ACCDB和EXCEL的方法…

C语言递归与迭代并举:双重视角下的C语言阶乘计算实现

引言 计算一个正整数的阶乘是常见的数学问题。阶乘的定义为&#xff1a;n的阶乘&#xff08;记作n!&#xff09;是所有小于及等于n的正整数的乘积。例如&#xff0c;5的阶乘&#xff08;5!&#xff09;就是54321120。下面我们将通过一个使用递归方法实现阶乘的C语言代码示例&am…

POI操作word表格,添加单元格,单元格对齐方法(不必合并单元格)

添加单元格&#xff0c;直接对row进行create新的cell&#xff0c;则会导致新创建的单元格与前面的单元格不对齐的现象。 //表格信息XWPFTable table doc.createTable();table.setWidth("100%");//第一行XWPFTableRow row0table.getRow(0);XWPFTableCell cell00row0.…

STM32GPIO(流水灯、蜂鸣器案例)

文章目录 一、介绍GPIO简介GPIOGPIO基本结构GPIO位结构GPIO模式 二、外设介绍LED、蜂鸣器简介硬件电路 面包板介绍 三、实现LED闪烁连接LED线路具体程序引入Delay具体代码如下&#xff1a; 四、实现流水灯组装线路根据GPIO_Init中结构体成员GPIO_Pin的定义&#xff0c;可以使用…

Redis学习——高级篇⑦

Redis学习——高级篇⑦ Redis7之缓存预热 缓存雪崩 缓存击穿 缓存穿透&#xff08;八&#xff09; 8.1 缓存预热8.1.1 是什么8.1.2 解决 8.2 缓存雪崩8.2.1 是什么8.2.2 发生8.2.3 预防 解决 8.3 缓存穿透8.3.1 是什么8.3.2 解决1 空对象缓存或者缺省值2 Goo…

【Linux网络编程三】Udp套接字编程(简易版服务器)

【Linux网络编程三】Udp套接字编程(简易版服务器&#xff09; 一.创建套接字二.绑定网络信息1.构建通信类型2.填充网络信息①网络字节序的port②string类型的ip地址 3.最终绑定 三.读收消息1.服务器端接收消息recvfrom2.服务器端发送消息sendto3.客户端端发送消息sendto4.客户端…

前端小案例——滚动文本区域(HTML+CSS, 附源码)

一、前言 实现功能: 这个案例实现了一个具有滚动功能的文本区域&#xff0c;用于显示长文本内容&#xff0c;并且可以通过滚动条来查看完整的文本内容。 实现逻辑&#xff1a; 内容布局&#xff1a;在<body>中&#xff0c;使用<div>容器创建了一个类名为listen_t…

【Java程序设计】【C00242】基于Springboot的冬奥会科普平台(有论文)

基于Springboot的冬奥会科普平台&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的冬奥会科普平台 本系统分为系统功能模块以及管理员功能模块。 系统功能模块&#xff1a;登录进入冬奥会科普平台可以查看首页&…

ToF 测距传感器 VL6180 测量范围修改(软件 I2C)

TOF 测距传感器 VL6180 传感器修改测量范围 ...... by 矜辰所致前言 之前写过一篇关于ToF 测距传感器 VL6180 使用的文章&#xff1a; ToF 测距传感器 VL6180 使用踩坑记&#xff08;软件 I2C&#xff09; 之后有粉丝问我如何修改测量距离&#xff0c;当时我只回答让粉丝去…