C语言语句、语句分类及注释

文章目录

  • 一、语句和语句分类
  • 二、注释
    • 🍕注释是什么?为什么写注释?
    • 1. /**/的形式
    • 2. //的形式
    • 3. 注释会被替换
  • 三、随机数的生成
    • 1.rand函数
    • 2.srand函数
    • 3.time函数
    • 4.设置随机数的范围
  • 四、C99中的变长数组
  • 五、问题表达式解析
    • 表达式1
    • 表达式2
    • 表达式3
    • 表达式4
    • 表达式5
  • 六、位段补充

一、语句和语句分类

C语言的代码是由一条一条的语句构成的,C语言中的语句可为以下五类:
🍑空语句
🍑表达式语句
🍑函数调用语句
🍑复合语句
🍑控制语句

(1) 空语句
空语句是最简单的语句,一个分号就是一条语句,即空语句。

#include<stdio.h>
int main()
{;//空语句return 0;
}

空语句一般出现的地方是:这里需要一条语句但是这条语句不需要做任何事,就可以写一个空语句

(2) 表达式语句
表达式语句就是在表达式的后边加上分号。如下所示:

#include<stdio.h>
int main()
{int a = 20;int b = 0;b = a + 5; //表达式语句return 0;
}

(3) 函数调用语句
函数调用的时候,也会加上分号,就是函数调用语句。

#include<stdio.h>
int Add(int x, int y)
{return x + y;
}
int main()
{printf("hehe\n");//函数调用语句int ret = Add(2, 3);//函数调用语句return 0;
}

(4) 复合语句
成对括号中的代码就构成一个代码块,也被称为复合语句

#include<stdio.h>
void print(int arr[], int sz) //函数的大括号中的代码也构成复合语句
{int i = 0;for (i = 0; i < sz; i++){printf("%d ", arr[i]);}
}
int main()
{int i = 0;int arr[10] = { 0 };for (i = 0; i < 10; i++) //for循环的循环体的大括号中的就是复合语句{arr[i] = 10 - i;printf("%d\n", arr[i]);}return 0;
}

(5) 控制语句
控制语句用于控制程序的执行流程,以实现程序的各种结构方式(C语言支持三种结构:顺序结构、选择结构、循环结构),它们由特定的语句定义符组成,C语言有九种控制语句。可分成以下三类:
🍊1.条件判断语句也叫分支语句:if语句、switch语句;
🍊2.循环执行语句:do while语句、while语句、for语句;
🍊3.转向语句:break语句、goto语句、continue语句、return语句。

二、注释

🍕注释是什么?为什么写注释?

注释是对代码的说明,编译器会忽略注释,也就是说,注释对实际代码没有影响。
注释是给程序员自己,或者其他程序员看的。
好的注释可以帮我们更好的理解代码,但是也不要过度注释,不要写没必要的注释。
当然不写注释可能会让后期阅读代码的人抓狂。

写注释一定程度上反应了程序员的素质,建议大家写必要的注释,在未来找工作的时候,写代码时留下必要的注释也会给面试官留下更好的印象。

C 语言的注释有两种表示方法。

1. /**/的形式

第一种写法是将注释放在 /*…*/ 之间,内部可以分行
形式1:

/* 注释 */

🏐形式2:

/*
这是一行注释
*/

这种注释可以插在一行内部。

int fopen(char* s /* file name */, int mode);

上面示例中,/*file name*/ 用来对函数参数进行说明,跟在它后面的代码依然会有效执行。这种注释一定不能忘记写结束符号*/,否则很容易导致错误。

例如:
在这里插入图片描述上面示例的原意是,第五行和第七行代码的尾部,有两个注释。但是,第一行注释忘记写结束符号*/,导致注释一延续到第三行才结束。

🍏🍏 /**/ 这种注释不支持嵌套注释,从/*开始注释后,遇到第一个 */就认为注释结束了
在这里插入图片描述

2. //的形式

第二种写法是将注释放在双斜杠//后面从双斜杠到行尾都属于注释。这种注释只能是单行,可以放在行首,也可以放在一行语句的结尾。这是C99标准新增的语法。
🍆形式1:

//这是一行注释

🌽形式2:

int x = 1; //这也是注释

不管是哪一种注释,都不能放在双引号里面。放在双引号里面的注释符号,会成为字符串的一部分,会被解释成普通符号,失去注释作用。

#include<stdio.h>
int main()
{printf("//hello /* world */ ");return 0;
}

程序运行结果:
在这里插入图片描述上面示例中,双引号里面的注释符号,都会被视为普通字符,没有注释作用。

