C程序设计语言 第二章 第三章

第二章 类型、运算符与表达式

  变量和常量是程序处理的两种基本数据对象。声明语句说明变量的名字及类型和初值,运算符指定进行的操作。表达式把变量与常量组合起来生成新的值。对象的类型决定该对象可取值的集合以及可以对该对象执行的操作。

  整型包括signed(带符号)和unsigned(无符号) 两种形式,可以表示无符号常量与十六进制字符常量。浮点运算可以单精度进行,也可以使用更高精度的long double 类型运算。字符串常量可以编译时连接。ANSI C还支持枚举类型,对象可以声明为const(常量)类型,表明其值不能修改.该标准还对算术类型之间的自动强制转换规则进行了扩充,以适合于更多的数据类型。

 

2.1 变量名

  变量名的命名与符号常量的命名存在一些限制条件,名字必须有字母和数字组成的序列,第一个字符必须是字母。下划线“_”被看作是字母,通常用于命名较长的的变量名,以提高其可读性。由于库函数通常以下划线开头,因此变量名不要以下划线开头。大写小写作字母是有区别的,在传统C语言用法中,变量名使用小写字母,符号和常量名全部使用大写字母。

  对于内部名至少前31个字符是有效的。函数名与外部变量名包含的字符数目可能小于31,这是因为汇编程序和加载程序可能会使用在这些外部名,语言本省是无法控制加载和汇编程序的。对于外部名,ANSI标准仅保证6个字符的唯一性,并且不区分大小写。类似于if、else、int、float等关键字保留给语言本身使用的,不能用作变量名,所以关键字中的字符都必须是小写。

  选择变量名要能够尽量从字面上表达变量的用途,这样不容易引起混淆,局部变量一般使用较短的变量名(尤其是循环控制变量),外部变量使用较长名字。

 

2.2 数据类型及长度

  C语言提供下列几种基本数据类型:

  char             字符型,占用一个字节,可以存放本地字符集中的一个字符

  int                 整型,通常反应宿主机上整数的自然大小。

  float         单精度浮点数。

  double     双精度浮点数。

  此外,还有一些可用限定这些基本类型的限定符。其中short与long这两个限定符用于限定整数类型

  short int  sh;

  long int  counter;

  在上述类型的声明中,关键字int可以省略。通常很多人习惯怎么做。

  short与long两个限定符的引入可以为我们提供满足实际需要的不同长度的整型数。int通常代表机器中整数的自然长度。short 类型通常为16位,long 类型通常为32位,int类型可以为16或者32位。各编译器可以根据硬件特性自主选择合适的类型长度,但要遵循下列限制:short与int类型至少为16位,而long类型至少为32位,并且short类型不得长于int类型,而int类型不得长于long类型。

  类型限定符signed与unsigned可用于限定char类型或任何整型。unsigned类型的只有大于0的数或0,并遵守算术模2的n次方定律,其中n是该类型占用的位数。例如,如果char对象占用8位,那么unsigned char 类型变量的取值范围为0-255,而signed char 类型变量的取值范围则为-128~127(在采用对二的补码的机器上)。不带限定符的char类型对象是否带符号取决于具体机器,可打印的字符总是正值。

  long double类型表示高精度的浮点数。同整型一样,浮点型的长度也取决于具体实现。float 、double与long double类型可以表示相同的长度,也可以表示两种或三种不同的长度。

  

 练习2-1 打印各种类型的取值范围。%u是无符号(正数),%l是长整型。
1
void print_char_short_int() 2 { 3 printf("signed char min = %d\n",SCHAR_MIN); 4 printf("signed char max = %d\n",SCHAR_MAX); 5 printf("signed short min = %d\n",SHRT_MIN); 6 printf("signed short max = %d\n",SHRT_MAX); 7 printf("signed int min = %d\n",INT_MIN); 8 printf("signed int max = %d\n",INT_MAX); 9 printf("signed long min = %ld\n",LONG_MIN); 10 printf("signed long max = %ld\n",LONG_MAX); 11 12 printf("unsigned char max = %u\n",UCHAR_MAX); 13 printf("unsigned short max = %u\n",USHRT_MAX); 14 printf("unsigned int max = %u\n",UINT_MAX); 15 printf("unsigned long max = %lu\n",ULONG_MAX); 16 }

 

 

