c语言实验二数据类型运算符和表达式,c语言数据类型及其运算

  c语言实验二数据类型运算符和表达式,c语言数据类型及其运算

  C语言系列:2、数据类型、运算符和表达式文章目录C语言系列:2、数据类型、运算符表达式1。前言2。变量名3。数据类型和长度3.1基本数据类型3.2短和长限定符3.3有符号和无符号限定符4。常量4.1整数常量和浮点常量4.2八进制和十六进制表示法4.3字符常量4.4转义字符4.5常量表达式4.6字符串常量4.7枚举常量5.1变量声明5.2初始化5.3常量限定符6。算术运算符7。关系运算符和逻辑运算符7.1关系运算符7.2逻辑运算符8。类型转换8.1类型转换8.2隐式类型转换8.3强制类型转换9。自增自减运算符10。按位运算符11。赋值运算符和表达式12。条件表达式和三元运算符。运算符优先级和求值顺序1前言计算机基础、数学、英语是编程的基础。这些基础越牢固越好,否则这栋楼不会建得很高。我现在就是这样的情况。因为在某大学学的是机械电子专业,计算机基础不是很好。计算机原理有些东西不太清楚,导致很多东西不知道。大学数学不够扎实,导致现在AI需要的一些数学知识,英语基础不是很好。很多英文资料只能用翻译软件管理,经常有人看,所以现在技术处于瓶颈期。不仅基础需要补充,学习新东西也很难。好在还有很多热情,所以即使前路艰难,我们也会继续前行。如果我们不放弃,就有希望,不是吗?

  变量和常量是程序处理的两个基本数据对象。该语句声明变量的名称和类型,还可以指定变量的初始值。指定操作员将做什么。该表达式将变量与常数结合起来生成新值。对象的类型决定了对象的一组可能值以及可以在对象上执行的操作。

  2.变量名变量名由字母、数字、下划线组成一般视为字母,但第一个字符必须是字母;因为一些例程的名字通常以下划线开头,所以变量名不应该以下划线开头;大写字母和小写字母是有区别的;保留字不能用于变量名;尽量了解变量名的含义,尽量对局部变量使用较短的变量名,对外部变量使用较长的名字;3.数据类型和长度3.1基本数据类型C语言只提供以下基本数据类型:

  Char类型,占用一个字节,可以在本地字符集中存储一个字符int integer,这通常反映了该整数在所用机器中最自然的长度。float单精度浮点型double双精度浮点型另外,可以在这些基本数据类型前面加上一些限定符。

  3.2短限定符和长限定符短限定符和长限定符用于限定整数类型:

  short int shlong int计数器;在上述类型的声明中,可以省略关键字int。通常很多人都习惯这样做。

  短、长两个限定词的引入,可以为我们提供不同长度的整数,以满足实际需要。

  Int通常表示特定机器中整数的自然长度。

  类型short通常是16位,类型1ong通常是32位,类型int可以是16位也可以是32位;编译器可以根据硬件特性独立选择合适的类型长度,但应遵守以下限制:short和int类型至少应为16位,而long类型至少应为32位,short类型不应长于int类型,int类型不应长于long类型。在64位的机器上,long可能占用8个字节,也就是64位,而short仍然是2个字节,int是4个字节,也满足上面的限制。long double类型表示高精度浮点数。和整数一样,浮点的长度取决于具体的实现。float、double和long double类型可以表示相同的长度或两个或三个不同的长度。

  3.3有符号和无符号限定符类型限定符有符号和无符号可用于限定char类型或任何整数类型。无符号类型

  的个数永远是正数或0,遵守算术模2 n的规律,其中n是该类型所占的位数。比如char对象占用8位,无符号char类型变量的取值范围是0 ~ 255,而有符号char类型变量的取值范围是-128 ~ 127(在有二进制补码的机器上)。没有限定符的char类型对象是否有符号取决于特定的机器,但是可打印的字符总是正数。

  在标准头文件limits.h和float.h中可以找到与这些类型的长度定义相关的符号常量以及与机器和编译器相关的其他属性。编写一个程序来确定分别由有符号和无符号定义的char、short、int和long变量的值的范围。使用标准头文件中的相应值打印:

  #包含stdio.h

  #包括限额. h

  int main() {

  printf(有符号的char max:%d,min:%d\n ,CHAR_MAX,CHAR _ MIN);

  printf(unsigned char max:%u\n ,UCHAR _ MAX);

  printf(有符号短整型最大值:%d,最小值:%d\n ,short最大值,short最小值);

  printf(unsigned short max:%u\n ,USHRT _ MAX);

  printf(signed int max:%d,min:%d\n ,INT_MAX,INT _ MIN);

  printf(unsigned int max:%u\n ,UINT _ MAX);

  printf(有符号长最大值:%d,最小值:%d\n ,LONG_MAX,LONG _ MIN);

  printf(unsigned long max:%lu ,ULONG _ MAX);

  返回0;

  }

  4.常数4.1整型常数和浮点型常数类似于1234的整型常数属于int类型。long类型的常数以字母l或l结尾,如

  123456789L .如果一个整数太大而不能用int类型来表示,它也将被视为long类型。无符号常量以字母u或u结尾。后缀UL或ul表示无符号长整型。

  浮点常数包含一个小数点(如123.4)或一个指数(如1e-2),或者两者都包含。不带后缀的浮点常量是双精度类型。后缀f或f表示浮点型,后缀l或l表示长双精度型。

  4.2八进制和十六进制是指整数除了十进制外,还可以用八进制或十六进制表示。前缀为0的整数常量表示它是八进制形式;前缀0x或0X表示它是十六进制形式。例如,十进制数31可以写成八进制形式037,也可以写成十六进制形式0x1f或0X1F。八进制和十六进制常量也可以对长类型使用后缀L,对无符号类型使用后缀U。例如,0XFUL是一个无符号长整型(无符号长整型)常数,其值等于十进制数15。

  这里不讨论System,只要你知道十进制、十六进制、八进制和二进制的转换和表示。

  4.3字符常量字符常量是一个整数,一个字符在写的时候用单引号括起来,比如 x 。机器字符集中的值是字符常量的值。例如,在ASCII字符集中,字符“0”的值是48,与值0无关。如果使用字符 0 而不是与特定字符集相关的值(如48),那么程序就不需要关心该字符对应的具体值,增加了程序的可读性。字符一般用于与其他字符进行比较,但也可以像其他整数一样参与数值运算。

  4.4转义字符ANSI C语言中的所有转义字符序列如下:

  \响铃符号

  \b回退字符

  \f分页符

  \n换行符

  \r回车

  \ t水平选项卡

  \v垂直制表符

  \ \ \反斜杠

  \?问号

  \ \ 单引号

  \ 双引号

  \ooo八进制数

  \xhh十六进制字符常量 \0 表示值为0的字符,即空字符。我们通常用 \0 的形式代替0来强调某些表达式的字符属性,但它们的数值是0。

  4.5常量表达式常量表达式是只包含常量的表达式。该表达式在编译时计算,而不是在运行时计算。

  它可以出现在常数出现的任何地方,例如:

  #定义

  char line[MAXLINE 1];或者

  #define/*闰年*/

  int days[31 28 LEAP 31 30 31 30 31 31 30 31 31 30 31 30 31 30 31];这通常用来存储一些可能经常变化的常数,以便统一变化。一般常数也是用宏的形式表示,这样可以防止出现“魔鬼数字”,也可以防止后续维护混淆这个常数的含义。

  4.6字符串常量字符串常量也称为字符串文字,是由0个或多个用双引号括起来的字符组成的字符序列。

  例如:

  我是一根绳子

  /*空字符串*/都是字符串。不是双引号字符串的一部分,它仅用于限定字符串。常量中使用的转义字符序列也可以在字符串中使用。在字符串中使用表示双引号。您可以在编译时连接多个字符串常量,例如,采用以下形式:

  你好,“世界”相当于

  “hello,world”字符串常量的连接为将长字符串分散在几个源文件行中提供了支持。

  从技术角度来看,字符串常量是字符数组。字符串的内部表示形式使用空字符 \0 作为字符串的结尾,因此。用于存储字符串的物理存储单元的数量比双引号中的字符数多一个。这个表示也说明了C语言中对字符串的长度没有限制,但是程序必须扫描整个字符串才能确定字符串的长度。标准库函数strlen(s)可以返回字符串参数s的长度,但是长度不包括结尾的 \0 。

  这是我们设计的strlen函数的一个版本:

  /* strlen:返回s */int strlen(char s[]){ int I;while (s[i]!= \ 0 )I;返回I;} strlen和其他字符串函数在标准头文件string.h中声明

  我们应该弄清楚字符常量和只包含一个字符的字符串的区别:‘x’和‘x’是不同的。前者为整数,其值为机器字符集中字母X的对应值(内部表示值);后者是一个包含一个字符(即字母X)和一个终止符 \0 的字符数组。

  4.7枚举常数枚举常数是另一种类型的常数。枚举是常量整数值的列表,例如:

  枚举布尔值{否,是};在没有明确说明的情况下,枚举类型中第一个枚举名称的值为0,第二个为1,依此类推。如果只指定了枚举名称的一部分的值,则没有指定值的枚举名称的值将根据最后指定的值向后增加。参见下面两个例子中的第二个例子:

  枚举转义{ BELL=\a ,BACKSPACE=\b ,TAB=\t ,NEWLINE=\n ,VTAB=\v ,RETURN= \ r };枚举月份{ JAN=1,2,3,4,5,6,7,8,9,10,11,12 };/* feb的值是2,MAR的值是3,以此类推*/不同枚举中的名称必须互不相同。同一枚举中的不同名称可以具有相同的值。

  枚举提供了一种方便的方法来建立常量值和名称之间的关联。与#define语句相比,它的优点是可以自动生成常量值。虽然可以声明枚举类型的变量,但编译器不会检查存储在此类型变量中的值是否是此枚举的有效值。但是,枚举变量提供了这种检查,所以枚举比#define有优势。此外,调试器可以以符号形式打印出枚举变量的值。

  5.声明5.1变量声明所有变量都必须在使用前声明,虽然有些变量可以通过上下文隐式声明。一个声明指定一个变量类型,下面的变量表可以包含一个或多个这种类型的变量。例如:

  int下,上,步骤;char c,1 line[1000];声明语句中的多个变量可以在多个声明语句中反汇编和声明。上述两个声明语句也可以等价地写成如下形式:

  int lowerint upperint步;char c;char行[1000];以这种形式编写代码会占用更多的空间,但是很容易为每个声明语句添加注释,并在以后进行修改。

  5.2初始化也可以在声明的同时初始化变量。在声明中,如果变量名后跟等号和表达式,则表达式将作为初始化表达式来初始化变量。例如:

  char esc= \ \int I=0;int limit=MAXLINE 1;float EPS=1.0e-5;如果变量不是自动变量,它只能初始化一次。从概念上讲,应该在程序开始执行之前完成,初始化表达式必须是常量表达式。每次进入一个函数或块,自动初始化的变量都会初始化一次,它的初始化表达式可以是任意表达式。默认情况下,外部变量和静态变量将被初始化为0。未显式初始化的自动变量的值是未定义的(即无效)。

  5.3 const限定符任何变量的声明都可以用const限定符来限定。此限定符指定变量的值不能修改。对于数组,const限定符指定数组的所有元素的值都不能修改:

  const double e=2.71828182845905const char msg[]=警告:“”;Const限定符也可以与数组参数一起使用,这表明该函数不能修改数组元素的值:

  int strlen(const char[]);如果试图修改const限定符的值,结果取决于具体的实现。

  6.算术运算符二进制算术运算符包括:-,/,%(模运算符)。整数除法会截断结果的小数部分。表情:

  x%的结果是x除以y的余数,当x被y整除时,其值为0。比如一年能被4整除但不能被100整除,就是闰年,能被400整除的一年也是闰年。因此,闰年可以通过下面的语句来判断:

  if ((year % 4==0 year % 100!=0) year % 400==0) printf(%d是闰年\n ,year);else printf(%d不是闰年\n ,year);模运算符%不能应用于float或double类型。在负操作数的情况下,整数除法截取的方向和模运算结果的符号取决于具体机器的实现,这与上溢或下溢的情况相同。

  二元运算符和-的优先级相同,优先级低于运算符*、/和%,而运算符*、/和%的优先级低于一元运算符和-。算术运算符采用从左到右的组合规则。

  7.关系运算符和逻辑运算符7.1关系运算符关系运算符包括以下运算符:

  ==它们具有相同的优先级。优先级紧挨着它们的是等式运算符:

  ==!=关系运算符的优先级低于算术运算符。因此,表达式i lim-1等价于i (lim-1)。

  7.2逻辑运算符逻辑运算符和有一些特殊的性质。用连接的表达式从左到右求值,知道结果值是真还是假后立即停止计算。大多数C语言程序都使用这些属性。例如:

  for(I=0;i lim-1 (c=getchar())!=\n c!=EOFI)s[I]=c;在读取一个新字符之前,必须首先检查数组S中是否有足够的空间来存储这个字符,因此必须首先测试条件i lim-1。如果这个测试失败,就没有必要继续读下一个字符。

  同样,如果在调用getchar函数之前测试C是否为EOF,结果也会不正确。因此,函数的调用和赋值必须在测试c中的字符之前完成。

  运算符的优先级高于,但这两个运算符的优先级都低于关系运算符和相等运算符。

  因此,表达式i lim-1 (c=getchar())!=\n c!=EOF不需要额外的括号。但是,由于运营商!=比赋值运算符优先级高,所以在表达式(c=getchar())中!=\n\n ,需要使用圆括号,这样才能达到预期的目的:先将函数的返回值赋给C,然后将C与 \n 进行比较。

  根据定义,在关系表达式或逻辑表达式中,如果关系为真,则表达式的结果值为数值1;如果为false,结果值为0。

  非逻辑运算符!用于将非零操作数转换为0,将操作数0转换为1。该运算符通常用于以下类似结构中:

  如果(!有效)一般不采取以下形式:

  If (valid==0)当然很难判断以上两种形式哪个更好。类似于!valid的用法读起来更直观(“如果无效”),但对于一些更复杂的结构可能就很难理解了。

  8.类型转换8.1类型转换当一个运算符的几个操作数是不同的类型时,就需要通过一些规则把它们转换成某种共同的类型。一般来说,自动转换是指在不丢失信息的情况下,将“较窄”的操作数转换为“较宽”的操作数。比如计算表达式f i时,整型变量I的值自动转换为浮点型(这里变量F是浮点型)。不允许使用无意义的表达式,例如,不允许将float类型的表达式作为下标。编译器可能会对可能导致信息丢失的表达式给出警告信息,比如将较长的整数值赋给较短的整型变量,将浮点值赋给整型变量等等,但这些表达式并不违法。

  因为char类型是一个小整数,所以可以在算术表达式中自由使用char类型变量。

  这为实现一些字符转换提供了很大的灵活性。例如,下面的函数atoi就是一个例子,它设置一个

  将数字转换为相应的数值:

  /* atoi:将s转换为integer */int atoi(char s[]){ int i,n;n=0;for(I=0;s[i]=0的[I]= 9 ;I)n=10 * n(s[I]- 0 );返回n;} s[i]-0 可以计算出s[i]中存储的字符对应的数值,因为字符集中的 0 , l 等对应的数值是一个连续递增的序列。

  lower函数是另一个将char类型转换为int类型的例子,它转换ASCII字符集中的字符

  映射到相应的小写字母。如果要转换的字符不是大写字母,lower函数将返回字符本身。

  /* lower:将c转换为小写;仅限ASCII */int lower(int c){ if(c= A c= Z )返回c A - A ;否则返回c;}以上函数是为ASCII字符集设计的。在ASCII字符集中,大写字母和对应的小写字母有一个固定的区间作为数值,每个字母表都是一个连续的3354,也就是只有A和z之间的字母,但后一点对于EBCDIC字符集来说并不成立,所以这个函数并不局限于转换EBCDIC字符集中字母的大小写。

  * *注:* *在将字符类型转换为整数时,我们需要注意一点。c没有指定char类型的变量是无符号的还是无符号的。当char类型的值转换为int类型的值时,结果有可能是负整数吗?对于不同的机器,结果是不同的,这反映了不同机器结构的差异。在某些机器中,如果char类型值最左边的位是1,它将被转换为负整数(“符号扩展”)。另一方面,在其他机器中,当将char类型值转换为int类型值时,在char类型值的左边加上0,这样转换结果值总是正的。

  C语言的定义保证了机器标准打印字符集中的字符不会是负数,所以这些字符在表达式中总是正数。然而,存储在字符变量中的位模式在一些机器中可能是负的,而在另一些机器中可能是正的。为了保证程序的可移植性,如果要在char类型的变量中存储非字符数据,最好指定有符号或者无符号的限定符。

  8.2隐式类型转换在C语言中,很多情况下都会进行隐式算术类型转换。一般来说,如果二元运算符(有两个操作数的运算符称为二元运算符,如or *)的两个操作数是不同类型的,那么在运算之前应该将“较低”类型升级为“较高”类型,运算的结果将是较高的类型。但是,如果没有无符号类型的操作数,就使用下面的代码

  这些非正式的规则可以:

  如果其中一个操作数的类型是long double,则另一个操作数转换为1 long double;如果一个操作数的类型是double,则另一个操作数转换为double;如果一个操作数的类型是float,另一个操作数就转换成float;将char和short类型的操作数转换为int类型;如果一个操作数的类型是long,另一个操作数也转换为long。注意,表达式中float类型的操作数不会自动转换为double类型,与原来的不同。

  意义不一样。一般来说,数学函数(如标准头文件math.h中定义的函数)使用双精度类型的变量。float类型主要用于使用大型数组时节省存储空间,有时也是为了节省机器执行时间(双精度算术运算特别耗时)。

  当表达式包含无符号类型的操作数时,转换规则更复杂。主要原因是有符号值和无符号值之间的比较操作是与机器相关的,因为它们取决于机器中不同整数类型的大小。举个例子,假设int类型占用16位,long类型占用32位,那么,-1L1U,因为无符号int类型的1U会提升为有符号long类型;但是-1L 1UL,这是因为1L将被提升为未签名的long类型,从而成为一个相对较大的正数。

  赋值时也需要类型转换。赋值操作符右边的值需要转换成左边变量的类型,也就是赋值表达式结果的类型。

  如前所述,无论符号扩展名如何,字符变量都将被转换为整数变量。当较长的整数被转换为较短的整数或char类型时,多余的高位将被丢弃。因此,以下各段:

  int I;char c;I=c;c=I;执行后,c的值将保持不变。无论是否进行符号扩展,这个结论都成立。但是,如果两个赋值语句的顺序颠倒了,信息可能会在执行后丢失。

  如果X是float类型,I是int类型,那么语句x=i和i=x必须在执行期间进行类型转换。当float类型转换为int类型时,小数部分会被截断;转换双精度类型时

  当它是浮点类型时,是舍入还是截断取决于具体的实现。

  因为函数调用的参数是表达式,所以在向函数传递参数时可以执行类型转换。如果没有函数原型,char和short类型都将转换为int类型,float类型将转换为double类型。因此,即使调用函数的参数是char或float类型,我们也将函数的参数声明为int或double类型。

  8.3强制类型转换最后,可以在任意表达式中使用一个称为强制类型转换的一元运算符来强制进行显式类型转换。在下面的语句中,表达式将根据上述转换规则转换为由类型名指定的类型:

  (类型名称)表达式

  我们可以这样理解强制类型转换的确切含义:在上面的语句中,表达式首先被赋给一个由类型名指定的类型的变量,然后整个语句被那个变量替换。比如库函数sqrt的参数是double类型,如果处理不当,结果可能没有意义(sqrt是在math.h中声明的)。因此,如果n是一个整数,您可以使用sqrt((double) n)将n转换为double,然后再将其传递给函数sqrt。注意,cast只生成指定类型的n的值,n的值本身没有改变。转换运算符与其他一元运算符具有相同的优先级。

  通常,参数由函数原型声明。这样,当函数被调用时,声明将自动转换参数。例如,对于sqrt的函数原型

  double sqrt(double);以下函数调用:

  root 2=sqrt(2);您可以自动将整数2转换为double类型的值2.0,而无需使用转换运算符。

  标准库包含一个可移植的函数rand来实现伪随机数生成器,以及一个函数srand来初始化种子的数量。前一个函数rand使用强制类型转换。

  无符号长整型next=1;/* rand:返回0上的伪随机整数.32767 */int rand(void){ next=next * 1103515245 12345;return(unsigned int)(next/65536)% 32768;}/* srand:为rand() */void srand设置种子(unsigned int seed){ next=seed;}为了考虑程序的可读性,一般要求强制显式类型转换,尽量避免隐式类型转换。

  9.自增运算符和自减运算符C语言为变量的递增和递减提供了两种特殊的运算符。自增运算符将其操作数递增1,自减运算符将其操作数递减1。我们经常使用运算符来增加变量的值,如下所示:

  if(c== \ n )nl;and这两个操作符很特殊,因为它们可以用作前缀操作符(用在变量前面,比如n)。也可以用作后缀运算符(用在变量之后,如n)。在这两种情况下,效果都是将变量n的值增加1。然而,它们之间有一点不同。* *表达式n先将n的值递增1,然后使用变量n的值,而表达式n先使用变量n的值,然后将n的值递增1。* *也就是说,对于使用变量n的值的上下文,n和n的作用是不同的。如果n的值是5,那么

  x=n;

  执行的结果是将x的值设置为5,并且

  x=n;

  将x的值设置为6。执行完这两条语句后,变量n的值为6。自增自减运算符只能作用于变量,像(i j)这样的表达式是非法的。

  注意上面的特色。一些奇怪的问题像这个测试,以避免检查是否清楚。在实际编码过程中,要尽量避免这种特殊用法。这不是炫耀我们的技术,而是找骂。

  10.按位运算符C语言提供了6个按位运算符。这些运算符只能处理整数操作数,即有符号或无符号的char、short、int、long类型:

  按位与(AND)

  按位“或”

  按位异或

  左移

  右移

  ~按位求反(一元运算符)

  按位AND运算符通常用于屏蔽一些二进制位,例如:

  n=n 0177此语句将n中除7个较低的二进制位之外的所有位设置为0。

  按位OR运算符通常用于将一些二进制位置设置为1,例如:

  X=x 该语句将X中与SET_ON中的1相对应的那些二进制位置设置为1。

  当两个操作数的对应位不同时,按位XOR运算符将该位设置为1,否则,将该位设置为0。

  我们必须区分位运算符和逻辑运算符,后者用于从左到右查找表达式的真值。例如,如果x的值为1,y的值为2,那么x y的结果为0,x y的值为1。

  移位运算符和用于将运算的左操作数分别向左和向右移动,移动的位数由右操作数指定(右操作数的值必须为非负)。因此,表达式x 2会将x的值左移2位,右边空出的2位会用0填充。这个表达式相当于将左操作数乘以4。无符号类型的无符号值右移时,左边空的部分会用0填充;当signed类型的有符号值向右移位时,一些机器会用符号位填充左边的空部分(即“算术移位”),而另一些机器会用0填充左边的空部分(即“逻辑移位”)。

  一元运算符~用于求整数的二进制补码,即操作数的每个二进制位上的1都变0,0变1。例如:

  X=x ~077会将x的后6位设置为0。注意,表达式x ~077与机器字长无关,它比x 0177700形式的表达式要好,x 0177700形式的表达式假设x是16位值。这种可移植的形式不会增加额外的开销,因为~077是一个常量表达式,可以在编译时计算。

  为了进一步说明一些位操作符,让我们看看函数getbits(x,p,n),它在x中从右边返回。

  一种以p位开始并向右计数n位的字段。这里假设最右边的位是第0位,n和p都是合理的正值。

  例如,getbits(x,4,3)返回x中第四、第三和第二位数的值。

  /* getbits:从位置p */unsigned getbits(unsigned x,int p,int n){ return(x(p 1-n))~(~ 0n);}其中表达式m (p 1-n)将所需字段移动到单词的右端。0的所有位都是1。这里用语句0 n将~0左移n位,最右边的n位用0填充。然后用~运算逐位反相,从而建立最右边N位全为1的掩码。

  1.赋值运算符和表达式在赋值表达式中,如果表达式左侧的变量在表达式右侧重复出现,例如:

  I=I ^ 2,您可以将此表达式缩写为以下形式:

  I=2,其中运算符=称为赋值运算符。

  大多数二元运算符(例如,带有左操作数和右操作数的运算符)都有相应的赋值运算符op=,其中op可以是下列运算符之一:

  -*/%如果expr1和expr2是表达式,则

  表达式1 op=表达式2

  相当于:

  表达式1=(表达式1) op(表达式2)

  两者的区别在于,前一种形式expr1只计算一次。注意,在第二种形式中,expr2两边的括号是必不可少的,例如,

  x *=y 1

  的含义:

  x=x *(y ^ 1)

  而不是

  x=x * y 1

  这里举个例子。下面的函数bitcount计算整数参数为1的二进制位数。

  /* bitcount:在x中计数1位*/

  int bitcount(无符号x)

  {

  int b;

  for(b=0;x!=0;x=1)

  如果(x 01)

  b;

  返回b;

  }这里将X声明为无符号类型,以保证当X右移时,无论程序运行在什么机器上,空出的位都会用0填充(而不是符号位)。

  赋值运算符除了简洁之外,还有一个优点:它的表示接近人的思维习惯。我们通常说“I加2”或者“I加2”,而不是“取I的值,加2,把结果放回I”。所以,i=2这个表达式比i=i 2更自然。此外,对于复杂表达式,如:

  Yyval[yypv[p3 p4] yypv[p1 p2]]=2赋值运算符使程序代码更容易理解。代码的读者不必煞费苦心地检查两个长表达式是否完全相同,也不必奇怪它们为什么不同。此外,赋值操作符还有助于编译器生成高效的代码。

  从上面的例子中,我们可以看到赋值语句是有值的,可以用在表达式中。下面是最常见的例子:

  while ((c=getchar())!=EOF)其他赋值运算符(如=、-=等。)也可以用在表达式中,虽然这种用法很少。

  在所有这样的表达式中,赋值表达式的类型是其左操作数的类型,其值是赋值运算完成后的值。

  12.条件表达式和三元运算符下面一组语句:

  如果(a b)

  z=a;

  其他

  z=b;用于求A和B的最大值,并将结果保存在z中.条件表达式(使用三元运算符)? ")提供了另一种方式来编写这个程序和类似的代码段,在表达式中

  expr1?在expr2:首先计算expr1。如果其值不等于0 (true),则计算expr2的值,并将其作为条件表达式的值。否则,计算expr3的值,并将其用作条件表达式的值。expr2和expr3中只能计算一个表达式。因此,上述语句可以改写为:

  z=(a b)?甲:乙;/* z=max(a,b) */需要注意的是,条件表达式其实就是一个表达式,其他表达式可以用的地方都可以用;如果expr2和expr3的类型不同,结果的类型将由本章前面讨论的转换规则决定。

  例如,如果f的类型是float,n的类型是int,那么表达式

  (n 0)?f:是一个浮点类型,不管n是否为正。

  条件表达式中第一个表达式两边的括号不是必须的,因为条件运算符?具有非常低的优先级,仅高于赋值运算符。但是我们还是建议使用括号,因为这样可以让表达式的条件部分更容易阅读。

  条件表达式可以用来编写非常简洁的代码。例如,下面的loop语句打印数组的N个元素,每行10个元素,每列之间有一个空格,每行(包括最后一行)末尾有一个换行符:

  for(I=0;I n;我)

  printf(m%c ,a[i],(i==9!i==n-1)?\ n : );在每第10个元素和第n个元素之后打印一个换行符,在所有其他元素之后打印一个空格。编写这样的代码可能需要一些技巧,但它比用等效的if-else结构编写的代码更紧凑。这是另一个很好的例子:

  printf(您有%d个项目%s,\n ,n,n==1?: s );13.运算符的优先级和求值顺序表2-1总结了所有运算符的优先级和组合,以及一些我们还没有涉及到的规则。同一行的操作员优先级相同,每行的优先级从上到下递减。比如,*、/和%的优先级相同,优先级高于二元运算符,-的优先级。运算符()表示函数调用。运算符-和。用于访问结构构件。

  表2-1运算符的优先级和组合

  运算符

  结合性

  () [] - .

  从左到右

  !~-*(type)sizeof

  从右到左

  */%

  从左到右

  -

  从左到右

  从左到右

  ==

  从左到右

  ==!=

  从左到右

  从左到右

  ^

  从左到右

  从左到右

  从左到右

  从左到右

  ?

  从左到右

  ==-=*=/=%==^====

  从右到左

  ,

  从右到左

  注意:一元运算符、和的优先级高于相应的二元运算符、和。

  注意位运算符,和优先级比运算符==和!=低。这意味着位测试表达式,如

  如果((x掩码)==0).必须用括号括起来才能得到正确的结果。

  和大多数语言一样,C语言不在同一个运算符(,,和,运算符除外)。例如,以…的形状

  x=f()g();语句,f()可以在g()之前或g()之后计算。因此,如果函数F或G改变了另一个函数使用的变量,X的结果可能取决于这两个函数的计算顺序。为了保证特定的计算顺序,中间结果可以保存在临时变量中。

  同样,C语言也没有规定函数参数的求值顺序。因此,以下声明

  printf(%d %d\n ,n,power(2,n));/*错误*/根据n的自动递增操作是在power调用之前还是之后执行,不同的编译器可能会产生不同的结果。解决方案是将语句改写为以下形式:

  n;

  printf(%d %d\n ,n,power(2,n));函数调用、嵌套赋值语句、自增自减运算符都可能有“副作用”。3354在计算表达式时,一些变量被修改。在有副作用的表达式中,执行结果和表达式中变量的修改顺序之间存在微妙的依赖关系。下面的陈述是一个典型的令人不愉快的情况:

  a[I]=I;问题是:数组下标I指的是旧值还是新值?编译器可能会对这种情况做出不同的解释,从而产生不同的结果。c语言标准故意没有说明这些问题中的大部分。表达式什么时候会有这个副作用(给变量赋值)将由编译器决定,因为最佳求值顺序与机器结构有很大关系。(ANSI C标准明确规定所有对参数的副作用必须在函数调用前生效,但这对于前面描述的printf函数调用没有帮助。)

  在任何编程语言中,如果代码执行的结果与求值顺序有关,那就是糟糕的编程风格。自然需要知道哪些问题需要避免,但是如果不知道这些问题在各种机器上是如何解决的,最好不要尝试使用特殊的实现方法。

  如果对运算符的优先级没有特殊要求,就不需要记忆。在实际编码中,需要括号来清楚地显示执行顺序。

  否则将追究法律责任。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

