C语言学习笔记

      之  数据类型转换与数据运算

一:数据类型转换

1自动转换(5+5.000000=?结果是10还是10.000000):发生在不同类型的数据混合运算时,由编译系统自动完成。

不同的数据类型,要转换成精度较高的。

A转换按数据长度增加的方向进行,确保精度不降低,比如:int型和long型运算时,先把int量转成long型后再进行运算

  BCharshort类型要转换成int ,然后再参加运算。

 C在赋值运算中,赋值号两边的数据类型不同时,赋值号右边的类型将转换为左边的类型,如果右边的数据类型长度比左边长,将丢失一部分,丢失的部分按四舍五入向前舍入。

比如:计算10+a+5*5.000000 105为整型,5.000000 为双精度实型)

    先计算‘a’的整型为97+10=107//char转换为int

      计算5*5.000000=25.000000//将整型5转换为double型实型

      计算107+25.000000=132.000000//将整型107转换为double型;

所以它的最终结果为精度最高的double型。

比如我们来看两个程序实例


//#include 
#include 
using namespace std;
void main()
{
   unsigned int a=6; //定义无符号整型
   int b=-20; //定义有符号整型
   cout<


为什么是一串很大的整数呢?而不是-14呢?问题就在自动转换上,我们观察上述讲过的转换规则,unsignedint同时出现运算时,int需要转换成unsigned,即:有符号需要转换成无符号类型。程序中的-20需要转换成无符号整型。


//#include 
#include 
using namespace std;
void main()
{
   unsigned char a=6; //定义无符号整型
   char b=-20; //定义有符号整型
   cout<


int型修改为char类型之后,结果竟然是-14,这又是为什么呢?还是自动转换规则。看规则,int以下类型(short,char不管有无unsigned)计算会转为int,也就是说不管有没有符号,char类型都要转换成int,所以a+b遵循了有符号整型的运算。

2)强制类型转换

区别与自动转换,强制转换很明显是强制的。格式为:(类型说明符)表达式

      比如:int a ; (float) a 的意思是将整型a 强制转换为了实型。(int)(x+y)的意思是将x+y的值转换为整型。

3)需要注意的是:无论是自动转换或者是强制转换,都只是为本次运算的需要而对变量的数据长度进行的临时性转换,而不改变数据说明时对该变量定义的类型

    如下程序:


#include 
main()
{
   float f=5.75;
   printf("(int)f=%d\nf=%f\n",(int)f,f);
}


           二:数据运算

1.运算符的优先级与结合性

优先级

结合性

运算符

备注

1

左结合

()
[]
->
.

圆括号
下标运算符
指向结构体成员运算符
结构体成员运算符

2

右结合

!
~
++
--
+
-
(类型)
*
&
sizeof

逻辑非运算符
按位取反运算符
前缀增量运算符
前缀减量运算符
正号运算符
负号运算符
类型转换运算符
指针运算符
地址运算符
长度运算符

3

左结合

*
/
%

乘法运算符
除法运算符
取余运算符

4

左结合

+
-

加法运算符
减法运算符

5

左结合

<<
>>

左移运算符
右移运算符

6

左结合

<
<=
>
>=

关系运算符

7

左结合

==
!=

等于运算符
不等于运算符

8

左结合

&

按位与运算符

9

左结合

^

按位异或运算符

10

结合性

|

按位或运算符

11

左结合

&&

逻辑与运算符

12

左结合

||

逻辑或运算符

13

右结合

? :

条件运算符

14

右结合

=
+=
-=
*=
/=
%=
&=
^=
|=
<<=
>>=

赋值运算符

15

左结合

,

逗号运算符

2.算术运算(+-*/%

1乘除取余的优先级要高于加减;

2/”除运算,参加除运算的变量均为整数,结果也为整数(舍去小数),多数机器上采取“向零取整”的原则。比如:7/4=1(而不是1.75)-7/4=-1

3%,参与模运算的变量必须都为整型,其结果为两数相除的余数,并且余数与被除数的符号相同。比如:7%4=3,  -8%5=-3,   8%-5=3  

3.赋值运算

1变量名=表达式,运算顺序是从右向左。比如:x=y=z=0, x=(y=(z=0))

(2)当赋值运算符两边的数据类型不同时,系统将自动进行类型转换,赋值运算符右边的数据类型转换成左边的变量类型,在上一篇中已经说过了。

3复合赋值运算:比如:n+=1等价于n=n+1; x*=y+1等价于x=x*(y+1)

4.自增自减运算

如果n=3 ,n的值和m的值如下表所示


n的值

m的值

运算分解

m=n++

4

3

m=n; n=n+1

m=++n

4

4

n=n+1; m=n

m=-n++

4

-3

m=-n; n=n+1

m=- ++n

4

-4

n=n+1 ;m=-n;


关于自增自减是一个重要的概念,在之后的指针学习中还会重点学习。

5.逗号运算

1表达式1,表达式2....表达式n。自左向右结合。

2表达式n的值为整个逗号表达式的值。比如:a=(1,2,3,4,5,6),a的值等于6。也就是最后一个的值。

3逗号运算符在所有运算符中的优先级别最低,它往往起到了把若干个表达式串联起来的作用。比如:a=3*4,a*5,a+10。 从左向右 先去3*4,然后将12的值赋给a,然后计算a*5。将60的值赋给a,然后计算a+10的值。

6.关系运算与逻辑运算

关系运算无非就是大于(>)小于(<),逻辑运算有非(!)与(&&)或(||

逻辑表达式的值只有真(1)和假(0)两个值

A的取值

B的取值

A(求反)

A&&B

A||B

0

0

0

1

1

0

0

0

0

1

0

1

0

1

0

0

1

0

0

对于关系运算来说,a>b>c并不代表着a的值比b大,b的值比a大。关系运算与逻辑运算需要密切合作。我们来举一个例子:看两个程序。


#include 
main()
{
   int a=6,b=4,c=1;
   if(a>b>c)
   {
       printf("OK\n");
   }
   else{
       printf("ERROR\n");
   }
}


我们看到的结果竟然是ERROR,而不是我们预想的OK,这是为什么呢?原因就在判断上。在数学上,a>b>c一点都没有错,但是在我们的C程序中,计算机判断条件的依据只有两种结果,那就是1(真)或者是0(假)。比如:a>b是真,所以a>b的值为1,然后1>c吗?很显然1=c,所以if()条件中的条件并不成立,所以结果为ERROR那这样怎么改呢?很简单,用逻辑运算符


#include 
main()
{
   int a=6,b=4,c=1;
   //if(a>b>c)
   if(a>b && b>c)
   {
       printf("OK\n");
   }
   else{
       printf("ERROR\n");
   }
}


7.1:位运算之取反(~)

1取反能对一个二进制的每一位都取反。

 看一个程序实例:


#include 
main()
{
    unsigned char a,b;//定义无符号
//char a,b;
a=26;
b=~a;//对a取反
   printf("b=%u\n",b);//以无符号输出
}


分析一下char类型默认分配一个字节,即8位。26的二进制为:00011010

  对26的二进制取反(~a)得:11100101,我们在深入剖析类型修饰符unsigned中讲解过,无符号的二进制最高位为数据位,所以11100101的十进制为229

2为了便于区分有符号和无符号的区别,我们再来做一个程序实例:


#include 
main()
{
    //unsigned char a,b;//定义无符号
char a,b;//定义有符号
a=26;
b=~a;//对a取反
    //printf("b=%u\n",b);//以无符号输出
    printf("b=%d\n",b);//以有符号输出
}


26的二进制:00011010,取反:11100101char类型默认有符号(我的是有符号,有些课本中说无符号),所以最高位为符号位,所以是负数,对11100101减一取反是:10011011,转换成二进制为-27

  对于这一块不理解的同学可以参考:C语言进阶[暑期特别篇]深入剖析类型修饰符unsigned

7.2:位运算之左移(<<

左移是将一个数的各个二进制位全部向左平移若干位,左边移出的部分忽略,右边空出的位置补0,比如:

      A = 0 0 0 1 1 0 1 0

A<<2=0 1 1 0 1 0 0 0

 一个数据,每左移一位相当于乘以2,左移2位相当于乘以4。比如:4左移2=4*4=16

7.3 位运算之右移(>>

右移是将一个数的各个二进制位全部向右平移若干位,右边移出的部分忽略,左边空出的位置对于无符号数补0,对于有符号数,若原符号位为0,则全补0,若原符号位为1,则全补1比如:

   A 被定义为unsigned(无符号) char

            A= 1 0 0 1 1 0 1 0

        A>>2 = 0 0 1 0 0 1 1 0

A被定义为char (默认有符号)

           A= 1 0 0 1 1 0 1 0

       A>>2 = 1 1 1 0 0 1 1 0

7.4 位运算之与或(&&|)

比如: a= 1 0 1 1 1 0 1 0

         b= 0 1 1 0 1 1 1 0

     a&&b= 0 0 1 0 1 0 1 0  只有111,其它的全是0

       a|b= 1 1 1 1 1 1 1 0  只要有一个1,就是1

7.5 位运算之异或(^

异或运算的作用是判断两个相应位的值是否相异。相异为1,反之则为0

         a= 1 0 1 1 1 0 1 0

         b= 0 1 1 0 1 1 1 0

       a^b= 1 1 0 1 0 1 0 0