C语言学习杂记(4)—运算符、表达式及语句

C语言专注于数据,数据的处理多种多样,比如:比较大小、更改值、逻辑判断、四则运算等。如何更好地理解数据的处理原则?如何趋利避坏?这是我们这篇文章所要披露的。我始终坚信,只有好的理解,才有好的运用。

示例程序

#include <stdio.h>

int main(void)
{
    int age;
    int days;
    const int daysOfOneYear = 365;

    printf("If you input your age, and I can calculate your total days.\n");
    printf("And while your input is not a number, program will stop.\n");
    while(scanf("%d", &age))
    {
        days = daysOfOneYear*age;
        printf("%d year is %d day\n", age, days);
    }
    printf("program is stoped!\n");

    return 0;
}

程序简单输出如下:

If you input your age, and I can calculate your total days.
And while your input is not a number, program will stop.
10
10 year is 3650 day
5
5 year is 1825 day
29
29 year is 10585 day
stop
program is stoped!

这个程序是简单的循环计算,它带来了基本的数据输入输出交互,同时使用了运算符对数据进行乘法操作。

运算符

C使用运算符来表达算数运算,最最基本的有=、+、-、×、/、%,但是没有较为复杂的运算,比如:乘方、立方、三角函数等。我们会一个一个说明他们的用途。

1、算数运算符=

在C语言中,=代表的是赋值,不是数学上的等于。数学上的等于使用“==”两个等号来表示。其基本定义如下:

// 变量名 = 表达式
// 至于什么是表达式,我们后面会提到
param = 234;
f = 23.44;

【注】:赋值运算符属于“左值”运算符,在C语言中,左值指的是标识一个特定的数据对象的名字或表达式。比如:变量名是左值。右值指的是能赋给可修改的左值的值,比如:bmw=232, bmw是一个左值,232是一个右值。

2、算数运算符+和-

“+”表示把两个数加在一起,“-”表示把两个数相减。

c = a + b; // c为a和b的和
d = a - b; // d为a和b的差
3、算数运算符*

乘法比加法更加复杂一些,同时乘法可以组合出更多的数学概念。乘法表、立方、平方这些概念我们都可以使用乘法来表示。在做乘法运算的时候,我们需要考虑上溢的问题,比如最大的整数乘以2,得到的结果可能不是实际想要的结果。

4、算数运算符/

规则如下:

c = a / b; // a除以b,然后将结果赋值给c。b被a除。b去除a,将结果赋值给c。
运算符优先级

为什么需要优先级?我们先看一个例子。

int result = 3 + 4 * 10 / 2

如果没有优先级,我们可能从左往右计算,3+4 = 7,7*10=70,70/2=35。但实际的计算结果却不是这样的。我们曾经学习过的数学,里面也提到,乘除法会比加减法先计算。这样得到的结果就是:4*10=40,40/2=20,3+20=23。这就是需要优先级的原因。优先级表如下:

运算符 结合性
() 从左往右
+-,一元运算符 从右往左
*/ 从左往右
+-,二元运算符 从左往右
= 从右往左
sizeof

sizeof是一种运算符,用于求取具体值或类型的长度,它的类型是size_t,是一个无符号整数类型,打印的时候可以使用%zd进行打印。

取模运算符%

%是用于求取除法后的余数。经过这么多年的软件开发,我逐渐发现这个运算符带来的好处。第一个好处是它带来的间歇性,比如每隔多久执行任务;第二个好处是拆分,比如有5台机器,我们想做集群,如何控制请求访问到哪台机子,可以用到取模,对5取模得1的,请求到1号机器,对5取模得2的,请求到2号机器。

自增++和自减--

自增运算符完成的任务是对自身加1,其对外暴露的方式有两种,++在变量之前和++在变量之后。自增带来的好处最明显的莫过于循环,比如循环50次,循环到满足条件。自增和自减的优先级非常高,仅次于圆括号运算符,比如:x*y++等同于x*(y++)。

【警告】对于初学者,在使用这两个运算符的时候可能会带来一些困扰。
如果我们的代码写成下面的方式:

int num = 3;
printf("%d, %d\n", num, num*num++);

初看起来,它一点问题都没有,但是我们++作用的范围是什么?因为printf是一个参数可变的函数,计算机有可能是先计算最后的表达式(num*num++),再计算num,这时得到的结果就和我们的预期不一致了。

再比如说:

int ret = num / 2 + 5*(1+num++);

其造成的困扰原因和上面一样,我们不知道是+号前面的先计算,还是+后面的先计算。
C语言对此没有做出保证。但是我们有一些约定的规则,只要我们遵循他们,就可以避免这些问题。

1、当一个变量出现在同一个函数的多个参数中时,不要使用自增和自减在它上面
2、当一个变量多次出现在一个表达式里时,不要使用自增和自减在它上门

不过,C也并不是一点保证也没有,我们后面会看到它的保证(基于顺序点的讨论)。

表达式和语句

语句组成了C的步骤,而大多数的语句由表达式组成。

1、表达式

表达式由运算符和操作数(操作数是运算符操作的对象)组成。一些最基本的四则运算,比较操作、赋值等,都可算是表达式。而每一个表达式都有一个值。=的值是什么?它的值就是变量的值。

2、语句

一条语句是一条完整的计算机指令,在C语言中,语句是由英文分号结束的。

c = 4  // 这只是一个表达式
c = 4; // 因为有分号,所以它算是一个语句

C把任何后面带分号的表达式看成一个语句,但是有些语句是没有意义的。因为它实际上并没有做什么事情。语句更典型的用处是改变值和函数调用。

