
C语言是很经典的一种编程语言。所以本系列只是讲一下基础内容仅供初学者学习如何打代码不对专业知识进行过多的解释旨在让感兴趣的同学可以操作而非全部理解。C语言系列文章C语言第一章——Hello World!https://blog.csdn.net/Yang_04/article/details/147539548C语言第二章——计算三角形周长https://blog.csdn.net/Yang_04/article/details/147540458C语言第三章——计算三角形面积https://blog.csdn.net/Yang_04/article/details/147540814C语言第四章——计算一元二次方程的解https://blog.csdn.net/Yang_04/article/details/147545466本系列代码都将在 C语言编译器Dev-cpp 5.11 中进行编写运行。在上一章节中我们成功设计了一个计算一元二次方程解的程序#include stdio.h #include math.h #define delta pow(b,2)-4*a*c int main() { double a,b,c; double x1,x2; printf(一元二次方程求解程序ax2bxc0a≠0\n); printf(请输入a的值);scanf(%lf,a); printf(请输入b的值);scanf(%lf,b); printf(请输入c的值);scanf(%lf,c); x1 (-b pow(delta,0.5)) / 2 * a; x2 (-b - pow(delta,0.5)) / 2 * a; if(a ! 0) // a 不等于 0 的时候执行 { if(delta 0) // delta 大于 0 的时候执行 { printf(x1的值为%lf\n,x1); printf(x2的值为%lf\n,x2); } else if(delta 0) // if(x1 x2) { printf(x1x2%lf\n,x1); } else // if(delta 0) delta 小于 0 的时候执行 { printf(error:Δ小于0方程无实数解\n); } } else // if(a 0) a 等于 0 的时候执行 { printf(error:a的值不能为0\n); } return 0; }相信喜欢细节的读者们都关注到了一个小细节在16行和17行关于x1和x2的计算公式中左边括号是一个整体 -b±pow(delta,0.5) 在右边是先 /2 后 *a其实应该写成(-b ± pow(delta,0.5)) / (2 * a)才是比较合理的否则很有可能会先进行 /2 运算然后再进行 *a 运算也就是会变成了(-b ± pow(delta,0.5)) * a / 2那么我们的程序也就会出现计算错误结果的情况但是为什么在我们上一章的程序没有因此而出现计算错误呢这个就要涉及到C语言中的一个关于 “优先级” 的概念在使用同一类符号时有些符号需要考虑先使用和后使用的情况。https://www.runoob.com/cprogramming/c-operators.html就像我们小学时学的四则运算在遇到加减乘除的式子时会先计算乘除再计算加减所以我们写代码时也是一样的道理。由于在C语言中乘法符号*的优先级比 取整符号/要高所以在我们这个程序计算x1和x2的结果时因为括号的优先级最高左边有小括号而且是个整体肯定是要先算的这个毫无疑问那么我们在计算右边时根据上表的优先级来看那就是先计算2 * a的值然后再计算左边 / 右边至于我为什么要说 / 是 取整符号 呢因为他还有个好兄弟——叫做 取余符号%什么意思呢在计算数值时我们通常会涉及到二进制转换数那么这里就稍微提及一下不作过多的说明。没关系长痛不如短痛我们马上来讲一下 这到底是怎么个事儿十进制由数字0到9构成计数系统。比如我们经常使用的0123456789这样子就是十进制的计数进位之后原位归零二进制由数字0和1构成计数系统。和十进制类似也是进位之后原位归零不过换成了两个数来计算进位而已。那如果我们要用二进制显示我们日常使用的十进制数的话应该如何表达呢假如我们用4位十进制数和4位二进制数来进行计数那么我们可以稍微来列举一下 0到15 的十进制数与其二进制数的转换关系十进制0000——二进制0000十进制0001——二进制0001十进制0002——二进制0010十进制0003——二进制0011十进制0004——二进制0100十进制0005——二进制0101十进制0006——二进制0110十进制0007——二进制0111十进制0008——二进制1000十进制0009——二进制1001十进制0010——二进制1010十进制0011——二进制1011十进制0012——二进制1100十进制0013——二进制1101十进制0014——二进制1110十进制0015——二进制1111怎么样好像也不是很复杂是吧那么 如果我需要的 不是按顺序的写出这些 十进制数对应的二进制数 而是说 随便来个 十进制数你能不能马上说出 对应的二进制数 呢那你可能第一反应就是说“那我把这个表记下来不就好了嘛”那如果我不是要15的二进制数呢我要的是16或者128甚至是带小数的数3.14的二进制数呢那是不是就需要更多位数的二进制数来存储而且一个个列表来数来计算的话是不是也就麻烦了很多 是吧所以就有两种方法来对付这种 十进制数转二进制数十进制数转二进制数整数部分——“除二取余法”顾名思义将十进制数的整数部分除以二商不为0的话就用商继续除以2一直除到商为0然后将余数从下往上按顺序排列。比如 1212 / 2 6......06 / 2 3......03 / 2 1......11 / 2 0......1将余数从下往上排列就是1100这个也就是十进制数 12 的二进制数小数部分——“乘二取整法”顾名思义将十进制数的整数部分忽略小数部分乘以二初始个位值为0小数部分乘以二的积不为0的话就继续用积乘以2并记录整数部分的值个位出现进位是将其记录下来并将个位值清零一直乘到小数部分为0 或者 达到规定的位数 为止然后将个位值从上往下按顺序排列。比如 3.14整数部分的 3 我们可以通过上面的 “除二取余法” 得到他的二进制数为0011所以 小数部分是 0.14 我们使用 “乘二取整法”0.14 * 2 0.280.28 * 2 0.560.56 * 2 1.120.12 * 2 0.240.24 * 2 0.480.48 * 2 0.960.96 * 2 1.920.92 * 2 1.840.84 * 2 1.680.68 * 2 1.360.36 * 2 0.720.72 * 2 1.440.44 * 2 0.880.88 * 2 1.760.76 * 2 1.520.52 * 2 1.040.04 * 2 ......太多啦我不算啦这里已经有 4个4位数了我就不继续进行计算了草率了 这个数计算量貌似有点大那么我们的十进制数 3.14 最终转换的二进制数就是0011.0010 0011 1101 0111我们可以使用网上找到的进制转换器来验证一下我们的答案可以看到在整数部分和小数后的前16位小数的换算都是正确的只不过我们不再计算下去了而已换个好算的数字就是这个样子的https://zhuanlan.zhihu.com/p/75291280那么我们讲了这么多是为了什么呢十进制转二进制时使用的是取整数和取余数的方法那么我们如果想写一个可以输入任意的十进制数 随即 输出对应的二进制数 的程序的话那我们是不是就需要用到 取整数 和 取余数所以在我们写代码时就需要用两个 “大哥” 区分开这两个计算方式隆重介绍一下这两位 “大哥” 就是我们的 取整符号/ 和 取余符号%我们可以写个程序来看下他俩的区别#include stdio.h int main() { short int i,j; i 21 / 2;printf(short int i 21 / 2 %d\n,i); j 21 % 2;printf(short int j 21 %% 2 %d\n,j); printf(\n); long int x,y; x 12 / 2;printf(long int x 12 / 2 %ld\n,x); y 12 % 2;printf(long int y 12 %% 2 %ld\n,y); printf(\n); int a,b; a 3 / 2;printf(int a 3 / 2 %d\n,a); b 3 % 2;printf(int b 3 %% 2 %d\n,b); printf(\n); float c,d; c 13 / 2;printf(float c 13 / 2 %f\n,c); d 13 % 2;printf(float d 13 %% 2 %f\n,d); printf(\n); double p,q; p 23 / 2;printf(double p 23 / 2 %lf\n,p); q 23 % 2;printf(double q 23 %% 2 %lf\n,q); return 0; }编译运行一下效果如下我们注意到在 输出函数printf() 中一个%号是占位符在 C语言第二章——计算三角形周长 有解释到。那么如果我们想要在 输出函数printf() 中显示 “%” 这个符号呢那么很简单的一个事我们只要像上面那个代码那样 写成 “%%” 这样子就好啦你也可以理解为“给 百分号% 占位置”反正你知道怎么用就好了那如果我们想要写个程序来输出数值的各种进制数我们可以百度一下https://blog.csdn.net/agkl_hanhan/article/details/123978372所以我们可以这样写#include stdio.h #include stdlib.h int main() { int i; char s[10]; printf(请输入十进制整数);scanf(%d,i); itoa(i, s, 2); printf(%d的二进制数%s\n,i,s); printf(%d的八进制数%o\n,i,i); printf(%d的十进制数%u\n,i,i); printf(%d的十六进制数%x\n,i,i); return 0; }编译运行一下效果如下当我们把十进制数转换成二进制数后根据 “三位一体” 和 “四位一体” 来转换成 八进制数 和 十六进制数至于十进制数怎么转换成八进制数和十六进制数有机会再说这里就不再赘述感兴趣的也可以自己百度。好我们接下来还是关注一下我们的重点取整符号/顾名思义用来取两数相除时的整数商比如 34 ÷ 4 8......2所以 34 / 4 8取余符号%顾名思义用来取两数相除时整数商所对应的余数部分比如 34 ÷ 4 8......2所以 34 % 4 2怎么样这样子是不是很好理解了那么如果我拿出他们哥俩的组合技 阁下又应该如何应对呢比如256 / 10 / 10 256 / 10 % 10 256 % 10 我们可以稍微计算一下256 / 10 2525 / 10 2所以 256 / 10 / 10 2256 / 10 2525 % 10 5所以 256 / 10 % 10 5256 % 10 6仔细看一下我们的计算结果是不是发现规律了通过对10的取整取余我们可以获得多位数的各位置对应数值那么你就会好奇了取整符号/和取余符号%到底哪个优先级会高呢如果出现在我们上一章的代码中会不会导致我们的程序计算数值出现错误呢我去问了下chatGPT4.0他的回答倒是挺符合我们的问题的当然啦~经过上面取整取余的小训练如果我们想要写一个输入随机数输出按顺序排序大小的数值的代码你就可以很快的想到 可以通过对每个位置的数值进行比较 然后再依次进行排序输出对吧不过这样子的话 目前对于我们所学的知识量来说 还是稍微复杂了点那我们有没有简单一点的方法其实是有滴~这就要涉及到我们这一章要写的代码啦~怎么做呢其实 我们可以比较相邻两个位置的数字如果谁比谁大那就互换位置。等每个相邻位置的数字比较完这样子我们的数字也就排好啦~是不是有点听不懂没关系那我们来这样子想想看首先我们需要输入两个数然后我们再判断如果ab那么就将a和b的数值互换怎么实现呢众所周知我们如果直接写一条ab把b的值赋给a之后a原来的值就没有了因为此时a的值被覆盖了那怎么办呢我们可以借助一个中间量比如我们可以叫它为temp暂时储存a的值比如这样子 “tempa;” 然后我们再用一句 “ab;” 将b的值赋给a此时a的值被b的值覆盖接着我们再把temp的值这里储存着原来a的值赋给b也就是 “btemp;” 这样子我们就实现了a、b的值互换啦~让我们来认真写个代码看看效果是不是和我们想的一样#include stdio.h int main() { int a,b; int temp; printf(请输入两个整数:); scanf(%d %d,a,b); if(ab) { tempa;ab;btemp; } printf(从大到小排序为:%d %d\n,a,b); return 0; }编译运行一下没有问题喜欢举一反三的小伙伴们很快就能想到了那我们也可以写输入三个数、四个数、五个数甚至更多个数的排序啊是的。只要你想其实可以写很多很多个不过呢这里提供一个输入四个数的程序读者可以自行理解一下逻辑这里不再继续多讲#include stdio.h int main() { int a,b,c,d; int temp; printf(请输入四个整数:); scanf(%d %d %d %d,a,b,c,d); if(ab) { tempa;ab;btemp; } if(ac) { tempa;ac;ctemp; } if(ad) { tempa;ad;dtemp; } if(bc) { tempb;bc;ctemp; } if(bd) { tempb;bd;dtemp; } if(cd) { tempc;cd;dtemp; } printf(从大到小排序为:%d %d %d %d\n,a,b,c,d); return 0; }编译运行一下没有问题反骨的你可能会想那除了这样子一个个比较有没有其他方法来实现数值互换的操作呢其实是有的不过我们需要知道一个概念异或什么意思呢我们可以搜一下https://blog.csdn.net/broadCE/article/details/52071360简而言之就是不同的出1相同的出0毕竟是“异”嘛那你很快就会想到了那它肯定也有个“兄弟”就是不同的出0相同的出1那个就是我们所说的 “同或”那么在C语言中异或的符号我们用 ^ 来实现我们可以先来看看位运算由于查到的结果很清晰明了我就不作解释了直接上图https://blog.csdn.net/w7486/article/details/119614008注意按位运算是一个字符实现在逻辑判断中的 “与”运算 和 “或”运算|| 是两个字符实现因为“同或”的结果和“异或”取反的结果一样所以当我们需要用到“同或”时可以考虑先“异或”然后再将其取反这样子得到的结果也是“同或”的值有点曲线救国的意思但这种思想 在我们以后编写程序时会经常用到因为我们可能通常会借助现有的东西去等价或者去实现我们想要的效果至于为什么左移相当于“×2”右移相当于“/2”我们可以继续回想一下我们刚开始所说的进制转换由于二进制转十进制时我们的转换方法是 计算第n位的 “值*2ⁿ” 然后相加由于我们计算机里面都是从 “第0位” 开始计数所以在计算时需要注意这个问题。https://zhuanlan.zhihu.com/p/75291280言归正传我们可以用 “异或” 的方法来实现两个数互换数值比如这样#include stdio.h int main() { int a,b; printf(请输入a的值:);scanf(%d,a); printf(请输入b的值:);scanf(%d,b); a a ^ b; b b ^ a; a a ^ b; printf(a的值为:%db的值为%d\n,a,b); return 0; }编译运行一下没有问题至于为什么是这么写你可以自己将a、b的十进制数转成二进制数之后 将这两个数的二进制数异或看看 自行研究当然你也可以改写我们刚刚四个数排序的代码用“异或”的方式进行数值互换这里我就不写了有点懒乐怎么样做到这里你是不是已经对 判断语句if() 很熟练了那么我们可以来介绍一下它的“好朋友”——switch...case当我们在编写程序的时候如果碰到同一个变量有多个值时使用多个if()语句也……可以但是这样子会导致我们的代码看上去很冗长所以这时我们就要考虑用switch...case来简化我们的多个if()语句比如说我们想要写一个输入数字输出对应语句的程序像这样#include stdio.h int main() { int a; printf(请输入数字:);scanf(%d,a); if(a 1) { printf(星期一); } if(a 2) { printf(星期二); } if(a 3) { printf(星期三); } if(a 4) { printf(星期四); } if(a 5) { printf(星期五); } if(a 6) { printf(星期六); } if(a 7) { printf(星期日); } return 0; }编译运行一下没有问题但是这样子我们会发现代码太长了而且还是同一个变量只是出现了变化的值而已这样子万一a有更多取值的话那岂不是要了我们的老命所以switch...case应运而生switch就是“开关”的意思嘛我们可以理解为用变量作为我们执行代码的“总开关”case是“箱子”switch...case一般是应对“一个变量有多个值”的情况所以我们也可以把它理解为 “抽屉” 或者别的其他东西。当我们的开启了“总开关”switch我们可以根据case里的值对其分别对应输出我们的语句所以将上面一大堆if()的代码 用switch...case来写就是这个样子的#include stdio.h int main() { int a; printf(请输入数字:);scanf(%d,a); switch(a) { case 1:printf(星期一);break; case 2:printf(星期二);break; case 3:printf(星期三);break; case 4:printf(星期四);break; case 5:printf(星期五);break; case 6:printf(星期六);break; case 7:printf(星期日);break; default:break; } return 0; }怎么样相比之下是不是看上去简洁很多编译运行一下没有问题那么switch...case的结构是什么呢switch() { case 值1:代码块1; case 值2:代码块2; case 值3:代码块3; ... default:代码块n; }那么你会好奇“break;”是干嘛用的呢其实是用来 退出 的或者是 打断、中断 的意思反正差不多你能理解到就行假如我不写 break; 那么程序就会继续运行在switch...case中就会继续执行后面的语句直到遇到 break; 才会停下来比如这样#include stdio.h int main() { int a; printf(请输入数字:);scanf(%d,a); switch(a) { case 1:printf(星期一\n); case 2:printf(星期二\n); case 3:printf(星期三\n);break; case 4:printf(星期四\n);break; case 5:printf(星期五\n);break; case 6:printf(星期六\n);break; case 7:printf(星期日\n);break; default:break; } return 0; }编译运行一下没有问题那default呢这又是什么我们可以查一下如果你不理解“缺省”的意思没关系你可以理解为 “尚未确定” 的意思也就相当于我们在 C语言第四章——计算一元二次方程的解 中关于 判断语句if() 的变形 if...else 中的 else语句也就是 其他的条件因为我们没办法时时确定else或default的条件所以这就差不多是 “缺省” 的意思了所以我们可以这样子来完善我们的代码#include stdio.h int main() { int a; printf(请输入数字:);scanf(%d,a); switch(a) { case 1:printf(星期一\n);break; case 2:printf(星期二\n);break; case 3:printf(星期三\n);break; case 4:printf(星期四\n);break; case 5:printf(星期五\n);break; case 6:printf(星期六\n);break; case 7:printf(星期日\n);break; default:printf(请输入有效日期\n);break; } return 0; }编译运行一下没有问题综合运用起来我们可以写一个百分制成绩转换五等级成绩#include stdio.h int main() { // 百分制成绩转成五等级成绩 int score 0,mark; printf(请输入你的成绩:); scanf(%d,score); //约束条件 if(score 0 || score 100) { printf(请输入有效成绩\n); } mark score / 10; /* 加a b 减a - b 乘a * b 取整a / b 取余a % b 取高位数字一直对 10 取整 a / 10 ······ 取低位数字一直对 10 取余 a % 10 ······ */ switch(mark) { //0-5共用 case 0: case 1: case 2: case 3: case 4: case 5:printf(E \n);break; case 6:printf(D \n);break; case 7:printf(C \n);break; case 8:printf(B \n);break; case 9:printf(A \n);break; case 10:printf(A \n);break; } return 0; }编译运行一下没有问题但是这个程序当我们输入 超过了100或者小于0的数根据我们的代码它就会执行 printf(请输入有效成绩\n); 并且执行完这个语句之后程序就停止了。想要继续使用的话就需要重新再编译运行一次这样子会让我们的程序显得很鸡肋那么有没有什么办法可以让它不停止运行在出现 输入小于0或大于100 的数时可以在执行完 printf() 之后回到输入成绩的语句 重新输入数值呢那就要介绍一下这个比较方便的跳转语句了goto我们可以看一下它的应用这里我们随便取个 loop 作为跳转位置的标记当然这个标记名可以取别的只要不是有冲突或者有歧义的名字就好#include stdio.h int main() { // 百分制成绩转成五等级成绩 int score 0,mark; loop: printf(请输入你的成绩:); scanf(%d,score); // 约束条件 if(score 0 || score 100) { printf(请输入有效成绩\n); goto loop; } mark score / 10; /* 加a b 减a - b 乘a * b 取整a / b 取余a % b 取高位数字一直对 10 取整 a / 10 ······ 取低位数字一直对 10 取余 a % 10 ······ */ switch(mark) { //0-5共用 case 0: case 1: case 2: case 3: case 4: case 5:printf(E \n);break; case 6:printf(D \n);break; case 7:printf(C \n);break; case 8:printf(B \n);break; case 9:printf(A \n);break; case 10:printf(A \n);break; } return 0; }编译运行一下没有问题好啦第五章完结。本文到此结束有缘下次再见注本文内容说法仅为个人理解全文原创多处用词口语化并非完全都是书上的概念本系列文章旨在可以让初学者独立完成基础程序代码编写仅供学习参考。而且本系列文章随机更新因为我平时可能没空写或者懒得写说不定哪天就弃坑了也可能你所看到的就是最后一篇乐。