一道c语言运算符优先级问题

时间:2021-09-30 01:08:22

一道c语言运算符优先级问题

#include <iostream>

using namespace std;

int main()

{

char test[] = {“This is testing.”}, *p = test;

int i,j;

i = 2,j=5;

//print

cout<<*p<<*p++<<endl; // 输出为 : h T

cout<<i<<j<<endl; //输出为: 2,5

cout<<i<<i++<<endl; //输出为:3,2

p = test;

cout<<*p<<*++p<<endl; //输出为:h h

i = 2;

cout<<i<< --i<<endl; //输出为:1 1

i = 2;

printf(“%d,%d”,i,i++); //输出为:3,2

getchar();

return (0);

}

解析


面对:cout<<*p<<*p++<<endl;这样一个语句,初一看输出结果应该是:T h  但是实测结果是 h  T ,刚好相反! 为什么呢? 其实这是个运算符优先级问题。

1.要知道不论是 cout<<….<<endl; 还是 printf(); 其参数入栈顺序都是自右至左!,输入时从左至右输出。例如:

cout<<i<<j<<endl; 是先入栈 endl , 紧接着入栈 j值,然后是i值入栈,最后是 cout入栈,然后输出时,是先出i值,然后再出j值,这里还要明白出栈时并不是简单的先出栈cout,然后出栈i,…..  最后出栈endl的, 出栈时就涉及cout库函数怎么操作内存地址的事情,这里完全不用理会,只要知道入栈的顺序是自右至左先入栈j然后入栈i, 出栈时自左至右先出i,再出j值。

2.上面说到入栈是自右至左进行的,其实计算也是自右至左进行的,但是并不是计算一个就入栈一个,而是先自右至左计算全部表达式完毕,然后再自右至左依次入栈。比如:

cout<<*p<<*p++<<endl;

面对这个语句, 计算机是先来计算*p++,发现*p++带有后置运算符,所以第一步就是申请一个临时寄存器Reg1 把当前*p的值暂存到Reg1中,然后执行 后置运算,这里要注意了,这里的指针运算符*和自增运算符优先级是相同的, 现在指针运算符已经使用完了,就是说刚运用指针运算符取出了*p地址下的数据内容,即*p,然后碰到后置运算符++,但是这里就要特别注意了,后置运算符++是对变量进行操作,不会其其它操作符进行操作,所以这里的后置运算符++是应用到了变量p上,而不是*p上,所以 *p++的运算结果是p指向了其下一个地址,注意这里的*p++中的++是对P进行操作的,即操作的是p的地址增加了一个单位,而不是(*p)++,這样表示 ++对(*p)这个数据进行了加1操作,当前的*p数据内容显然是执行第一个字符,这里是指向’t’,那么’t’加1之后,从ascii码表上可知’t’的下一个字符是’u’,而当前环境下,(*p)++实际输出正是’u’。

那么现在可以知道,因为*p++含有后置运算符++,所以计算*p++的结果是将当前p地址下的内容保存到一个临时寄存器Reg1中,然后执行p++,即p地址自增一个单元。

上面计算完*p++之后,接着自右向左走,此时则要来计算*p了,通过前面*p++的计算,此时*p中的p是指向了test数组的第一个值,即指向了’h’字符,即将’h’字符赋值给p地址下的数据存储单位中,然后自右至左走,走到了cout,这里不需要计算,至此全部表达式计算完毕,然后入栈操作, 入栈也是自右至左入栈,所以先入栈*p++那里的值,因为这里有后置运算符,后置运算符就是要先用当前变量的值,然后再进行计算,所以计算之前的值就是代表当前变量在计算这个表达式的值,当然这里只有*p++,所以这个表达式*p++的值就是其进行后置运算之前的保存在临时寄存器Reg1中的值,所以这里入栈*p++表达式式的值其实就是入栈临时寄存器Reg1的值,这里显然是入栈’T’这个字符,即数组的第一个字符。接着自右至左走,入栈*p的值,此时*p的其实就是数组的第二个字符的值,这里显然是’h’。然后入栈cout。 好了现在所有入栈操作已完成, 其入栈顺序是 先入栈endl ,然后是入栈’T’,然后是入栈’h’,最后入栈cout。先入栈的在栈底,后入栈的在栈顶,也就是说endl在栈底,然后是’T’ , ‘T’上面是’h’,然后是’cout’在最上面, 入栈完了之后就调用 cout函数来出栈, 要出栈就是从栈顶走到栈底咯, 现在是cout在栈顶吧,所以调用 cout函数,然后按格式输出,然后cout弹出来了之后, 接下来是遇到’h’字符了, 那么弹出’h’字符, 注意这里就是输出来的第一个字符了,然后接着弹出’T’字符,最后遇到endl,然后再去弹出,发现栈顶指针已经走到栈底指针家了,所以就不弹出了。

