伊吖学C笔记(3、字符、分支结构)

一、字符(串)

如果说"加减乘除余"是C语言中的数学,那字符(或字符串)就是C语言中的语文。

1.定义

用"char ch;"来定义单个字符变量,用"char str[20];"定义字符串,用"char *str;"也可定义字符串。

字符的双重属性,即:既表字符又表数字。为了弄清这个问题,我们先看看ASCII表:

表中,一个8位二进制对应特殊的功能或字符,比如00001010(10)代表换行(\n),00001101(13)代表回车(\r),00110000(48)代表字符0,00110001(49)代表字符1,010000001(65)代表A,01100001(97)代表a,等等。

一个字符默认的数值就是它ASCII的十进制数,用%c输出是字符,用%d输出是数字。

当然,ASCII码还有扩展部分:

输出扩展字符需要加上:

#include <windows.h>和SetConsoleOutputCP(437);

比如实线表格线,就要用到这些字符:

但是要与下面这个中文表格的区别:

这是中文双字节制表符,在word或excel里通过插入符号实现。

单个字符的处理要用单引号,一个个处理太麻烦,通常我们用字符串来处理文字。字符串定义常用到字符数组和指针。

我们发现定义字符串数组,输出时出了问题,数组st、s都出现不必要的尾巴。那是因为:集中定义时,用双引号时,字符串会自动加上结束标志"\0",本例str[]、*p就是。而单个定义时,没有"\0",输出时循环遍历输出。如要把它当作串输出,需多定义一位长度。

多行文本定义:

2.字符输入

2.1、getchar()

getchar()支持一次输入字符串,多次调用,每次一个字符。

与getchar()相对应的是putchar(ch),输出字符。

2.2、getch()

对比getchar(),getch()无缓冲无回显立即响应;有时在程序执行过程中需要暂停,可加一句getch();意思是等待键盘输入一个字符继续。getch()也可用于密码保护:

也有getche(),类似getch(),但有回显。

2.3、gets()

字符串输入函数,空格一起计算字符。

对应的put(a)为输出字符串函数。

另外还有fgets()、fgetc(),也可以读串,后说。

2.4、scanf()

格式:scanf("格式控制",变量地址列表)

scanf()有点眼盲,空格后面就不认了。看样子字符串,还是gets()好用。

scanf()运行完成一次后,键盘缓冲区还留了一个结束标志,对后续输入造成了影响。

当输入单个字符时,前面有没有输入,如果有则要空一格,抵消结束符。另外,scanf()参数后半截是变量地址列表,不是变量列表,如果是变量,一定要作地址引用,加&。数组、指针不用加&,默认就是地址的意思。

3.字符操作

3.1、字符串连接strcat(a,b)

3.2、字符串复制strcpy(a,b)

无论长短,皆是复制品。

也可以通过程序实现:

3.3、字符串比较strcmp(a,b)

相等才是0,要注意,第一个长:1,第一个短:-1。

3.4、字符串截取strncpy(a,b+n,m)

3.5、其他

strlen(a)字符串的长度

strlwr(a)大写字母变小写

strupr(a)小写变大写

二、分支

我们设计的程序在执行过程中,不可能是一帆风顺,遇到一些十字路口,要进行选择,走哪条路?这就是程序的分支结构。

1.单分支

++if(++ ++条件)操作语句;++

如果只关心一个条件(比如,班里叫张三的同学),或一类条件(比如,考试成绩在90分以上),并且只对满足条件的对象进行操作或运算,其他不管,就用++if(条件)操作语句;++,最简单的if,满足条件即运行,根据条件选择执行。

题目:输入一个字符串,统计有多少数字?

2.双分支

++if(++ ++条件)操作语句1;++

++else++ ++操作语句2;++

如果同时关心满足条件的和不满足条件的两类情况(比如:班上及格的同学和不及格的同学),要进行两种不同的操作或运算,就用双分支。

题目:输入字符串,分别输出是数字还是不是数字,并分别统计个数?

3.多分支

++if(条件1)操作语句1;++

++else if++ ++(条件2)操作语句2;++

++...++

