当前位置:网站首页>20210807#1 C语言程序结构
20210807#1 C语言程序结构
2022-07-26 10:36:00 【竹某】
一.C语言程序结构
C语言的三类程序结构:顺序结构,选择结构(分支结构),循环结构。
几个重要程序结构相关的概念:表达式,语句,代码块。
简而言之,C语言中使用分号(;)隔开的就是一条语句,而C语言中大括号间的语句就是代码块。
而表达式的概念较为复杂:其从组成上来看,为操作符和操作数;其从作用上来看,是为了产生side effect(副作用)和求值(每一个表达式必有值,void也是值的一种类型)。
详见C语言基本概念之表达式_astrotycoon-CSDN博客_c语言表达式
其中需要强调的是,print()之类的函数调用也是expression,()是函数调用操作符,而print是操作数。
二.选择结构
1.if语句
//if的三种常用用法
if(expression1){
block1;
}
或是
if(expression1)
statement1;
if(expression1){
block1;
}
else{
block2;
}
if(expression1){
block1;
}
else if(expression2){
block2;
}
else if(expression3){
block3;
}
else{
block4;
}关于if……else……使用中if和else的对应:
首先,if可以没有else与之对应;
其次,else必需有与之对应的if。
所以我们考虑如何找到与else对应的if。原则是:找到else上,同一block内最近的if。
关于if……else……被认为是一个语句:
if,else,for,while,do之后若不加{},则只能加单个statement,而不能加block。在嵌套的if……else……语句中,else后没有自己的{},之后却可以放if……else……语句。这说明,if……else……在此被认为是一个语句。使用for同样可以证明。
//证明if else会被认为是一条语句
#include <stdio.h>
int main() {
//利用if证明
if (1)
if (0)
printf("if\n");
else
printf("else\n");
//利用for证明
for (int i = 0; i < 10; ++i)
if (i > 5) printf("if\n");
else printf("else\n");
return 0;
}2.switch语句
switch(整型表达式){
case 整型常量表达式1:
block1;
case 整型常量表达式2:
block2;
case 整型常量表达式3:
block3;
......
//default不是必需的,但是建议有,以处理例外的情况
default:
block4;
}switch语句用于处理多路分支逻辑,case是不同block的入口,而break是出口。也就是说一旦进入了某种case,程序就会执行之后的全部代码,直到break为止。所以在switch中,break的作用是:跳出switch语句。
default的位置与case的位置没有严格的规定,但是default建议放在最后。default也不是必需的,但是建议有,以处理case之外的情况。
switch语句中如果没有循环的话,是不能有continue的。
三.循环结构
1.while语句
while(expr1){
block1;
}
或是
while(expr1)
statement1;while语句的实现逻辑如下。