2.3  常量

  1234的整数常量属于int类型。long类型的常量以字母l或L结尾,如果一个整数太大不能用int类型表示时,也将被当作long类型处理。无符号常以字母u或者U结尾。后缀ul或UL表明是unsigend long 类型。

  浮点数常量中包含一个小数点(如123.4)或一个指数(如le-2),也可以两者都有。没有后缀的浮点数常量为double类型。后缀f或者F表示float类型,后缀l或L则表示long doubble类型。

  整型数除了用十进制表示外,还可以用八进制或十六进制表示。带前缀0的整型常量表示为八进制形式;前缀为0x或0X,则表示为十六进制形式。八进制和十六进制的常量也可以使用后缀L表示long类型,使用后缀U表示unsigned类型。例如,0XFUL是一个unsigned long类型(无符号长整型)的常量,其值等于十进制数15.

  一个字符常量是一个整数,书写时将一个字符包括在单引号中,如‘x'。字符在机器字符集中的数值就是字符常量的值。例如,在ASCII字符集中,字符’0‘的值为48,他与数值0没有关系。如果用字符’0‘代替这个与具体字符集有关的值(比如48),那么,程序就无需关心该字符对应的具体值,增加了程序的易读性。字符常量一般用来与其他字符进行比较,也可以像其他整数一样参与数值运算。

  某些字符可以通过转义字符序列(例如,换行符\n)表示字符和字符串常量。转移字符序列看起来像两个字符,但只是表示一个字符。另外可以用'\ooo'表示仍以字节大小的位模式。其中ooo表示1~3个八进制数字(0...7)。这种模式还可以用'\xhh'表示,其中,hh是一个或多个十六进制数字(0-9,a-f,A-F)。因此,可以这样写:

  #define VTAB '\013'      //垂直制表符

  #define BELL '\007'       //报警符号

  上述语句用十六进制写为:

  #define VTAB  '\xb'     

  #define BELL   '\X7'

  ANSI C语言中的全部转义字符序列如下

  

\a     响铃符             \\        反斜杠
\b     回退符             \?        问号
\f     换页符             \'        单引号
\n     换行符             \"        双引号
\r     回车符             \ooo      八进制
\t     横向制表符          \xhh      十六进制数
\v     纵向制表符

 

  字符常量'\0'表示值为0,也就是字符(null). 我们通常用'\0'的形式代替0,以强调默写表达式的字符属性,但其数字值为0.

  常量表达式仅仅只包含常量的表达式。这种表达式在编译时求值,而不再运行时求值.而不再运行时求值,它可以出现在常量可以出现的仍和位置.

  例如:     

  #define MAXLINE 1000

  char line[MAXLINE+1];

  #define LEAP 1

  int days[31+28+LEAP+31];

  字符串常量也叫字符串字面值,时用双引号括起来的0个或多个字符组成的字符序列.

  例如:

  "I am a string"

  ""

  都是字符串.双引号不是字符串的一部分,只用于限定字符串.字符常量中使用的转移字符序列同样也可以用在字符串。字符常量中使用的转义字符序列同样也可以在字符串中。在字符中使用\"表示双引号字符.编译时可以将多个字符串常量连接起来.

  例如:

  "hello, " "world" 等价于  "hello, world"

  字符串常量的连接为将较长字符产分散在若干个源文件行中提供了支持.从计数角度看,字符串常量就是字符数组.字符串内部表示使用一个空字符'\0'作为串的结尾,存储字符串的物流存储单元比双引号中的字符数多一个.C语言对字符串的长度没有限制,但程序必须扫描整个字符串后才能确定字符串长度.标准库函数strlen()返回字符串长度,不包括末尾'\0'.

  

