文章目录[隐藏]
- 7.1 if语句
- 7.2 if else 语句
- 7.2.1 getchar()和putchar()
- 7.2.2 ctype.h系列的字符函数
- 7.2.3 多重选择 else if
- 7.2.4 else与if配对
- 7.2.5 多层嵌套的if语句
- 7.3 逻辑运算符
- 7.3.1 备选拼写:iso646.h
- 7.3.2 优先级
- 7.3.3 求值顺序
- 7.3.4 范围
- 7.4 一个统计单词的程序
- 7.5 条件运算符:?:
- 7.6 循环辅助:continue和break
- 7.6.1 continue语句
- 7.6.2 break语句
- 7.7 多重选择:switch和break
- 7.7.1 switch语句
- 7.7.2 只读每行的首字符
- 7.7.3 多重标签
- 7.7.4 switch和if else
- 7.8 goto语句
- 7.8.1 避免使用goto
- 7.9 关键概念
7.1 if语句
问题:读取一列数据,每个数据都表示每日的最低温度(℃),然后打印统计的总天数和最低温度在0℃以下的天数占总天数的百分比。程序中的需要你换通过scanf()读入温度值。while循环每迭代一次,就增加天数,其中if语句负责判断0℃以下的温度并单独统计相应的天数。
//colddays.c --找出0℃以下的天数占总天数的百分比
#include<stdio.h>
int main(void)
{
const int FREEZING = 0;
float temperature;
int cold_days = 0;
int all_days = 0;
printf("Enter the list of daily low temperatures.\n");
printf("Use Celsius,and enter q to quit.\n");
while(scanf("%f",&temperature) == 1)
{
all_days++;
if(temperature < FREEZING)
{
cold_days++;
}
}
if(all_days!=0)
printf("%d days total:%.lf%%were below freezing.\n",all_days,100.0*(float)cold_days/all_days);
if(all_days==0)
printf("No data entered!\n");
return 0;
}
if语句被称为分支语句(branching statement)或者选择语句(select statement).
7.2 if else 语句
7.2.1 getchar()和putchar()
输入字符,scanf()和printf()根据%c读写字符。
getchar()函数不带任何参数,他从输入队列中返回下一个字符。例如:
下面语句读取下一个字符输入,并把该字符的值赋给变量ch;
ch = getchar();
//与之等价
scanf("$c",&ch);
putchar()函数打印它的参数。例如:
下面语句把之前赋给ch的值作为字符打印出来:
putchar(ch);
//与之等价
scanf("%c",ch);
由于这两个函数只处理字符,因此它比scanf和printf更快、更简洁。因为只处理字符,因此不需要转换说明。其定义在stdio.h头文件中(它们通常是预处理宏,而不是真正的函数)
编程问题:该程序把一行输入重新打印出来,但是每个非空格都被替代成原字符在ASCII序列中的下一个字符,空格不变。“如果字符是空白,原样打印;否则,打印原字符在ASCII序列中的下一个字符”。
// cypherl.c --更改输入,空格不变
#include<stdio.h>
#define SPACE ' '
int main(void)
{
char ch;
ch = getchar();
while(ch !='\n') //如果未换行
{
if(ch == SPACE)
putchar(ch);
else
{
putchar(ch+1);
}
ch=getchar();
}
putchar(ch);
return 0;
}
// 加密通话,另外一种写法~
#include<stdio.h>
#define SPACE ' '
int main(void)
{
char ch;
while((ch=getchar())!='\n')
{
if(ch == SPACE)
{
putchar(ch);
}
else
{
putchar(ch+5);
}
}
return 0;
}
//加密解密代码
#include<stdio.h>
#define SPACE ' '
char jiami(char a);
char jiemi(char a);
int main(void)
{
int a,i;
char ch;
printf("输入要处理的字符:");
ch = getchar();
printf("请选择你的要干什么。\n");
printf("按1编码,按2译码:");
scanf("%d",&a);
if(a==1)
{
putchar(jiami(ch));
}
else if(a==2)
{
putchar(jiemi(ch));
}
printf("\n结束!\n");
return 0;
}
char jiami(char a)
{
return (a+5);
}
char jiemi(char a)
{
return (a-5);
}
//改进
#include<stdio.h>
#define SPACE ' '
char jiami(char a);
char jiemi(char a);
int main(void)
{
int a,i;
char ch;
scanf("%d",&a);
if(a==1)
{
while((ch = getchar())!='\n')
{
if(ch==SPACE)
{
putchar(ch);
}
else
{
putchar(ch+5);
}
}
}
else if(a==2)
{
while((ch=getchar())!='\n')
{
if(ch==SPACE)
{
putchar(ch);
}
else
{
putchar(ch-5);
}
}
}
else
{
printf("这样子我很难哎~");
}
return 0;
}
7.2.2 ctype.h系列的字符函数
只转换字母,其余符号不变。isalpha()是字母,返回非零值。
// cypher2.c --替换输入的字母,非字母字符保持不变
#include<stdio.h>
#include<ctype.h>
int main(void)
{
char ch;
while((ch=getchar())!='\n')
{
if(isalpha(ch))
putchar(ch+1);
else
putchar(ch);
}
putchar(ch);
return 0;
}
tolower(ch); //不影响ch的值
ch=tolower(ch); //影响ch的值,把ch转换为小写字母
ctype.h头文件中的字符测试函数。
7.2.3 多重选择 else if
问题:多重选择的电费
略。
对于编译器的限制范围,C99标准要求编译器最少支持127层嵌套。
else if原理:
if..
{
}
else
if..
{
}
else
if...
{
}
...
// 等价于
if ()
{
...
}
else if()
{
...
}
else if()
{
...
}
else
{
}
7.2.4 else与if配对
规则:
如果没有花括号,else与离他最近的if匹配,除非最近的if被花括号括起来。
7.2.5 多层嵌套的if语句
给定一个整数,显示所有能整除它的约数。如果没有约数,则报告该数为一个素数。
提示用户输入数字
当scanf ()返回值为1
分析该数并报告结果
提示用户继续输入
for(div = 2;div < num;div++)
if(num % div == 0 )
{
printf("%d is divisible by %d\n",num,div);
}
该方法有点浪费时间~。如果144%2=0,说明2是144的约数;144除2=72,那么72也是144的一个约数。所以num%div成功,则获得两个约数。
分析后发现,必须测试到的数字到num的平方根就可以了,不用到num。
for(div=2;(div*div)<=num;div++)
if(num%div == 0)
{
printf("%d is divisible by %d and %d.\n",num,div,num/div);
}
不使用平方根而用这种办法是因为:1.整数乘法比求平方根快。其二,我们还没有正式介绍平方根函数。
如果其为完全平方数
for (div=2;(div*div)<=num;div++)
{
if(num%div==0)
{
if(div*div!=num)
printf("%d is divisible by %d and %d.\n",num,div,num/div);
else
printf("%d is divisible by %d.\n",num,div);
}
}
// divisors.c --使用嵌套if语句显示一个数的约数
#include<stdio.h>
#include<stdbool.h>
int main(void)
{
unsigned long num; //待测的数字
unsigned long div; //可能的约数
bool isPrime; //素数标记
printf("Please enter an integer for analysis:");
printf("Enter q to quit.\n");
while(scanf("%lu",&num)==1)
{
for (div=2,isPrime=true;(div*div)<=num;div++)
{
if(num%div==0)
{
if((div*div)!=num)
printf("%lu is divisible by %lu and %lu.\n",num,div,num/div);
else
printf("%lu is divisible by %lu.\n",num,div);
isPrime = false; //该数不是素数
}
}
if(isPrime)
printf("%lu is Prime.\n",num);
printf("Please enter an integer for analysis:");
printf("Enter q to quit.\n");
}
printf("Bye.\n");
return 0;
}
该程序会把1认为是素数,其实它不是。
7.3 逻辑运算符
问题描述:编写一个程序,计算输入的一行句子中除单引号和双引号以外的其他字符的数量。这种情况下可以使用逻辑运算符,并使用句点(.)标识句子的末尾。
// chcount.c --使用逻辑与运算符
#include<stdio.h>
#define PERIOD '.'
int main(void)
{
char ch;
int charcount = 0;
while((ch=getchar())!= PERIOD)
{
if(ch!='"'&&ch!='\'')
charcount++;
}
printf("There are %d non-quote characters.\n",charcount);
return 0;
}
逻辑运算符:
- &&与
- ||或
- !非
(练习&&时间)==完美
7.3.1 备选拼写:iso646.h
&& --and
|| --or
! --not
7.3.2 优先级
a>b&&b>c||b>d相当于
((a>b)&&(b>c))||(b>d).
7.3.3 求值顺序
逻辑表达式的求值顺序是从左往右的,一旦发现有使整个表达式为假的因素,立即停止求值。
7.3.4 范围
测试在某个范围:
if(range>=90&&range<=100)
//测试小写字母
if(ch>='a'&&ch<='z')
//对于EBCDIC编码的使用ctype.h的islower()函数
if(islower(ch))
7.4 一个统计单词的程序
问题描述:编写一个统计单词数量的程序(该程序读取并报告单词的数量),该程序能识别并计算这些内容:字符、行数和单词,伪代码如下:
读取一个字符
当有更多的字符输入时
递增字符计数
如果读完一行,递增行数计数
如果读完一个单词,递增单词计数
读取下一个字符
前面有一个输入循环的模型
while ((ch = getchar()) != STOP)
{
...
}
//改进
如果c不是空白字符,且inword为假
设置inword为真,并给单词计数
如果c是空白字符,且inword为真
设置inword为假
// wordcnt --统计字符数、单词数、行数
#include<stdio.h>
#include<ctype.h>
#include<stdbool.h>
#define STOP '|'
int main(void)
{
char c; //读入字符
char prev; //读入的前一个字符
long n_chars = 0L; //字符数
int n_lines = 0; //行数
int n_words = 0; //单词数
int p_lines = 0; //不完整的行数
bool inword = false; //如果c在单词中,inword 等于true;
printf("Enter text to be analyzed(| to terminate):\n");
prev = '\n'; //用于识别完整的行数
while((c=getchar())!= STOP)
{
n_chars++; //统计字符数
if(c=='\n')
{
n_lines++; //行数
}
if(!isspace(c)&&!inword)
{
inword = true; //开始一个新的单词
n_words++;
}
if(isspace(c)&&inword)
{
inword = false; //到达单词的末尾
}
prev = c;
}
if (prev!='\n')
p_lines = 1;
printf("characters = %d,words=%d,lines=%d,",n_chars,n_words,n_lines);
printf("partial lines = %d\n",p_lines);
return 0;
}
7.5 条件运算符:?:
C提供条件表达式(conditional expression)作为表达 if else语句的一种编写方式。?:该运算符分为两部分,需要三个运算对象。三元运算符。
比如:一个数的绝对值
x = (y<0)?-y:y;
//解释
if(y<0)
x=-y;
else
x=y;
把两个值中的最大值赋给变量
max=(a>b)?a:b;
问题描述:计算刷给定平方英尺的面积需要多少罐油漆。(1.7卖2罐)
// paint.c --使用条件运算符
#include<stdio.h>
#define COVERAGE 350 //每罐油漆可刷面积(平方英尺)
int main(void)
{
int sq_feet;
int cans;
printf("Enter number of square feet to be painted:\n");
while(scanf("%d",&sq_feet)==1)
{
cans=sq_feet/COVERAGE;
cans +=(sq_feet % COVERAGE==0)?0:1;
printf("You need %d %s of paint.\n",cans,cans==1?"can":"cans");
printf("Enter next value (q to quit);\n");
}
return 0;
}
7.6 循环辅助:continue和break
continue和break语句可以根据循环体中的测试结果来忽略一部分循环内容,甚至结束循环。
7.6.1 continue语句
3种循环都可以使用continue语句。执行到该语句,会跳过本次迭代的剩余部分,并开始下一轮的迭代。
// skippart.c --使用continue跳过部分循环
#include<stdio.h>
int main(void)
{
const float MIN=0.0f;
const float MAX=100.0f;
float score;
float total = 0.0f;
int n= 0;
float min = MAX;
float max = MIN;
printf("Enter the first score (q to quit):");
while(scanf("%f",&score)==1)
{
if(score<MIN||score>MAX)
{
printf("%0.1f is an invalid value.Try again:",score);
continue; //跳转到while循环的测试条件
}
printf("Accepting %0.1f:\n",score);
min = (score<min)?score:min;
max = (score>max)?score:max;
total+=score;
n++;
printf("Enter next score(q to quit):");
}
if(n>0)
{
printf("Average of %d scores os %0.1f.\n",n,total/n);
printf("Low = %0.1f,high=%0.1f\n",min,max);
}
else
printf("No valid scores were enterd.\n");
return 0;
}
有两种办法可以避免使用continue。
一:把剩余块放入else块中
二:用以下格式来代替:
if(score>=0&&score<=100)
{
/*语句*/
}
continue还可以作占位符。例如:下面的循环读取并丢弃输入的数据,直至读到行末尾;
while(getchar()!='\n')
continue;
如果使用了continue没有简化代码,
while((ch=getchar())!='\n')
{
if(ch=='\t')
continue;
putchar(ch);
}
//不如
while((ch=getchar())!='\n')
{
if(ch!='\t')
putchar(ch);
}
通常,在这种情况下,把if条件的关系反过来可以避免使用continue。
//不包括换行符
count = 0;
while(count<10)
{
ch = getchar();
if(ch=='\n')
continue;
putchar(ch);
count++;
}
//包含换行符
count = 0;
for(count = 0; count<10;count++)
{
ch = getchar();
if(ch=='\n')
continue;
putchar(ch);
}
7.6.2 break语句
程序执行到循环中的break语句时,会终止包含它的循环,并继续执行下一段程序。把skippart.c中的continue换成break时,不是执行下一轮循环,而是导致突出当前循环。如果break语句位于嵌套循环内,它只会影响包含它的循环。
break用例:
用一个循环计算矩形的面积,如果用户输入了非数字作为矩形的长或宽,则终止循环。
// break.c --使用break退出循环
#include<stdio.h>
int main(void)
{
float length,width;
printf("Rnter the length of the rectangle:\n");
while(scanf("%f",&length)==1)
{
printf("length = %0.2f:\n",length);
printf("Enter its width:\n");
if(scanf("%f",&width)!=1)
break;
printf("Width = %0.2f:\n",width);
printf("Area = %0.2f:\n",length*width);
printf("Rnter the length of the rectangle:\n");
}
printf("Done.\n");
return 0;
}
//也可以这样控制循环
//while(scanf("%f %f",&length,&width)==2)
//但是break可以方便显示用户输入的值。
和continue一样
while((ch=getchar())!='\n')
{
if(ch=='\t')
break;
putchar(ch);
}
//不如
while((ch=getchar())!='\n'&&ch!='\t')
{
putchar(ch);
}
break的嵌套
int p,q;
scanf("%d",&p);
while(p>0)
{
printf("%d\n",p);
scanf("%d",&q);
while(q>0)
{
printf("%d\n",p*q);
if(q>100)
break; //跳出内层循环
scanf("%d",&q);
}
if(q>100)
break; //跳出外层循环
scanf("%d",&p);
}
7.7 多重选择:switch和break
问题描述:程序读入一个字母,然后打印出该字母开头的动物名。
// animals.c --使用switch语句
#include<stdio.h>
#include<ctype.h>
int main(void)
{
char ch;
printf("Give me a letter of the alphabet,and I will give an animal name \n beginning with that letter.\n");
printf("Please type in a letter;type $ to end my act.\n");
while((ch=getchar())!='#')
{
if('\n'==ch)
continue;
if(islower(ch)) //只接受小写字母
switch(ch)
{
case'a':
printf("apple\n");
break;
case'b':
printf("bababababba\n");
break;
case'c':
printf("cat\n");
default:
printf("oh no");
}
else
printf("I recongized only lowercase letters.\n");
while(getchar()!='\n')
continue; //跳过输入行的剩余部分
printf("Please #\n");
}
printf("Bye!\n");
}
7.7.1 switch语句
switch在圆括号中的测试表达式的值应为一个整数值(包括char类型)。case标签必须是整数类型(包括char)的常量或整型常量表达式(即,表达式中只包含整型常量)。不能用变量作为case标签。switch的构造如下:
switch(整型表达式)
{
case 常量1:
语句;
case 常量2:
语句;
。。。
default
语句;
}
7.7.2 只读每行的首字符
animals.c的另外一个独特之处他读取的方式。响应单字符的交互程序中。
while(getchar()!='\n')
continue;
循环从输入中读取字符,包括按下Enter键产生的换行符。函数的返回值没有赋给ch,以上代买所做的只是读取并丢弃字符。由于最后丢弃的字符是换行符,所以下一个读取的字符是下一行的首字母。在外层的while循环中,getchar()读取的首字母并赋给ch。
假设用户一开始按Enter:
if(ch=='\n')
continue;
7.7.3 多重标签
// vowels.c --使用多重标签
#include<stdio.h>
int main(void)
{
char ch;
int a_ct,e_ct,i_ct,o_ct,u_ct;
a_ct=e_ct=i_ct=o_ct=u_ct=0;
printf("Enter some text;enter # to quit.\n");
while((ch=getchar())!='#')
{
switch(ch)
{
case 'a':
case 'A':a_ct++;
break;
case 'e':
case 'E':e_ct++;
break;
case 'i':
case 'I':i_ct++;
break;
case 'o':
case 'O':o_ct++;
break;
case 'u':
case 'U':u_ct++;
break;
default:break;
}
}
printf("number of vowels:A E I O U");
printf("%4d %4d %4d %4d %4d",a_ct,e_ct,i_ct,o_ct,u_ct);
return 0;
}
case 'u':后面的break可以去掉,但是防止再在后面添加东西时忘了break,因此还是保留较好。
//使用ctype库中的toupper()函数
while((ch=getchar())!='#')
{
ch = toupper(ch); //将字母转换为大写
switch(ch)
{
case 'A':
...
}
}
或者,也可以先不转换ch,把toupper(ch)放进switch的测试条件中;switch(toupper(ch)).
7.7.4 switch和if else
if else 在范围方面更好一点
7.8 goto语句
goto part2;
part2:printf("...");
7.8.1 避免使用goto
- 处理包含多条语句的if语句:
if(size>12) goto a; goto b; a: xxxxx; b: xxxxx; //在c中可以这样 if(size>12) { xxxxx; } else { xxxxx; }
- 二选一
C通过if else更清楚 - 创建不确定循环
redin:scanf("%d",&score); if(score<0) { goto stage2; } lots of statement goto readin; stage2:more stuff;
用while代替
scanf("%d",&score) while(score<=0) { lots of statement scanf("%d",&score); } more stuff;
- 跳转到循环末尾,开始下一次迭代,C用continue代替
- 跳出循环。C用break
- 胡乱跳转至程序的不同部分。简而言之,不要这么做!
可以接受:(出现问题时从一组嵌套循环中跳出,一条break只能跳出当前循环)while(funct > 0) { for(i=1;i<=100;i++) { for(j=1;j<=50;j++) { 其他语句 if(问题) goto help; 其他语句 } 其他语句 } 其他语句 } 其他语句 help:语句
讽刺的是,虽然C根本不需要goto,但是它的goto比其他语言的goto好用,因为C允许在标签中使用描述性的单词而不是数字。
// goto.c --跳转测试 #include<stdio.h> int main(void) { int a; int b; a1: scanf("%d %d",&a,&b); if(a==1) { goto a1; } goto a2; printf("hhahha"); a2: printf("end"); return 0; }
7.9 关键概念
智能的一个方面是,根据情况做出相应的响应。所以,选择语句是开发具有智能行为程序的基础。C语言通过if、if else和switch语句,以及条件运算符(?:)可以实现智能选择。
叨叨几句... NOTHING