现在知道cout<<*p<<*p++<<endl;为什么输出来是 h T 而不是期待的 T h 了吧。

之所以会出现這中情况是是因为cout<<…..<<endl; 是自右向左进行计算和入栈的。 如果先把*p 和*p++的值单独赋值给两个变量,那么输出来的就可以是 T h 了。 如

cout<<i<<j<<endl;

其实也就是说你在计算*p时一定要知道当前这个P执行了谁,它指到哪个地址去了,之所以会出现输出 h T  是因为这个p 在你来计算*p时, 它已经偷偷的指向了其它地方去了。

接着看:cout<<i<<i++<<endl;  这里和上面就是一样了, 知道i初始化为2,那输出则为3,2.

这里要明白:

自增运算符在前面就要运算再使用

自增运算符在后面就是要先使用再运算,因为是先使用再运算,所以在运算之前要用一个临时寄存器或申请一块临时地址把当前值保存起来。

接着看下面 cout<<*p<<*++p<<endl;,应该立刻就知道答案了。

因为++在前所以要先运算再使用,而cout<<….<<endl; 是自右至左运算的,所以会先碰到*++p,然后碰到*p。 先碰到*++p ,因为是前置运算,所以先运算再使用,所以++p 使得p指向了test[]数组的下一个地址值,然后进行指针运算,即取出当前地址下的数据内容。由p = test知,p是指向test[]数组的首地址,++p之后,p执行了test[]数组中的第二个值,即test[1],此时取出这个值,即*p , 此时即完成*++p,接着自右至左走,来到了*p,这个也是应指针运算符取出当前p地址中的数据内容,而p还是指向test[1],所以*p还是取出test[1]的值。所以最终输出的的结果就是 test[1], test[1],即 h h.

p = test;

cout<<*p<<*++p<<endl; //输出为:h h

下面的这两个也就可以同理分析了。

i = 2;

cout<<i<< --i<<endl; //输出为:1 1

i = 2;

printf(“%d,%d”,i,i++); //输出为:3,2

总结


1.碰到指针时,要知道当前操作的指针到底指向内存中的哪个地址,指向哪个变量!

2.声明指针时,要立即赋值为NULL,如 char *ptr = NULL;  如果是 char *ptr; 则会造成ptr指向不明,变成野指针。

3.要知道函数参数的计算方向,一般都是自右向左进行的。如cout<<endl; 因为只有这样才能保证出栈时的顺序和书写时的顺序一致! 比如你现在入栈是自左向右入栈,那现在第一个值被入栈到栈底了, 然后接着入栈其它的内容,最后要出栈的时候,你是要先取出第一个值吧,但是这个值被按自左向右入栈已经入栈到栈底了,這样你要取出来不是多麻烦的,自右向左入栈就要简单多了,直接出栈就可以了,因为最上面的就是第一个,然后这里的自右向左入栈的和计算的方向,不仅仅是满足这个方便,在c/c++语言中這样做还可以满足其确定动态参数的个数等功能。