1 int strlen(char s[])
2 {
3     int i;
4     while (s[i] != '\0')
5         ++i;
6     return i;
7 }

 

  

 

 

  标准头文件<string.h>中声明了strlen个其他字符串函数.

     字符常量和字符串之间的区别:'x'与"x"时不同的,前者是一个整数,是字母x在机器字符集中对应的数值;后者是一个包含字符(字母x)以及一个结束符'\0'的字符数组.

  枚举常量是另一种类型的常量.是一个常量整型值的列表.例如  enum boolean { NO,  YES };

  没有显式说明的情况下,enum类型中第一个枚举名的值为0,第二个为1,依次类推.如果指定部分枚举名的值,那么未指定值的枚举名将依着最后一个指定值向后递增,

  例如:  

  enum escapes { BELL = '\a', BACKSPACE = '\b', TAB = '\t', NEWLINE = '\N', VTAB = '\v', RETURN = '\r'};

  enum months { JAN = 1, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC };

  不同枚举中的名字必须互补相同.同一枚举中不同的名字可以具有相同的值.枚举建立常量值与名字之间的关联提供一种便利方式.相对于#define语句来说,常量值可以自动生成.尽管可以声明enum类型的变量,但是编译器不检查这种类型的变量中存储的值是否为该枚举的有效值.枚举变量提供这种检查,因此枚举比#define更有优势.调试程序可以以符号形式打印出枚举变量的值.

 

2.4    声明

    所有变量都必须先声明后使用,尽管某些变量可以通过上下文隐式声明.一个声明指定一种变量类型,后面所带的变量表可以包含一个或多个该类型的变量.

  例如: int lower, upper, step;

      char c, line[1000];

  也可以声明的同时对变量进行初始化.

  例如: char esc = '\\';

         int i = 0;

      int limit = MAXLINE + 1;

      float eps = 1.0e-5;

  如果变量不是自动变量,只能进行一次初始化,概念上讲,是程序开始执行之前进行,并且初始化表达式必须为常量表达式.每次进入函数或程序块时,显式初始化的自动变量都将被初始化一次,其初始化表示可以是仍和表达式.默认外部变量与静态变量将被初始化为0.未经显式初始化的自动变量值为未定义(既无效值)

  任何变量的声明都可以使用const限定符号限定.该限定符指定变量的值不能被修改.对数组而言,const限定符的数组所有元素值都不能修改.

  

2.5  算数运算符

  判断闰年代码

  

 

1 void leap_year()
2 {
3     int year;
4     year = 2019;
5     if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
6         printf("%d is a leap year\n",year);
7     else
8         printf("%d is not a leap year\n",year);
9 }

 

  取模运算符不能用于float或double类型.有负操作的情况下,整数除法截取的方向以及取模运算结果的符号取决与具体机器的实现.和处理上溢出或下溢出时一样的.

  二元运算符+和-比运算符*,/,%低,他们又比一元运算符+和-低

  一元就是只需要一个操作数,如a--、a++、 !a、 ~a等
  二元就是需要两个操作数才能完成运算 如典型的a+b、 a-b、 a*b、 a/b等

  

2.6  关系运算符与逻辑运算符

   关系运算符:     >    >=   <    <=   它们的优先级次于 ==   !=   

     关系运算符的优先级比算数运算符低.表达式 i < lim - 1 等价于  i  <  (lim - 1)

     逻辑运算符&&与||连接的表达式按从左到右的顺序进行求值,并且在知道结果为真或假立即停止计算.运算符&&比||优先级高,单两者都比关系运算符和相等运算符低.

     由于运算符 != 的优先级高于复制运算符的优先级,因此 例: (c = getchar()) != '\n'

     在关系表达式或逻辑表达式章,如果关系为真,结果1,假则0.

     逻辑非运算符!的作用时将非0操作做转换为0,将操作数0转为1.   例如:   if (!valid)

 

 练习2-2 