4;    // 没有意义
4+3;  // 没有意义

一些常用的语句示例。

#include <stdio.h>
int main(void)
{
    int count, num;       // 声明语句
    
    count = 0;           // 赋值语句
    sum = 0;
    while(count++<20)    // while语句块
    {
        sum = sum + count;     //计算语句
    }
    printf("sum = %d\n", sum); // 函数语句
    return 0;
}

【注】
a、一个声明语句并不是一个表达式语句,因为我们一旦去掉分号,它并不是一个表达式,也没有一个值。
b、赋值语句用途很广,它是表达式语句的特例
c、函数语句用于函数调用
d、while称为语句块,是因为它包含的语句不止一个

3、副作用和顺序点

在C语言中,对表达式求值是语句的主要作用,顺带来的其他用途我们叫做副作用。比如,赋值语句num = 50;它的副作用就是将变量num设置为50,之所以叫副作用,就是因为求值50是主要作用了。
顺序点,是程序执行的顺序中的一点,在该点处,所有副作用都在进入下一个语句之前计算。理解顺序点至关重要。也就是说赋值、自增、自减,在进行下一语句之前,全部完成。在初学C的时候,对于i++,我们常常理解为先使用i,再增加它的值。这样的理解倒是简单,但是带来的理解不当也是显而易见。如果我们使用顺序点来理解就更明晰了。例如:

y = (4 + x++) + (6 + x++);

因为4+x++并不是一个完整的表达式,所以并不能保证先计算4+x++。

4、语句块

语句块,又叫复合语句,是使用大括号括起来的一些列语句。常用的语句块有if、while、for等控制语句块。还有就是为了在显示上区分逻辑部分而加的大括号。

cast,类型转换

一般进行语句和表达式计算的时候,使用的是同一种类型。但是如果出现类型不一致,也不会出现很明显的错误,C本身自带类型转换。类型转换涉及到一些规则,通常我们只需记住就行了。
1、在表达式中,short和char会自动转换为int,在特定场景下,会转换为uint(unsigned int,无符号整数)。这个特定场景指的是short和int有相同大小,这时unsigned short比int大,这时的转换就转换为unsigned int。
2、float自动转换为double。
3、在包含两种数据类型的任何运算里,两个值都被转换成两种类型中较高的级别。
4、级别由高到低分别是:long double、double、float、unsigned long long、long long、unsigned long、long、unsigned int、int。类似1中的特定场景,当long和int具有相同大小的时候,此时unsigned int比long级别更高。这儿没涉及倒short和char,是因为他们已经被提升到int或unsigned int了。
5、当做函数参数传递时,int和short会自动转换为int,float会转换为double。
提升通常是一个平滑的过程,但是降级会带来风险。降级意味着截取。

除了自动转换外,我们也可以进行强制转换,C语言使用(type)避免自动转换。

mouse = 1.6+1.7; // 情况1
mouse = (int)1.6 + (int)1.7; // 情况2

假设mouse是int类型,情况1会得到结果3,情况2会得到结果2。具体这两种哪种更精确,取决于实际的场景。我们这儿只是说明可以自动转换,也可以进行强制转换。

函数参数的简单说明

#include <stdio.h>

int add(int first, int second);

int main(void)
{
    int a = 3, b = 9;
    int result;

    result = add(a, b);
    printf("%d add %d is %d\n", a, b, result);

    return 0;
}

int add(int first, int second)
{
    int c = first + second;
    return c;
}

在这个例子中,我们用到了函数add,这个函数的主要用途在于计算两个值的和。这里,函数add出现在了3处地方,第一处为main方法前面,用于函数的声明;第二处为main方法里面,用于函数的调用;第三出为main方法的后面,用于函数的定义。在函数定义的时候,我们可以使用first和second作为函数的“形式参数”,而真实调用的时候使用a和b作为“实际参数”。
更专业地说,实际参数,也叫参数,英文为parameter;实际参数,也叫参量,英文名为argument。

总结

对于数据的处理,C语言带来了很多简易、人性和合理的处理方式。一个操作符作用于一个或多个操作数,然后产生一个值。带一个操作数的操作符叫一元运算符,而带两个操作数的操作符叫二元运算符。
表达式是运算符和操作数的组合。在C中每一个表达式都有一个值。语句是对计算机的指令的完整表示,一个语句使用分号来分割。语句包含表达式语句、函数语句、赋值语句等等。
cast类型转换分为自动和手动,自动有一定的规则,而手动需要编码之人来指定,指定的方式为使用(type)。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345

推荐阅读更多精彩内容

  • 谨记 当你还在原地停留不动时,你的敌人已经前进一大步了;当你还沉浸在成功的喜悦中,你的对手又更上一层楼了;当你还在...
    长风留言阅读 1,744评论 2 5
  • •1 C语言程序的结构认识 用一个简单的c程序例子,介绍c语言的基本构成、格式、以及良好的书写风格,使读者对c语...
    CONLYOUC阅读 8,696评论 9 66
  • 前言 把《C++ Primer》[https://book.douban.com/subject/25708312...
    尤汐Yogy阅读 9,506评论 1 51
  • 头昏脑涨睡意朦, 辗转反侧思想滞, 谁言未来坎坷路, 现与此刻全赴会。
    A把时间当做朋友阅读 40评论 0 3
  • 110篇,13万多字,1年5个月。在这个写作平台上,这些数字码字成绩。坚持每周一至二篇。当然,没有大红花奖励。 每...
    走在雨的缝中阅读 406评论 14 25