一道c语言运算符优先级问题的更多相关文章

  1. C语言运算符优先级总结

    一 写在开头1.1 本文内容本文内容为C语言中运算符优先级的总结.转载于:https://blog.csdn.net/huangblog/article/details/8271791,感谢原作者的付 ...

  2. C语言运算符优先级和ASCII表

    1. C语言运算符优先级及结合性 优先级 运算符 名称或含义 使用形式 结合方向 说明 1 [] 数组下标 数组名[常量表达式] 左到右 -- () 圆括号 (表达式)/函数名(形参表) -- . 成 ...

  3. C语言运算符优先级及结合性

    今天去翻了下C语言运算符的优先级和结合性,发现当初学习的时候就没认真记住,惭愧.发现一篇讲得不错的文章,编辑了下转来供以后翻阅. C语言运算符优先级表(由上至下,优先级依次递减) 运算符 结合性 () ...

  4. &lpar;转&rpar;C语言运算符优先级 详细列表

    C语言运算符优先级 详细列表 文章转自:Slyar Home 优先级 运算符 名称或含义 使用形式 结合方向 说明 1 [] 数组下标 数组名[常量表达式] 左到右   () 圆括号 (表达式)/函数 ...

  5. C语言 运算符优先级和结合方向

    运算符优先级和结合方向 初级运算符( ).[ ].->..  高于  单目运算符  高于  算数运算符(先乘除后加减)  高于  关系运算符  高于  逻辑运算符(不包括!)  高于  条件运算 ...

  6. C语言运算符优先级和结合性一览表

    所谓优先级就是当一个表达式中有多个运算符时,先计算谁,后计算谁.这个其实我们在小学学算术的时候就学过,如1+4÷2. 但是C语言中的运算符已经远不止四则运算中的加减乘除了,还有其他很多运算符.当它们出 ...

  7. C语言运算符优先级和口诀(转)

    一共有十五个优先级: 1   ()  []  .  -> 2   !  ~   -(负号) ++  --   &(取变量地址)*   (type)(强制类型)    sizeof 3   ...

  8. C语言运算符优先级和口诀 (转)

    一共有十五个优先级: 1   ()  []  .  -> 2   !  ~   -(负号) ++  --   &(取变量地址)*   (type)(强制类型)    sizeof 3   ...

  9. 转载--C语言运算符优先级和口诀

    转载:http://www.cnblogs.com/zhanglong0426/archive/2010/10/06/1844700.html 一共有十五个优先级: 1   ()  []  .  -& ...

随机推荐

  1. 【开源】OSharp框架解说系列(5&period;2):EntityFramework数据层实现

    OSharp是什么? OSharp是个快速开发框架,但不是一个大而全的包罗万象的框架,严格的说,OSharp中什么都没有实现.与其他大而全的框架最大的不同点,就是OSharp只做抽象封装,不做实现.依 ...

  2. 从库查看状态的时候显示&OpenCurlyDoubleQuote; Last&lowbar;Error”

    mysql> show slave status\G;*************************** 1. row ***************************         ...

  3. 使用ueditor中的setContent&lpar;&rpar; 时经常报innerHtml错误(笔记)

    1)今天遇到个问题,使用ueditor中的setContent() 时经常报innerHtml错误:网上找了下解决方案:发现这个可以用: 不能创建editor之后马上使用ueditor.setCont ...

  4. HTML5离线缓存Manifest

    web app不比PC,有性能和流量方面的考虑,离线应用越来越重要,虽然浏览器有缓存机制,但是时常不靠谱,更何况普通情况下html文件是没法缓存的,断网之后一切over. 什么是manifest? 简 ...

  5. Gengxin讲STL系列——Set

    本系列第二篇blog 第一篇写的心潮澎湃,结果写完一看,这都是些什么玩意= =| Set的中文名称是“集合”.集合,高一数学必修一课本给出的定义已经很明确了,简单来讲就是一个不含重复元素的空间(个人定 ...

  6. Laravel的console使用方法

    适用场景:分析数据(日志) php artisan make:console 你的命令类名 示例: php artisan make:console Check 在\app\Console\Comma ...

  7. Spring事务管理的实现方式:编程式事务与声明式事务

    1.上篇文章讲解了Spring事务的传播级别与隔离级别,以及分布式事务的简单配置,点击回看上篇文章 2.编程式事务:编码方式实现事务管理(代码演示为JDBC事务管理) Spring实现编程式事务,依赖 ...

  8. Linux 教程 技巧集

    Linux 终端操作技巧 CTRL + U - 剪切光标前的内容 CTRL + K - 剪切光标至行末的内容 CTRL + Y - 粘贴 CTRL + E - 移动光标到行末 CTRL + A - 移 ...

  9. ionic3中NavController类push setRoot相关问题解决

    今天在测试app的时候发现,登录页跳转到首页后,会加载两次数据.百思不得其解,查看了所有代码也没能发现问题.最终抱着尝试的态度,动了如下代码: if (suc) { //this.navCtrl.pu ...

  10. how tomcat works 总结

    希望各位网友在看完<<how tomcat works>>一书或者鄙人的tomcat专栏文章后再看这篇博客 这里主要是梳理各个章节的核心概念 第一章 一个简单的Web服务器 第 ...