1
void nonuse_() 2 { 3 enum loop {NO, YES}; 4 enum loop okloop = YES; 5 int i = 0,lim = 1000; 6 char c,s[lim]; 7 while(okloop == YES) 8 if (i >= lim - 1) 9 okloop = NO; 10 else if ((c = getchar()) == '\n') 11 okloop = NO; 12 else if (c == EOF) 13 okloop = NO; 14 else 15 { 16 s[i] = c; 17 ++i; 18 } 19 }

 

 

 

 2.7   类型转换

    自动转换是把比较窄的操作数转换为比较宽的操作数,不对是信息的转换.例如: f+i,当f为浮点数i自动转浮点数.不允许使用无意义的表达式,例如把浮点型作为下标.针对可能导致信息丢失的表达式,编译器可能会给出警告比如把长整型赋值个短整型变量,把浮点型值赋给整形变量.

  char类型是小整型,算数表达式中可以自由使用char类型的变量.

  将字符类型转换为整型时,C语言没有指定char类型的变量时无符号变量(signed)还是带符号变量(unsigned).当把一个char类型转换为int类型的值时,对不同机器,其结果也不同,这反应了不同机器结构之间的区别.在某些机器中,如果char类型值的最左一位为1,则转换为负整数(进行"符号扩展").另一种机器转换时,在char类型值左边添加0,转换结果总是正值.为了保证程序的可移植性,如果在char类型中存储非字符数据,最好指定signed和unsigned限定符.

  d = c >= '0' && c <= '9'   当c为数字时,d的值为1,否则d值为0.

  类型转换不同的时将char和short类型操作数转换为int类型,其他都时同类转换.float类型操作数不会自动转为都变了类型.

  表达式中包含unsigned类型的操作数时,带符号和无符号之间比较与机器相关,取决于机器中不同整数类型的大小.

  赋值时也要进行类型转换.左边变量的类型是赋值表达式的类型.

  无论是否进行符号扩展,字符型变量都将转为整型变量.当把较长整数转换为较短整数或char类型时,超出的高位部分将被丢弃.

  给函数传递参数也可能进行类型转换,没有函数原型的情况下,char与short类型都将被在转换为int类型.float会被转换为都变了类型.

  在任何表达式中都可以使用一个称为强制类型转换的的一元运算符强制进行显式类型转换.

  

练习2-3 编写函数htoi(s),把十六进制数字转换成等价整型值.包括0-9,a-f,A-F.
比如要转换16进制的0x123那公式是 1*16的2次方 + 2*16的一次方 + 3*16的0次方 等价于 1*16*16 + 2*16 + 3 等价于 (1*16+2)*16+3 下面公式是这样的
{n = 16 * n + hexdigit;} 通过循环之后达到上面的效果.

  
1
int htoi() 2 { 3 int hexdigit,i,inhex,n; 4 i = 0; 5 char s[500]; 6 while ((s[i] =getchar()) != EOF) 7 { 8 ++i; 9 } 10 i = 0; 11 if (s[i] == '0') 12 { 13 ++i; 14 if (s[i] == 'x' || s[i] == 'X') 15 ++i; 16 } 17 n = 0; 18 inhex =1; 19 for (;inhex == 1; ++i) 20 { 21 if (s[i] >= '0' && s[i] <= '9') 22 {hexdigit = s[i] - '0';} 23 else if (s[i] >= 'a' && s[i] <= 'f') 24 {hexdigit = s[i] - 'a' + 10;} 25 else if (s[i] >= 'A' && s[i] <= 'F') 26 {hexdigit = s[i] - 'A' + 10;} 27 else 28 {inhex = 0;} 29 if (inhex == 1) 30 {n = 16 * n + hexdigit;} 31 } 32 printf("%d",n); 33 }

 

 2.8     自增运算符与自减运算符

    自增运算符++使其操作数递增1,自减运算符减1. 他们的不同之处在于++或--可以在变量前表示先将变量的值+1在使用变量的值,在变量后面则表示先使用变量的值,然后变量的值在增1.

 