3. 注释会被替换

编译时,注释会被替换成一个空格,所以 min/*这里是注释*/Value 会变成 min Value ,而不是minValue 。

三、随机数的生成

1.rand函数

C语言提供了一个函数叫rand,这个函数是可以生成随机数的,函数原型如下所示:

int rand (void);

rand函数会返回一个伪随机数,这个随机数的范围是在0~RAND_MAX之间,这个RAND_MAX的大小是依赖编译器上实现的,但是大部分编译器上是32767。

rand函数的使用需要包含一个头文件是:stdlib.h
测试一下rand函数,这里多调用几次,产生5个随机数:

#include<stdio.h>
#include<stdlib.h>
int main()
{printf("%d\n", rand());printf("%d\n", rand());printf("%d\n", rand());printf("%d\n", rand());printf("%d\n", rand());return 0;
}

程序运行结果:
在这里插入图片描述我们先运行一次,看看结果,再运行一次再看看结果,多运行次呢?
在这里插入图片描述在这里插入图片描述可以看到虽然一次运行中产生的5个数字是相对随机的,但是下一次运行程序生成的结果和上一次一模一样,这就说明有点问题。

如果再深入了解一下,就不难发现,其实rand函数生成的随机数是伪随机的伪随机数不是真正的随机数,是通过某种算法生成的随机数。真正的随机数的是无法预测下一个值是多少的。而rand函数是对一个叫“种子”的基准值进行运算生成的随机数。之所以前面每次运行程序产生的随机数序列是一样的,那是因为rand函数生成随机数的默认种子是1。如果要生成不同的随机数,就要让种子是变化的。

2.srand函数

C语言中又提供了一个函数叫srand,是用来初始化随机数的生成器的,srand的原型如下:

void srand (unsigned int seed);

程序中在调用 rand 函数之前先调用 srand 函数,通过 srand 函数的参数seed来设置rand函数生成随机数的时候的种子,只要种子在变化,每次生成的随机数序列也就变化起来了。那也就是说给srand的种子是如果是随机的,rand就能生成随机数;在生成随机数的时候又需要一个随机数,这咋办呢?看下面:

3.time函数

在程序中我们一般是使用程序运行的时间作为种子的,因为时间是时刻在发生变化的。在C语言中有一个函数叫 time,就可以获得这个时间,time函数原型如下:

time_t time (time_t* timer);

🍇time 函数会返回当前的日历时间,其实返回的是1970年1月1日0时0分0秒到现在程序运行时间之间的差值,单位是。返回的类型是time_t类型的,time_t类型本质上其实就是32位或者64位的整型类型。
🍇time函数的参数 timer 如果是非NULL指针的话,函数也会将这个返回的差值放在timer指向的内存中带回去。
🍇如果 timer 是NULL,就只返回这个时间的差值。time函数返回的这个时间差也被叫做:时间戳。time函数的使用需要包含头文件:time.h

如果只是让time函数返回时间戳,我们就可以这样写:

time(NULL);//调用time函数返回时间戳,这里没有接收返回值

那我们就可以让生成随机数的代码改写成如下:

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int main()
{//使用time函数的返回值设置种⼦//因为srand的参数是unsigned int类型,我们将time函数的返回值强制类型转换srand((unsigned int)time(NULL));printf("%d\n", rand());printf("%d\n", rand());printf("%d\n", rand());printf("%d\n", rand());printf("%d\n", rand());return 0;
}

程序运行结果:
在这里插入图片描述在这里插入图片描述(注:截图只是当时程序运行的结果,你的运行结果不一定和这个一样)
srand函数是不需要频繁调用的,一次运行的程序中调用一次就够了。

4.设置随机数的范围

如果我们要生成0~99之间的随机数,方法如下:

rand() % 100 //余数的范围是0~99

如果要生成1~100之间的随机数,方法如下:

rand()%100+1 //%100得到的余数是在0~99之间(包括0和99),0~99的数字+1,范围是1~100

如果要生成100~200的随机数,方法如下:

100 + rand()%(200-100+1) //余数的范围是0~100,加100后就是100~200

所以如果要生成a~b的随机数,方法如下:

a + rand()%(b-a+1)

四、C99中的变长数组

在C99标准之前,C语言在创建数组的时候,数组大小的指定只能使用常量常量表达式,或者如果我们初始化数据的话,可以省略数组大小。

int arr1[10];
int arr2[3+5];
int arr3[ ] = {1,2,3,4,5};

省略数组大小这种情况,虽然[ ]中没指定元素个数,但是编译器会根据你后面初始化元素的多少来确定数组的大小。

这样的语法限制,让我们创建数组就不够灵活,有时数组大了浪费空间,有时候数组又小了又不够用。
C99中给了一个变长数组(variable-length array,简称VLA)的新特性,允许我们可以使用变量指定数组的大小。

int n = a+b;
int arr[n];

上面示例中,数组 arr 就是变长数组,因为它的长度取决于变量n的值,编译器没法事先确定,只有运行时才能知道 n 是多少。
变长数组的根本特征,就是数组长度只有运行时才能确定,所以变长数组不能初始化。它的好处是程序员不必在开发时,随意为数组指定一个估计的长度,程序可以在运行时为数组分配精确的长度。有一个比较迷惑的点,变长数组的意思是数组的大小是可以使用变量来指定的,在程序运行的时候,根据变量的大小来指定数组的元素个数,而不是说数组的大小是可变的。数组的大小一旦确定就不能再变化了。

遗憾的是在VS2022上,虽然支持大部分C99的语法,但没有支持C99中的变长数组的语法,没法测试;但可以在gcc编译器上测试下面的代码:

#include <stdio.h>
int main()
{int n = 0;scanf("%d", &n);//根据输入的数值确定数组的大小int arr[n];int i = 0;for (i = 0; i < n; i++){scanf("%d", &arr[i]);}for (i = 0; i < n; i++){printf("%d ", arr[i]);}return 0;
}

五、问题表达式解析

表达式1

我们都知道,通过运算符优先级可以知道一个表达式优先级高的部分要比优先级低的先执行。但不能知道有相同优先级的几个部分会不会同时执行,还是又先后顺序?比如:

//表达式的求值部分由操作符的优先级决定。
//表达式1:
a*b + c*d + e*f

表达式1在计算的时候,由于*比+的优先级高,只能保证,*的计算比+的早,但是优先级并不能决定第三个 * 比第一个 + 早执行。
所以表达式的计算机顺序就可能是:

1 a*b
2 c*d
3 a*b + c*d
4 e*f
5 a*b + c*d + e*f

或者

a*b
c*d
e*f
a*b + c*d
a*b + c*d + e*f

表达式2

//表达式2
c + --c;

同上,操作符的优先级只能决定自减 – 的运算在 + 运算的前面,但是我们并没有办法得知,+ 操作符的左操作数的获取(使用)在右操作数之前还是之后求值,所以结果是不可预测的,是有歧义的。

表达式3

#include<stdio.h>
//表达式3
int main()
{int i = 10;i = i-- - --i * (i = -3) * i++ + ++i;printf("i = %d\n", i);return 0;
}

表达式3在不同编译器中的测试结果:(非法表达式程序的结果)
在这里插入图片描述上面的表达式在VS2022中的运行结果为:
在这里插入图片描述

表达式4

#include<stdio.h>
int fun()
{static int count = 1;return ++count;
}
int main()
{int answer;answer = fun() - fun() * fun();printf("%d\n", answer);//输出多少?return 0;
}

程序运行结果:

在这里插入图片描述虽然在大多数的编译器上求得的结果都是相同的。
但是上述代码 answer = fun() - fun() * fun();中我们只能通过操作符的优先级得知:先算乘法,再算减法。
但函数的调用先后顺序却无法通过操作符的优先级确定。

表达式5

#include <stdio.h>
int main()
{int i = 1;int ret = (++i) + (++i) + (++i);printf("%d\n", ret);printf("%d\n", i);return 0;
}

VS2022的运行结果:
在这里插入图片描述但如果你在gcc中运行上面的代码得到的结果就和上面的结果有差异。
看看同样的代码产生了不同的结果,这是为什么?简单看一下汇编代码,就可以分析清楚
这段代码中的第一个 + 在执行的时候,第三个++是否执行,这个是不确定的,因为依靠操作符的优先级和结合性是无法决定第一个+和第三个前置 ++ 的先后顺序的。

总结:
即使有了操作符的优先级和结合性,我们写出的表达式依然有可能不能通过操作符的属性唯一确定表达式的计算路径,那这个表达式就是存在潜在风险的,建议大家不要写出特别复杂的表达式。

六、位段补充

在位段中,位段的成员必须是int、unsigned int或者signed int(包括char类型, char也属于整型家族)。上面的意思是如果使用位段,那这个结构体中的成员一般是同类型的。比如:

struct S
{int _a : 2;int _b : 5;int _c : 10;int _d : 30;
};
struct S
{char _a : 3;char _b : 4;char _c : 5;char _d : 4;
};

特别是位段成员如果出现在表达式中,则会进行整型提升,自动转换为int类型或者unsigned int类型。

在C语言中,位段是用来节省内存空间的。内存分配是遵循以下规则的:
🏉1.成员大小限制:位段中的成员大小不能超过机器定义的类型大小。例如,int类型在大多数平台上是32位,因此位段中的成员大小(bit位数)不能超过32位。
🏉2.内存对齐:位段的内存对齐是基于其中成员的最大类型来确定的。如果一个位段中包含多个成员,且这些成员的类型大小不同,则内存对齐将基于最大的成员类型
🏉3.内存分配:位段通常不直接分配内存,而是作为结构体的一部分。结构体在内存中的分配遵循常规的内存分配规则,即通过 malloc 函数分配内存,并由程序员使用free函数释放内存。

位段中是可以有不同的类型成员的,但如果位段的成员有不同类型的话,那位段大小的计算就比较复杂。建议位段成员都以相同类型出现(只要是整型家族即可)。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/55619.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

redis中的数据类型(Set与ZSet)

&#xff08;一&#xff09;set set在我们目前有两个意思&#xff0c;首先就是这里使用的集合&#xff0c;第二个是我们的set和get方法 因为set是一个集合&#xff0c;所以他具有集合的一些特点&#xff1a; 1.集合中的元素无序 2.集合中的元素是不可重复的 3.集合间是可…

2.点位管理开发(续)及设计思路——帝可得后台管理系统

目录 前言一、页面原型二、修改1、页面展示2、新增 3 、总结思路 前言 提示&#xff1a;本篇继续点位管理的改造 一、页面原型 页面展示新增 二、修改 1、页面展示 页面修改&#xff1a;修改标签换行、顺序顺序、地址过长时换行问题&#xff1b; <el-table v-loading…

大厂笔试现已经禁用本地IDE怎么看

如果我说本来面试做题这种事情就是反人类你相信吗&#xff1f; 这个罪恶的源头就是 Google&#xff0c;说是为了选择高素质的计算机编程水平的人才&#xff0c;然后把面试就变成了考试&#xff0c;最大的受益者当然是印度人了。 当把一个考察过程变成标准化的考试过程&#x…

电脑失声,一招搞定

早已习惯了Edge浏览器的“大声朗读”功能&#xff0c;今天值班&#xff0c;值班室用的两台电脑只配有耳机&#xff0c;没有音箱&#xff0c;顿时感觉不适。 先找了一个带功放的老音箱&#xff0c;发现少了电箱到功放的音频线。 一顿搜索&#xff0c;在找到音频线的同时&#…

【案例】平面云

教程案例视频&#xff1a;Unity Shader Graph - 云教程 开发平台&#xff1a;Unity 2022 开发工具&#xff1a;Unity ShaderGraph   一、效果展示 二、ShaderGraph 路线图 三、案例分析 核心思路&#xff1a;使用 Noise&#xff08;噪声&#xff09;模拟云层状态   3.1 说明…

Chat登录时出现SSO信息出错的解决方法

目录 1. 问题所示2. 问题所示3. 解决方法 1. 问题所示 此贴主要是总结回顾&#xff0c;对此放置在运维专栏 出现如下问题&#xff0c;很懵&#xff0c;以为是节点挂了还是网址蹦了 一直刷新&#xff0c;登录之后就出现这个问题 2. 问题所示 对于SSO&#xff0c;也就是单点登…

负载均衡--相关面试题(六)

在负载均衡的面试中&#xff0c;可能会遇到一系列涉及概念、原理、实践应用以及技术细节的问题。以下是一些常见的负载均衡面试题及其详细解答&#xff1a; 一、什么是负载均衡&#xff1f; 回答&#xff1a;负载均衡是一种将网络请求或数据传输工作分配给多个服务器或网络资源…

详解JavaScript函数属性、方法和构造函数

函数属性、方法和构造函数 JS中&#xff0c;函数是值&#xff0c;对函数执行typeof运算会返回function&#xff0c;但是函数是JS中特殊的对象&#xff0c;也可以拥有属性和方法。 length属性 函数体里面&#xff0c;arguments.length表示传入函数的实参个数&#xff0c;而函…

2024年优化苹果免签封装APP H5站打包苹果APP 绿标-永不掉千(永久使用)

大家都知道苹果手机做APP签名很贵&#xff0c; 这个程序就是吧您的H5网站 一切网页可以打开的&#xff0c;封装成app 苹果手机上可以直接安装使用 永久可用&#xff01;&#xff01;很简单&#xff0c;可以看视频教程来安装使用&#xff0c; 视频教程&#xff1a; https://ww…

修改Anaconda虚拟环境默认安装路径(Linux系统)

文章目录 修改Anaconda虚拟环境默认安装路径(Linux系统)1.方法一&#xff1a;使用--prefix参数2.方法二&#xff1a;配置conda环境的默认安装位置 修改Anaconda虚拟环境默认安装路径(Linux系统) 1.方法一&#xff1a;使用--prefix参数 在创建虚拟环境时&#xff0c;使用--pre…

macOS编译和运行prometheus2.54

欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码)&#xff1a;https://github.com/zq2599/blog_demos 本篇概览 本文详述了在macOS(M2芯片)上编译和运行prometheus2.54版本的过程&#xff0c;以及安装node_exporter和grafana并使用prometheus指标进行展示 本地…

openpnp - 底部相机高级校正的参数设置

文章目录 openpnp - 底部相机高级校正的参数设置概述笔记修改 “Radial Lines Per Calibration Z” 的方法不同 “Radial Lines Per Calibration Z”的校验结果不同 “Radial Lines Per Calibration Z”的设备校验动作的比较总结备注END openpnp - 底部相机高级校正的参数设置 …

根据给定的相机和镜头参数,估算相机的内参。

1. 相机分辨率和传感器尺寸 最高分辨率&#xff1a;6000 4000 像素传感器尺寸&#xff1a;22.3 mm 14.9 mm 2. 计算像素大小 需要计算每个像素对应的实际尺寸&#xff08;mm/pixel&#xff09;&#xff1a; 水平方向像素大小&#xff1a; 垂直方向像素大小&#xff1a; …

国外电商系统开发-运维系统批量添加服务器

您可以把您准备的txt文件&#xff0c;安装要求的格式&#xff0c;复制粘贴到里面就可以了。注意格式&#xff01; 如果是“#” 开头的&#xff0c;则表示注释&#xff01;

在掌控板中加载人教版信息科技教学指南中的educore库

掌控板中加载educore库 人教信息科技数字资源平台&#xff08;https://ebook.mypep.cn/free&#xff09;中的《信息科技教学指南硬件编程代码说明》文件中提到“本程序说明主要供教学参考。需要可编程主控板须支持运行MicroPython 脚本程序。希望有更多的主控板在固件中支持ed…

(JAVA)浅尝关于 “栈” 数据结构

1. 栈的概述&#xff1a; 1.1 生活中的栈 存储货物或供旅客住宿的地方&#xff0c;可引申为仓库、中转站。例如酒店&#xff0c;在古时候叫客栈&#xff0c;是供旅客休息的地方&#xff0c;旅客可以进客栈休息&#xff0c;休息完毕后就离开客栈 1.2计算机中的栈 将生活中的…

有些硬盘录像机接入视频汇聚平台EasyCVR后通道不显示/显示不全,该如何处理?

EasyCVR视频监控汇聚管理平台是一款针对大中型项目设计的跨区域网络化视频监控集中管理平台。该平台不仅具备视频资源管理、设备管理、用户管理、运维管理和安全管理等功能&#xff0c;还支持多种主流标准协议&#xff0c;如GB28181、RTSP/Onvif、RTMP、部标JT808、GA/T 1400协…

Pikachu-Sql Inject-数字型注入(GET)

一、、破解 SQL 查询语句中的字段数 ?id1 order by 3 -- // -- 是注释&#xff0c; 加号 在MySQL中会转成空格 order by 1 &#xff0c;by 数字几&#xff0c;就是按照第几列进行排序&#xff1b;如果没有这一行&#xff0c;则报错 如&#xff1a;以下语句&#xff0c;根据…

RabbitMQ(死信队列)

一、本文抒写背景 前面我也在延迟队列篇章提到过死信队列&#xff0c;也提到过一些应用场景&#xff01; 今天呢&#xff0c;这篇文章&#xff0c;主要就是实战一个业务场景的小Demo流程&#xff0c;哈哈&#xff0c;那就是延迟关闭订单。 二、开始啦&#xff01;letgo! 首…

Qt系统学习篇(6)-QMainWindow

QMainWindow是一个为用户提供主窗口程序的类&#xff0c;包含一个菜单栏(menu bar)、多个工具栏(tool bars)、多个锚接部件(dock widgets)、一个状态栏(status bar)及一个中心部件(central widget)&#xff0c;是许多应用程序的基础&#xff0c;如文本编辑器&#xff0c;图片编…