break在循环语句中的作用是:退出当下循环,常与判断语句连用。
continue在循环中的作用是:退出本次循环(跳过本次循环之后的语句),重新进入当下循环。
while的结构相当松散,只有expr作为循环执行条件是被硬性要求的,而初始化语句往往在while前,步长增加语句往往在block1中。
以下是一段相当经典的while循环的代码:
#include <stdio.h>
int main(){
char ch='0';
while((ch=getchar())!=EOF){
putchar(ch);
}
return 0;
}
//getchar()函数的作用是从输入缓冲区中取一个字符(如果没有的话会等待),并将其作为返回值return。
//putchar(char ch)返回值不关注。作用是打印字符ch。
//顺便讲以下scanf()函数,作用是按给定格式读入数据并将其存入指定地址。
//从输入缓冲区中读入数据,到space或是'\n'为止(并不读入两者)。
//EOF。#define定义的标识符常量。 定义语句: #define EOF (-1)
//键盘键入的方式是:ctrl+z。作用是作为文件结束的标志,类似于'\0'。2.for语句
for循环和while循环执行loop的次数>=0,不会保证循环一定会执行1次。
for循环较之于while循环,将初始化语句、条件判读语句和步长增加语句放在一起,显得更加紧凑。
for(初始化语句;条件判断语句;步长增加语句){
block1;//循环体
}
//当然这三种语句都可以省略。但是条件判断语句被省略的话就被认为是恒为1.
//这会导致死循环。
//在初始化语句中可以定义一个循环控制变量,这使得程序更加紧凑。也使得循环变量可以复用。
//但是一个for循环只能在其初始化语句中定义1/0个循环变量。
for循环不建议在循环体block中改变循环变量的值,这常会导致逻辑错误。
另一个实用的建议是控制循环变量的范围为前0后开。这样可以轻易地看出循环的次数,也非常适合控制数组。
for循环支持多循环变量控制循环。但是这并不常用。例子如下,不同循环变量对应的(仅限初始化和步长增加)语句之间用逗号,隔开。条件判读语句应该仍为expression。
#include <stdio.h>
int main(){
int j=0;
int k-0;
for(int i=0, j=0, k=0;i+j+k<10;++i,++j,++k){
printf("Bamboo");
}
return 0;
}
//一次只能在for循环的初始化语句中定义一个循环控制变量。
//写成for(int i=0, int j=0, int k=0;i+j+k<10;++i,++j,++k){}会导致error3.do……while……循环
do……while……循环和while循环在结构上都不如for循环紧凑。此外,do……while……循环保证循环体被执行1次。
do{
statement;
}
while(expr);//这里的分号不能掉 
4.循环控制语句break和continue
break和continue都会使程序跳出本次循环,不执行本次循环后续代码。但是break是彻底退出loop;而continue只是退出本次循环,对于while和do-while而言,它们直接回到条件判断语句;对于for循环,它回到步长增加语句这里。
5.其他建议
使用循环嵌套时,注意一些变量需要初始化。这些变量的特点是,往往随着内循环的循环而变动,而需要随着外循环的循环而初始化。
使用循环嵌套时可能会导致计算冗余。选用合适的算法均可以提高运算效率。
例子是:
//计算1!+2!+3!+…………+10!
#include <stdio.h>
int main(){
int sum=0;//用于存放和
int ret=1;//用于存放阶乘
for(int i=1;i<11;++i){
ret=1;//这个ret就需要在每次外循环中初始化
for(int j=1;j<i+1;++j){
ret=ret*j;
}
sum+=ret;
}
printf("%d\n",sum);
return 0;
}
这段代码有显而易见的冗余,即每次计算阶乘都是从头乘起,没有利用i!计算的结果得到(i+1)!.
改进后的代码为:
#include <stdio.h>
int main(){
int sum=0;
int ret=1;
for(int i=1;i<11;++i){
ret=ret*i;
sum+=ret;
}
printf("%d\n",sum);
return 0;
}6.折半查找法
折半查找有序数组中的元素,是程序结构的一个很好的例子。
首先在算法层面考虑如何查找元素。首先需要指定查找范围,即数组的下标[left,right]。
在此基础上取mid=(left+right)/2,注意这是整数除法。拿arr[mid]与给定元素进行比较,若小说明给定元素在mid右边,取left=mid+1;若大说明给定元素在mid左边,取right=mid+1;若相等说明找到,返回元素下标,否则继续查找(若...则...可以使用分支结构)。上面的查找过程需要循环进行,直到找到元素(使用break控制)或是无查找范围(经过思考left>right时无查找范围)时停止循环。由于不知道执行循环次数,所以选用while循环较好。
int binarySearch(int* arr, int left, int right, int element) {
int index = -1;//找到返回下标,否则返回-1
while (left <= right) {
int mid = (left + right) / 2;
//若...则...
if (arr[mid]>element) {
right = mid - 1;
}
else if (arr[mid] < element) {
left = mid + 1;
}
else {
index = mid;
break;//找到则退出循环
}
}//end of while
return index;
}//end of function
//基本结构为循环结构和其内的选择结构。选择while来实现loop的原因是不知循环次数,当循环次数已知的话,建议使用for。编写上述程序得到的经验:
1.C语言是和计算机交流的语言,使计算机正确工作地方法只有程序编写者清楚地知道计算机应该做什么并且将它使用高级语言清楚地表述。所以把时间花在算法上。
2.不能为了图快而放弃对算法设计的深入思考,这样反而浪费时间。心里的浮躁一定会反映在笔端,反映在程序上。
3.使用循环时如果知道次数选择for,否则选择while。循环的条件不但可以放在()中的表达式里,还可以使用if……break或是if……continue加以控制。
7.另一些简单的代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
int main() {
char arr1[] = "welcome to bit";
char arr2[] = "##############";
int left = 0;
int right = strlen(arr1)-1;
while (left<=right) {
arr2[right] = arr1[right];
arr2[left] = arr1[left];
right--;
left++;
puts(arr2);
Sleep(1000); //类似于arduino中的delay函数,单位都是ms。S大写。
system("cls"); //s小写。
}
printf("%s\n",arr2);
return 0;
}
//前面使用strlen函数计算字符串长度,是不计算末尾的'\0'的。如果使用sizeof(arr1)/sizeof(char)计算的话,会计入末尾的'\0'
//char arr1[]="hello"这么定义的字符串末尾有'\0',而char arr1[]={'h','e','l','l','o'};这样定义的结尾没有'\0'。
//另外需要注意,计算其他类型数组长度时可以使用sizeof,而不会出现问题。但是要注意,在函数内部计算数组长度时会出现问题。
//比如边栏推荐
猜你喜欢

js 获得当前时间,时间与时间戳的转换

PLC overview
![[leetcode每日一题2021/8/30]528. 按权重随机选择【中等】](/img/13/c6cb176d7065035f60d55ad20ed1bf.png)
[leetcode每日一题2021/8/30]528. 按权重随机选择【中等】

Oracle cannot start tnslistener service cannot start

.NET 开源框架在工业生产中的应用

The problem of large fluctuation of hx711 data

.net5wtm (asp.net core) PgSQL unpacking operation

Centos8 (liunx) deploying WTM (asp.net 5) using PgSQL

粽子大战 —— 猜猜谁能赢

Issue 8: cloud native -- how should college students learn in the workplace
随机推荐
7-25 0-1背包 (50分)
[Halcon vision] programming logic
A semicolon is missing
Our Web3 entrepreneurship project is yellow
事务的传播性propagation
MLX90640 红外热成像仪测温传感器模块开发笔记(六)红外图像伪彩色编码
数据分析入门 | kaggle泰坦尼克任务
图片随手机水平移动-陀螺仪。360度设置条件
Uninstall Meizu app store
Parallelism, concurrency and several directions for high concurrency optimization
.net operation redis hash object
mysql 进不去了怎么办
datav漂亮数据屏制作体验
码云,正式支持 Pages 功能,可以部署静态页面
英语基础句型结构------起源
链式方法调用的事务问题剖析
Inheritance method of simplified constructor (I) - combined inheritance
记给esp8266烧录刷固件
反射机制简述
[C language] named type and anonymous type