++else if++ ++(条件n)操作语句n;++

++else++ ++操作语句n+1;++

如果关心的条件有多个(比如考核结果分为:优秀、称职、基本称职、不称职),并且进行不同的操作,这时就可以用到多分支。看个一个打折的例子:

题目:输入字符,如果输入是大写字母直接输出;如果是小写,转换为大写输出;如果是其他,输出不是字母。

字母大小写转化的问题,先看ASCII字符表,如下:

从表中可以看出:大写字母A-Z的ascii编号从65到90,小写字母的编号从97到122,这是固定的。

大写变小写,只需要把编号增加32就行。有些编程用的是:+'a'-'A',也就是+97-65,也是加32,一个意思。小写变大写,减32就行,总之,小写的编号比大写的大。

题目:由键盘输入一个3位的整数,判断该数是否为升序数。若输入的不是3位数,输出"Enter error"。升序数是指高位数依次小于其低位数的数。如,359为升序数。

设计思路:首先是判断是不是三位数?这是一层意思,然后再在三位数里判断是升序还是不是升序,这是第二层意思。用if...else if...else...这个语句可以解决。

if(a<100||a>999)

//判断非三位数:如果小于100或大于999,那就一定不是三位数了。

else if(a/100<a/10%10&&a/10%10<a%10)

//判断是否升序:a是三位整数,a/100的结果取整,即为百位数字。比如358/100=3,865/100=8,整数除整数,结果只取整数。个位数,a%10,即除以10的余数,比如358%10=8、865%10=5。中间的十位数还是有点麻烦,先除以10取出前两位,再除以10取余数,即a/10%10。比如:358/10%10=5、865/10%10=6。

升序要同时满足:百位数<十位数<个位数,所以中间要用逻辑与&&。如果同时满足条件,即++百位数<十位数++ 成立,并且++十位数<个位数++也成立。

题目:输入三个整数x,y,z,请把这三个数由小到大输出。

思考:三个数的排序,当然先比较2个,分出大小。再用第三个数去分别比较,比小的小,放在最前面;比大的大,放在最后面;否则放中间。这是最常规的思路(方法1)。

键盘输入(三板斧):

int x,y,z;

printf("请输入三个整数,中间用空格格开:");

scanf("%d %d %d",&x,&y,&z);

排序如下:

if(x>y) //先排出x>y的可能排列组合:3种

if(y>z)printf("%d %d %d",z,y,x);//小于小的

else if (z>x)printf("%d %d %d", y,x,z);

else printf("%d %d %d", y,z,x);

else //再排出x<y的可能,也是3种

if(x>z)printf("%d %d %d",z,x,y);

else if (z>y)printf("%d %d %d", x,y,z);

else printf("%d %d %d",x,z,y);

这种思路好理解,不改变xyz原来的赋值,就是编程有些烦琐,用到了5个if、5个else、6个printf(因为有6种可能的排列组合)。

有没有更好更简洁的方法呢?有。交换法(方法2),xyz的顺序始终不变,小的值往前换,大的往后换,换3次。

if(x>y){t=x;x=y;y=t;} //保持x<y,如果x>y则互换

if(y>z){t=y;y=z;z=t;} //用z比较y,看谁最大,如果y>z则互换,保持y<z,此时z最大

if(x>y){t=x;x=y;y=t;} //再比较xy,再次确保x<y

我们发现第一个if与第三个if一模一样,没搞错吧?我们这样理解排序过程:

|------------------------|----|----|---|-----|-----|-----|
|   | x | y | z | 举例 |||
| 开始 | ? | ? | ? | 852 | 528 | 582 |
| if(x>y){t=x;x=y;y=t;} | 小 | 大 | ? | 582 | 258 | 582 |
| if(y>z){t=y;y=z;z=t;} | 小1 | 小2 | 大 | 528 | 258 | 528 |
| if(x>y){t=x;x=y;y=t;} | 小 | 中 | 大 | 258 | 258 | 258 |

这个比较后交换的顺序是:先是1、2位,再是2、3位(确定最大值),最后是1、2位。

有些书上的答案稍有区别:先是1、2位,再是1、3位(确定最小值),最后是2、3位,如下:

