【C语言初阶】带你轻松玩转所有常用操作符最终篇——下标引用、函数调用和结构体成员,表达式求值

news2024/11/18 1:26:28

在这里插入图片描述

君兮_的个人主页

勤时当勉励 岁月不待人

C/C++ 游戏开发


Hello,这里是君兮_,前几天非常忙没空更新,现在终于闲下来了,这是今天爆肝更新的第二篇,也是我们【C语言初阶】带你轻松玩转所有常用操作符的最后一篇,废话不多说,我们进入正题

  • 在正式开始之前,我们还是借助一张思维导图帮助大致简单回忆一下有关操作符的基础内容

在这里插入图片描述

  • 我们继续朝下讲最后的内容

操作符详解4

  • 一.下标引用、函数调用和结构体成员
    • 1. [ ] 下标引用操作符
    • 2.( ) 函数调用操作符
    • 3. 访问一个结构体的成员
      • "." 结构体.成员名
      • -> 结构体指针->成员名
  • 二.表达式求值
    • 1.隐式类型转换
      • 如何进行整体提升呢?
    • 2. 算术转换
    • 3 操作符的属性
    • 存在问题的一些表达式
  • 总结

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

1. [ ] 下标引用操作符

该操作符的操作数:一个数组名 + 一个索引值

int arr[10];//创建数组
arr[9] = 10;//实用下标引用操作符。
[ ]的两个操作数是arr和9。

  • 注意这里是说的arr和9只是“[ ]”两个操作数,因此我们也可以把该数组这样写:
9[arr];
  • 证明代码如下:
int main()
{
	int arr[10] = { 1,2,3,4,5 };//不完全初始化,此时后面未初始化元为0
	//              
	//数组的起始是有下标的,下标是0开始的
	printf("%d\n", arr[2]);//[] 下标引用操作符,arr 和 2 是[] 的两个操作数
	printf("%d\n", 2[arr]);
	return 0;
}

在这里插入图片描述

  • 但是通常为了代码的可读性和流畅性,我们最好别这么写,这里只是告诉你这样写也是对的!

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;
}
  • 非常简单,大家在日常也见识过很多次了,这里就不再细讲。

3. 访问一个结构体的成员

  • 通常有以下两种形式
. 结构体.成员名
-> 结构体指针->成员名

“.” 结构体.成员名

  • 这种通常用于直接访问结构体成员
struct Book
{
	char name[30];//成员
	char author[20];
	float price;
};


int main()
{
	struct Book b1 = { "C语言", "zz",99.6f };
	struct Book b2 = {"数据结构","yy",88.6f};//书
	printf("%s %s %.1f\n", b1.name, b1.author, b1.price);
	printf("%s %s %.1f\n", b2.name, b2.author, b2.price);

	//结构体变量.成员名
	return 0;
}

-> 结构体指针->成员名

  • 主要用于在结构体传参时通过结构体指针找到对应结构体成员
  • 代码如下:
struct Book
    {
    	char name[30];//成员
    	char author[20];
    	float price;
    };
    
    void Print(struct Book * p)
    {
    	printf("%s %s %.1f\n", (*p).name, (*p).author, (*p).price);
    	printf("%s %s %.1f\n", p->name, p->author, p->price);
    	//->
    	//结构指针->成员名
    }
    
    int main()
    {
        struct Book b1 = { "C语言", "zz",99.6f };
       	struct Book b2 = {"数据结构","yy",88.6f};//书
    	Print(&b1);
    	Print(&b2);
    
    
    	//printf("%s %s %.1f\n", b1.name, b1.author, b1.price);
    	//printf("%s %s %.1f\n", b2.name, b2.author, b2.price);
    
    	//结构体变量.成员名
    	return 0;
    }



二.表达式求值

  • 表达式求值的顺序一部分是由操作符的优先级和结合性决定。
    同样,有些表达式的操作数在求值的过程中可能需要转换为其他类型