练习2-4 编写程序将字符串s1和s2中重复的字符去掉.
1
void squeeze() 2 { 3 char s1[6]={'h','e','l','l','o','\0'},s2[6]={'r','l','l','e','o','\0'}; //定义两个试验用的数组 4 int i,j,k; 5 for (i = k =0; s1[i] != '\0';i++) 6 { 7 for (j = 0;s2[j] != '\0';j++) 8 { 9 if (s1[i] != s2[j] && s2[j+1] == '\0') //如果字符集s1的某一个字符不等于s2的字符集的所有字符 10 { //并且已经循环到s2的最后 11 s1[k++] = s1[i]; //给s1重新赋值 12 } 13 } 14 s1[k] = '\0'; 15 } 16 printf("%s",s1); 17 }

 

 

 练习2-5 编写函数any,将字符串s2的任一字符在字符串s1中的第一次出现的位置作为返回结果,如果不存在就返回-1
1
void any() 2 { 3 char s1[6]={'h','e','l','l','o','\0'},s2[6]={'r','l','l','e','o','\0'}; //定义两个试验用的数组 4 int i,j,k; 5 for (i=0;s2[i] != '\0';i++) 6 { 7 for (j=0;s1[j] != '\0';j++) 8 { 9 if (s2[i] == s1[j]) 10 { 11 printf("%c %d\n",s2[i],j); 12 break; //出现了就停止循环 13 } 14 if (s2[i] != s1[j] && s1[j+1] == '\0') //这里必须是if 不能是 else if 或者 else 15 {printf("%c %d\n",s2[i],-1);} //如果没出现就打-1 16 } 17 } 18 }

 

 2.9   按位运算符

    C语言提供了6个位操作运算符,只能用于整型.char、short、int、long

    &            按位与(AND) 有一个0的0,两个1得1.

       |        按位或(OR)   有一个1的1,两个1得1.

       ^             按位异或(XOR)两个数不同为1,相同为0.

       <<     左移

       >>     右移

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

 

   关于 书上例子 unsigned getbits(unsigned x, int p, int n)的解答,首先说题目的重点,返回X中从右边数第P位开始向右数n位的字段。

 

 //练习2-6,不是很清楚原理,通过分解,每一步求的值.这个里面有个重点,就是需要用程序员计算器来查看每个步骤,特别是取反,通过手算容易出错.
1
int main() 2 { 3 unsigned x,y; 4 x = 255; 5 y = 124; 6 int p=4,n=2,s; 7 8 //s = setbits(x,p,n,y); 9 s = ~(~0 << n); 10 s = ~(~0 << n) << (p+1-n); 11 s = ~(~(~0 << n)); 12 s = x & ~(~(~0 << n) << (p+1-n)); //这个公式是让x的P位开始到N的位置设置为0,方法是通过x同一个p到n的为0,其他全部为1的数相与,把x的n到p的位置变为0. 13 printf("%d",s); 14 } 15 unsigned setbits(unsigned x,int p,int n, unsigned y) 16 { 17 return x & ~(~(~0 << n) << (p+1-n)) | (y & ~(~0 << n)) << (p+1-n); 18 }

 

 

练习2-7,函数invert,将x中p位开始的n个位求反,其他不变.
1
unsigned invert(unsigned x,int p, int n) 2 { 3 return x ^ (~(~0 << n) << (p+1-n)); //通过异域的方式把x的p到n的值做出改变 4 }

 

 

练习2-8,函数rightrot。思路:获得x的后n位,然后左移,移动到只剩下n位,然后 |(或) x  右移n位。
1
unsigned rightrot(unsigned x,int n) 2 { 3 (x >> n) | ((x | (~0 << n)) << (32 - n)); 4 }
 练习2-8 这个是标准答案,循环移动
1
int main() 2 { 3 int wordlength(void); 4 int rbit,n; 5 unsigned x; 6 x = 198; 7 n = 3; 8 while (n-- > 0) //循环三次 9 { 10 rbit = (x & 1) << (wordlength() - 1); //让x与1得到的是x最右边二进制的那个数 然后左移31位,因为int在计算机里面是4个字节,4*8=32位。 11 x = x >> 1; // x改变x的值 12 x = x | rbit; //然后x与上面的值或操作得到新值 13 } 14 printf("%u",x); //%u可以控制输出为无符号,如果是%d 有可能会输出负数,原因是printf函数默认%d是输出带符号的数。 15 16 } 17 int wordlength(void) 18 { 19 int i; 20 unsigned v = ~0; //这里定义无符号 ~0,也就int类型的最大数。 21 for (i = 1; (v = v >> 1) > 0; i++); //循环得到最大数的的个数,其实就是32,int类型就是32位。 22 return i; //返回32 23 }
2-8的另一种,和我自己写的差不多。
1
unsigned rbits; 2 if ((n = n % wordlength()) > 0) //如果n小于32,那就执行 3 { 4 rbits = ~(~0 << n) & x; //获取x上最右边的n位数 5 rbits = rbits << (wordlength() - n); //然后左移32-n位 6 x = x >> n; // x的值右移n位 7 x = x | rbits; //然后或操作 8 }

 

 

2.10   赋值运算符与表达式

 

    https://blog.csdn.net/yanyong_/article/details/79287352

    网站是关于2的补码问题。

 

练习2-9.
1
int bitcount(unsigned x) 2 { 3 int b; 4 for (b = 0; x != 0; x &= x - 1) //例子 x的二进制 = 1010, x-1的二进制 = 1001,两个数and操作,x最右边为1的会被抹掉。 5 {++b;} //原因是两个数相差1,在二进制上的体现就是在数最右边0和1的区别. 6 return b; 7 }

2.11   条件表达式

    

1 z = (a > b) ? a : b;   //如果a>b,z=a,否则z=b.

 

     采用条件表达式可以编写出很简洁的代码。

练习2-10 。
void
lower(char s) {printf("%c",(s >= 'A' || s <= 'Z') ? s + 32 : s);}

 

 2.12  运算符优先级与求值次序

    同一行中的各运算符具有相同的优先级,各行间从上往下优先级逐行降低。

 

 

   位运算符&、^、| 的优先级比运算符 == 和 != 低。如 if ((x & mask) == 0) 必须用圆括号括起来才能得到正确的结果。

  printf("%d %d\n", ++n, power(2, n));  是错误语句,在不同编译器中会产生不同结果,取决于n的自增运算在power调用之前还是之后执行。

  ++n;

  printf("%d %d\n", n, pwoer(2,n));

  ansi c 标准明确规定了搜有对参数的副作用都必须在函数调用之前生效。

  在任何一种编程语言中,如果代码的执行结果与求值顺序相关,则都是不好的程序设计风格。

 

第三章     控制流 

    程序语言中控制流语句用于控制各计算机操作的执行顺序。

3.1  语句与程序块 

    C语言使用分号语句结束符,Pascal语言分号是分隔符。

    用一对花括号 { } 把一组声明和语句包括在一起就构成了一个符合语句(程序块),等价于单条语句。

3.2      if-else 语句

    if {表达式}

        语句1

    else

        语句2

    

3.3  else-if 语句

 

 1 int binserch(int x,int v[], int n)     //需要一个数x,一个数组v(升序),数组的长度,或者指定范围n
 2 {
 3     int low, high, mid;           //最低位的长度,最高位长度,平均数
 4     low = 0;
 5     high = n - 1;                 
 6     while (low <= high)           // 如果数组还有空间
 7     {
 8         mid = (low+high) / 2;     //大小相加除以2;
 9         if (x < v[mid])           //如果x小于v[mid]
10             high = mid - 1;       //让最高数-1
11         else if (x > v[mid])      //如果x大于v[mid]
12             low = mid + 1;        //让low+1
13         else
14             return mid;           //否则返回mid
15     }
16     return -1;
17 }

 

 

 

 练习3-1,标准答案
1
int test_3_1_binsearch(int x, int v[], int n) 2 { 3 int low,high, mid; 4 low = 0; 5 high = n - 1; 6 mid = (low+high) / 2; 7 while (low <= high && x != v[mid]) 8 { 9 if (x < v[mid]) 10 high = mid - 1; 11 else 12 low = mid + 1; 13 mid = (low+high) / 2; 14 } 15 if (x == v[mid]) 16 return mid; 17 else 18 return -1; 19 }

 

 

 3.4   switch 语句

  switch语句是一种多路判定语句,它测试表达式是否与一些常量整数值中的某一个值匹配,并执行相关应的分支动作。

    switch (表达式){

    case 常量表达式:语句序列

    case 常量表达式:语句序列

    default:语句序列

  

 练习3-2 函数escape(s,t)
1
int main() 2 { 3 void escape(char s[200],char t[200]); 4 char t[200] = "jshfjksdhfk\njdkhfjhdj\tkjsdjkas\n"; 5 char s[200]; 6 escape(s,t); 7 printf("%s",s); 8 } 9 void escape(char t[200],char s[200]) 10 { 11 int i=0,n=0; 12 for (i=0;t[i] !='\0';i++) 13 switch (t[i]){ 14 case '\n': 15 s[n++] = '\\'; 16 s[n++] = 'n'; 17 break; 18 case '\t': 19 s[n++] = '\\'; 20 s[n++] = 't'; 21 break; 22 default: 23 s[n++] = t[i]; 24 break; 25 } 26 s[n] = '\0'; 27 }

 

 函数3-2 翻版
1
int main() 2 { 3 int x; 4 void escape(char s[200],char t[200]); 5 char t[200] = "j\\nntttt\\n"; 6 char s[200]; 7 escape(t,s); 8 printf("%s",s); 9 } 10 void escape(char t[200],char s[200]) 11 { 12 int i=0,n=0; 13 for (i=0;t[i] !='\0';i++) 14 if (t[i] != '\\') 15 s[n++] = t[i]; 16 else 17 switch (t[++i]){ //t[++i] 等于 t[i+1] 18 case 'n': 19 s[n++] = '\n'; 20 break; 21 case 't': 22 s[n++] = '\t'; 23 break; 24 } 25 s[n++] = '\0'; 26 }

 

 

 3.5     while循环与for循环

    for 循环语句;

      for (表达式1;表达式2;表达式3)

      语句

      等价于下列while语句

      表达式1;

      while (表达式2){

      语句

      表达式3;

      }

    当语句中存在continue语句时,上面不等价。

    没有初始化或重新初始化操作,使用while循环语句更自然。如果语句中需要执行简单的初始化和变量递增,使用for语句更合适一些。在C语言中,for循环语句的循环变量和上限在循环体可以修改,并且当循环因某种原因终止后循环变量i的值仍然保留。

练习3-3
1
int main() 2 { 3 char s1[20] = "-a-x\nkd\nf-m"; 4 char s2[20]; 5 void expand(char s1[],char s2[]); 6 expand(s1,s2); 7 printf("%s",s2); 8 } 9 void expand(char s1[], char s2[]) 10 { 11 char c; 12 int i,j; 13 i = j = 0; 14 while ((c = s1[i++]) != '\0') //c等于自增的s1字符串不等于0 15 { 16 if (s1[i] == '-' && s1[i+1] >= c) //如果等于‘-’和s1[i+1] >= c变量所代表的字母,注意一个问题这里c的值是‘-’上一个的值。 17 { 18 i++; 19 while (c < s1[i]) //如果c小于那个字母 20 s2[j++] = c++; //s2自增等于当前字母+1一直到等于C等于那个字母 21 } 22 else 23 s2[j++] = c; //else正常等于。 24 } 25 s2[j] = '\0'; 26 }

 

  3.6    do-while 循环   

     do-while循环在执行后测试终止条件,这样循环至少被执行一次。

     do

      语句

        while  (表达式)

      

 

 

 

 

 1 int main()
 2 {
 3     int n=-15;
 4     char s[10];
 5     void itoa1(int n,char s[]);
 6     itoa1(n,s);
 7 
 8 }
 9 void itoa1(int n,char s[])
10 {
11     int i,sign;
12     if ((sign = n) < 0)      //如果是负数,那做个记号
13         n = -n;              //让n变成正数,后面操作需要正数
14     i = 0;   
15     do {
16         s[i++] = n % 10 + '0';     //(n%10 + 字符串的‘0’)得到的是 那个数的字符串的asicc码
17     } while ((n /= 10) > 0);       //如果n是二位数或者更大,继续上一步
18     if (sign < 0)                 //记号如果是负数
19         s[i++] = '-';             //添加负数
20     s[i] = '\0';                 //加上结束符
21     printf("%s",s);
22 }

 

 

 

 

 练习3-4.
1
void itao(int n,char s[]) 2 { //-(2的 字长-1 次幂) = -(2的31次幂),这个是int类型。=-2,147,483,648 3 int i, sign; 4 sign = n; 5 i = 0; 6 do{ 7 s[i++] = abs(n % 10) + '0'; //同样得到最右边的数 8 }while ((n /= 10) != 0); //因为n是负数,所以要求为不是0 9 if (sign < 0) 10 s[i++] = '-'; 11 s[i] = '\0'; 12 }

 

 

 

 

练习3-5,函数itob(n,s,b)标准答案
1
void itob(int n,char s[],int b) 2 { 3 int i,sign,j; 4 if ((sign = n) < 0) 5 n = -n; 6 i = 0; 7 do{ 8 j = n % b; //查看这个数是否小于要转换的底数 9 s[i++] = (j <= 9) ? j + '0' : j + 'a' - 10; //转换 10 } while ((n /= b) > 0); //如果不等于0 11 if (sign < 0) 12 s[i++] = '-'; 13 s[i] = '\0'; 14 }
 1 void itao(int n,char s[],int w)
 2 {                             //-(2的 字长-1 次幂) = -(2的31次幂),这个是int类型。=-2,147,483,648
 3     int i, sign;
 4     sign = n;
 5     i = 0;
 6     do{
 7         s[i++] = abs(n % 10) + '0';   //同样得到最右边的数
 8     }while ((n /= 10) != 0);              //因为n是负数,所以要求为不是0
 9     if (sign < 0)
10         s[i++] = '-';
11     while (i < w)
12         s[i++] = ' ';           //如果输入的数不够就用空格补齐
13     s[i] = '\0';
14 }

 

3.7    break 语句与 continue 语句

  continue语句只用于循环语句,如果用于switch语句将导致进入下一次循环。

 

3.8    goto 语句与标号

  C语言提供了可随意滥用的goto语句以及标记跳转位置的标号。最常见的用法是终止程序在某些深度嵌套的结构中的处理过程,例如一次跳出两层或多层循环。

  for (......)

   for (......)   {

    ......

    if (disaster)

     goto error;

    }

   .....

error:

  标号的命名同变量命名的形式相同,标号的后面要紧跟一个冒号。标号可以位于对应的goto语句所在函数的任何语句的前面。标号的作用域是整个函数。

  

 

 

 

 

  

 

posted @ 2019-11-16 19:04  C,python,linux,java  阅读(377)  评论(0)    收藏  举报