|------------------------|---|----|----|-----|-----|-----|
|   | x | y | z | 举例 |||
| 开始 | ? | ? | ? | 852 | 528 | 582 |
| if(x>y){t=x;x=y;y=t;} | 小 | 大 | ? | 582 | 258 | 582 |
| if(x>z){t=x;x=z;z=t;} | 小 | 大1 | 大2 | 285 | 258 | 285 |
| if(y>z){t=y;y=z;z=t;} | 小 | 中 | 大 | 258 | 258 | 258 |

程序运行结果如下:

上面就是if的基本框架及应用举例。if框架都可以嵌套,建议嵌套层级3-5层。

4.开关语句switch

最简单的理解:对号入座。

switch(开关){

case 1:...;

case 2:...;

...;

case n:...;

default:...;}

根据开关的值,决定到哪运行,就相当于,你是几班,就进几班的教室,case后面的值就是班号,如果你还没分班,前面都不是,就到default(缺省)报到。

case后面最后一般都会加上break,跳出switch,否则会顺序执行下面的case。

default:...也可以没有。

运行流程图如下:

下面看个例子:

首先 x=1,执行++case 1:a++;这句++ ,结果a=1了;由于后面没有break;继续执行++case 2:a++;b++;break;++这句,结果a=2,b=1了。执行完这句后,后面有break;跳出,结束switch。

再看个例子:

题目:输入某年某月某日,判断这一天是这一年的第几天?

思考:年有平年365、闰年366之分;月有31、30、29、28天的区别。第几天怎么确定?先从第一个月捋一捋,一月无论什么时候都是31天,那一月++日期数++ 就是这一年的第几天。比如1月5日,就是全年第5天;二月呢:就是二月的++日期数++ 加上31,就是这一年的第几天。比如2月3日就是全年第34天;三月呢:平年是三月的++日期数++ +31+28,闰年是++日期数+++31+29...依此类推,后面的月份都是两种可能,但有同一规律:闰年比平年多一天。是不是我们就可以:先只管平年,完成平年的计算;最后加上一个if判断,如果闰年,且月份数大于2,则平年的结果+1。

如何完成平年的第几天计算呢?我们先找找规律看:1-12月的月长分别为:31、28、31、30、31、30、31、31、30、31、30、31。虽然主要为30、31两个数,但规律并不明显,7月、8月连续两个31天,奇偶关系也变了。那我们就用比较老实的办法了,用switch()语句,设计12种可能性来完成。

闰年的判断:如果是世纪年,除以400等于0就是闰年++即y%400==0++ ;如果是非世纪年++(y%100!=0)++ ,除以4等于0才是闰年,即++y%4==0++。综合起来就是

++y%400==0||y%4==0&&y%100++ ++!=0++

因为"&&"(逻辑与)的优先级高于"||"(逻辑或),比如:A&&B||C&&D,等价于(A&&B)||(C&&D)。

如果是分步判断,流程如下:

相关推荐
xiaomu_3472 分钟前
机器人强化学习入门学习笔记(三)
笔记·学习
十五年专注C++开发6 分钟前
CMake基础:CMakeLists.txt 文件结构和语法
开发语言·c++·cmake·跨平台编译
低维歌者20 分钟前
python训练营day34
开发语言·python
zxc_user27 分钟前
java后端-海外登录(谷歌/FaceBook/苹果)
java·开发语言·谷歌·facebook·海外登录
2401_8368365936 分钟前
python与flask框架
开发语言·python·flask
北漂老男孩36 分钟前
Scala与Spark:原理、实践与技术全景详解
大数据·开发语言·spark·scala·学习方法
chainbees1 小时前
Qt 布局管理器的层级关系
开发语言·qt
南瓜胖胖1 小时前
【R语言科研绘图】
开发语言·r语言
要加油哦~1 小时前
刷题 | 牛客 - js中等题-下(更ing)30/54知识点&解答
java·开发语言·javascript
五步晦暝1 小时前
【Excel 扩展正则的能力】工作中赋予处理单元格文本的强大正则表达提取能力
开发语言·excel