1.隐式类型转换

  • C的整型算术运算总是至少 以缺省整型类型的精度 来进行的。
  • 为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升。
  • 整型提升的意义:
  • 表达式的整型运算要在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中。

如何进行整体提升呢?

  • 整形提升是按照变量的数据类型的符号位来提升的
  • 示例代码如下:
//负数的整形提升
char c1 = -1;
变量c1的二进制位(补码)中只有8个比特位:
1111111
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为1
提升之后的结果是:
11111111111111111111111111111111
//正数的整形提升
char c2 = 1;
变量c2的二进制位(补码)中只有8个比特位:
00000001
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为0
提升之后的结果是:
00000000000000000000000000000001
//无符号整形提升,高位补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 的结果是真.
    在这里插入图片描述
//实例2
int main()
{
char c = 1;
printf("%u\n", sizeof(c));
printf("%u\n", sizeof(+c));
printf("%u\n", sizeof(-c));//%u - 10进制的形式打印无符号的整数
return 0;
}
  • 实例2中的,c只要参与表达式运算,就会发生整形提升,表达式 +c ,就会发生提升,所以 sizeof(+c) 是4个字节.
  • 表达式 -c 也会发生整形提升,所以 sizeof(-c) 是4个字节,但是 sizeof( c ) ,就是1个字节.
    在这里插入图片描述

2. 算术转换

  • 如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数的转换为另一个操作数的类型,否则操作就无法进行
  • 下面的层次体系称为寻常算术转换

long double
double
float
unsigned long int
long int
unsigned int
int
上面类型由高—>低

  • 如果某个操作数的类型在上面这个列表中排名较低,那么首先要转换为另外一个操作数的类型后执行运算
  • 注意:
    算术转换要合理,要不然会有一些潜在的问题
float f = 3.14;
int num = f;//隐式转换,会有精度丢失

3 操作符的属性

  • 复杂表达式的求值有三个影响的因素。
    1. 操作符的优先级
    2. 操作符的结合性
    3. 是否控制求值顺序。
  • 两个相邻的操作符先执行哪个?取决于他们的优先级。如果两者的优先级相同,取决于他们的结合性。
  • 操作符优先级
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

存在问题的一些表达式

  • 例一
//表达式的求值部分由操作符的优先级决定。
//表达式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
  • 例二
//表达式2
c + --c;

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

  • 例三
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(); 中我们只能通过操作符的优先级得知:先算乘法,再算减法。
  • 函数的调用先后顺序无法通过操作符的优先级确定。
  • 例四
#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编译器,VS2013环境下都执行,看结果。
  • Linux环境的结果:
    在这里插入图片描述

  • VS2013环境的结果:
    在这里插入图片描述

  • 看看同样的代码产生了不同的结果,这是为什么?

  • 这段代码中的第一个 + 在执行的时候,第三个++是否执行,这个是不确定的,因为依靠操作符的优先级和结合性是无法决定第一个 + 和第三个前置 ++ 的先后顺序。

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


  • 资料引用:
    博客中有关操作符优先级的图片取自该博客:

    详解:操作符的优先级

总结

  • 今天的内容暂时到这里就结束了,我们今天就把所有有关操作符的知识点以及易错点都给讲完了。如果你还有问题的话一定要自己试一下,不然光看是非常容易遗忘的,咱们必须反复的练习才能熟悉起来!
  • 以上就是关于操作符的所有内容啦,我们通过四章节讲述了这一部分的内容,感兴趣可以翻翻以前有关的章节,链接我就贴在这里啦!
    【C语言初阶】带你轻松玩转所有常用操作符(1) ——算数操作符,移位操作符,位操作符
    【C语言初阶】带你轻松玩转所有常用操作符(2) ——赋值操作符,单目操作符
    【C语言初阶】带你轻松玩转所有常用操作符(3)——关系操作符,逻辑操作符,条件操作符,逗号表达式
  • 好了,如果你有任何疑问欢迎在评论区或者私信我提出,大家下次再见啦!

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

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

在这里插入图片描述

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

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

相关文章

nestjs post请求提交数据量太大会报错 [ExceptionsHandler] request entity too large

背景 在传给后端接口的数据&#xff0c;是一个超过1.5mb的json字符串&#xff0c;通过nest filter的时候直接被拦截掉了&#xff0c;返回【 请求体太长】的错误。 还没有到达contraller&#xff0c;就直接被框架拦截掉了&#xff0c; import { ExceptionFilter, Catch, Argu…

vue——实现表格的拖拽排序功能——技能提升

最近在写后台管理系统时&#xff0c;遇到一个需求&#xff0c;就是要实现表格的排序。 就是拖动某一行数据&#xff0c;放在指定位置&#xff0c;然后保存的时候根据最终的排序来处理生产单顺序字段。 参考大神的链接&#xff1a;vue-实现拖拽排序功能&#xff1a;https://ju…

mac苹果电脑,怎么批量修改文件名称

mac苹果电脑&#xff0c;如何批量修改文件名称&#xff1f;在苹果电脑上对文件名称进行修改是一件非常简单的操作&#xff0c;相信任何mac电脑用户都知道怎么操作&#xff0c;只需要选中要修改名称的文件&#xff0c;然后点击鼠标右键&#xff0c;然后会弹出一个菜单&#xff0…

layui代码记录

// 归档弹框jsguiDangRemarkInfo : function(activiti, buttonConf, call) {layui.use([layer, form, laydate], function () {var layer layui.layer;var form layui.form;var laydate layui.laydate;layer.open({type: 1,title: 归档备注信息,area: [350px, 300px],conten…

Redis 6.2.4集群搭建

1. 说明 这里使用的是redis的cluster集权模式&#xff0c;没有用哨兵模式&#xff08;哨兵模式依赖哨兵节点&#xff0c;哨兵节点一旦挂掉就不再高可用了&#xff0c;因此没有采用&#xff09;。 由于Redis Cluster至少需要6个节点&#xff0c;因此&#xff0c;这里咱们采用的…

【运维】Linux系统 AnolisOS [CentOs替代品]

【运维】AnolisOS 安装 CentOs替代品 下载 - OpenAnolis 龙蜥操作系统开源社区 Index of /anolis/ (aliyun.com)

(编辑器)HBuilderX怎么自动格式化代码

(编辑器)HBuilderX怎么自动格式化代码 解决参考&#xff1a;https://blog.csdn.net/G806218/article/details/127833356

CSDN 个性化推荐的数据治理

目录 1. 背景2. 数据治理2.1 从内容层面提升数据质量2.2 从用户层面提升数据质量2.3 增加特定数据的曝光2.4 保证数据的正确性与实效性 3. 总结 相关阅读 CSDN 个性化推荐系统的设计和演进如何支持研发对CSDN个性化推荐系统重构 1. 背景 CSDN 的个性化推荐流在主站中是一个很…

用UDP套接字实现客户端和服务端通信

IP地址和port端口号 IP地址 数据有IP(公网)标识一台唯一的主机。 port端口号 为了更好的标识一台主机上服务进程的唯一性&#xff0c;我们采用端口号port&#xff0c;标识服务器进程&#xff0c;客户端进程的唯一性&#xff01; ip端口号 IP地址(主机全网唯一性) 该主机上的端…

一年省七位数,得物自建HFDS在 Flink Checkpoint 场景下的应用实践

1 背景 随着Flink实例的迁移下云以及新增需求接入&#xff0c;自建Flink平台规模逐渐壮大&#xff0c;当前总计已超4万核运行在自建的K8S集群中&#xff0c;然而 Flink 任务数的增加&#xff0c;特别是大状态任务&#xff0c;每次Checkpoint 时会产生脉冲式带宽占用&#xff0…

统计项目代码行数工具cloc

Ubuntu用户 使用cloc在ubuntu内统计代码行数 安装cloc工具 sudo apt-get install cloc进入需要统计的目录内&#xff0c;然后执行 cloc .然后就会显示文件目录中的文件数(files)、空白行数(blank)、注释行数(comment)和代码行数(code)。 Windows 用户 也是使用cloc工具 …

leecode-下一排列

题目 题目 分析 妈呀&#xff0c;其实我直接调用函数&#xff0c;一行代码就通过了hhh&#xff0c;不过这种取巧的方式不可取&#xff0c;还是得老老实实的写。 首先需要明白什么叫下一排列&#xff1f; 比如输入&#xff1a; 1 5 8 4 7 6 5 3 1 答案就是&#xff1a; 1 5 …

什么是楼宇卫生间智慧厕所系统

楼宇卫生间智慧厕所系统是专为写字楼、办公楼、商场、集团大厦、工厂等应用场景所设计的解决方案。它利用全自动采集和监控智能化、无线数据传输功能&#xff0c;通过云平台管理软件和手机端应用&#xff0c;实现了公厕的智能化管理和使用者的便利。 随着城市化进程的加速&…

[Json]控制返回数据是否包含某个属性

控制返回数据是否包含某个属性 在我们返回给前端的Json格式的数据时&#xff0c;通常我们会定义一个类&#xff0c;里面定义几个成员变量用来定义返回给前端的具体内容&#xff0c;例如&#xff1a; package cn.tedu.csmall.commons.web;import io.swagger.annotations.ApiMo…

HDLbits--Exams/2013 q2bfsm

try1: module top_module (input clk,input resetn, // active-low synchronous resetinput x,input y,output f,output g ); parameter a0,b1,x12,x23,y14,y25,g16,g07;//b为resetn无效后的状态&#xff0c;在b状态使f保持一个周期 //b收到1后转移到x1&#xff0c;x1收到…

基于双机多线程的程序加速设计

摘要 不断提高程序的运行效率&#xff0c;而又不影响程序功能是程序员的不竭追求。本项目旨在利用并行技术进一步提高程序的效率。 程序设计中&#xff0c;主要实现了百万级数据的求和、求最大值以及排序功能。其中&#xff0c;排序功能使用快速排序算法和归并算法实现。共采用…

lenovo联想笔记本ThinkBook 14 Gen5+ IRH(21HW)原装Win11系统镜像原厂OEM恢复出厂状态

LENOVO联想笔记本电脑&#xff0c;ThinkBook 14 Gen5 IRH(21HW)&#xff0c;原厂Windows11原装OEM系统&#xff0c;恢复出厂时状态系统 系统自带所有驱动、出厂主题壁纸LOGO、Office办公软件、联想电脑管家等预装程序 所需要工具&#xff1a;16G或以上的U盘 文件格式&#x…

使用凌鲨查看mysql数据

MySQL是一种开源的关系型数据库管理系统&#xff0c;它被广泛应用于软件开发领域。它具有高可靠性、高性能、易于使用和可扩展性等优点&#xff0c;被许多大型企业和网站所采用。MySQL支持多种编程语言和操作系统&#xff0c;可以轻松地与其他应用程序集成。 继之前我们在凌鲨…

python如何将图片显示在网页上

from flask import Flask, render_template_string import base64 import cv2import osapp Flask(__name__)# 读取图像app.route(/)def index():# 读取图像文件并将其转换为Base64编码的字符串img_path 1.pngimg_data open(img_path, rb).read()img_base64 base64.b64encod…

vue中纯手写单选复选框样式(隐藏原生样式)

基于vue2项目&#xff0c;代码会全部在下面贴出&#xff0c;大家重点关注相关v-for循环实现及样式实现&#xff0c;先看效果&#xff1a; 先看单选 单选组件<easy-radio>&#xff1a; <template><div><div class"radio-item" v-for"(opt…