相关文章阅读

  • c语言调用退出函数 c语言退出整个程序怎么写
  • c语言中怎么给函数初始化 c语言的初始化语句
  • c语言编写函数计算平均值 c语言求平均函数
  • 详解c语言中的字符串数组是什么,详解c语言中的字符串数组结构,详解C语言中的字符串数组
  • 表达式求值c++实现,c语言实现表达式求值
  • 看懂c语言基本语法,C语言详解,C语言的基本语法详解
  • 用c语言实现快速排序算法,排序算法设计与实现快速排序C语言,C语言实现快速排序算法实例
  • 深入解析c语言中函数指针的定义与使用方法,深入解析c语言中函数指针的定义与使用情况,深入解析C语言中函数指针的定义与使用
  • 描述E-R图,E-R图举例,关于C语言中E-R图的详解
  • 折半查找法C语言,折半查找算法(算法设计题)
  • 折半查找法C语言,c语言折半法查找数据,C语言实现折半查找法(二分法)
  • 扫雷小游戏c++代码设计,c语言扫雷游戏源代码,C语言实现扫雷小游戏详细代码
  • 怎样统计程序代码行数,C语言统计行数,C#程序员统计自己的代码行数
  • 基于c语言的贪吃蛇游戏程序设计,用c语言编写贪吃蛇游戏程序,C语言实现简单的贪吃蛇游戏
  • 图的两种遍历算法,图的遍历算法代码c语言,Python算法之图的遍历
  • 留言与评论(共有 条评论)
       
    验证码: