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.rhkb.cn/news/437526.html

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

相关文章

手机实时提取SIM卡打电话的信令声音-(题外、插播一条广告)

手机实时提取SIM卡打电话的信令声音-(题外、插播一条广告) 前言 在去年的差不多这个时候&#xff0c;我们做了一遍外置配件的选型&#xff0c;筛选过滤了一批USB蓝牙配件和type-c转usb的模块。详情可参考《外置配件的电商价格和下载链接的选型.docx》一文&#xff1a;蓝牙电话…

FireRedTTS - 小红书最新开源AI语音克隆合成系统 免训练一键音频克隆 本地一键整合包下载

小红书技术团队FireRed最近推出了一款名为FireRedTTS的先进语音合成系统&#xff0c;该系统能够基于少量参考音频快速模仿任意音色和说话风格&#xff0c;实现独特的音频内容创造。 FireRedTTS 只需要给定文本和几秒钟参考音频&#xff0c;无需训练&#xff0c;就可模仿任意音色…

Python基础语句教学

Python是一种高级的编程语言&#xff0c;由Guido van Rossum于1991年创建。它以简单易读的语法和强大的功能而闻名&#xff0c;被广泛用于科学计算、Web开发、数据分析等领域。 Python的应用领域广泛&#xff0c;可以用于开发桌面应用程序、Web应用、游戏、数据分析、人工智能等…

基于SSM的列车订票管理系统(含源码+sql+视频导入教程+文档+PPT)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1 、功能描述 基于SSM的列车订票管理系统3拥有两种角色&#xff1b;管理员、用户 管理员&#xff1a;用户管理、车票管理、购票指南管理、系统管理等 用户&#xff1a;发布帖子、登录注册、购票等 1.…

C++继承与菱形继承(一文了解全部继承相关基础知识和面试点!)

目的减少重复代码冗余 Class 子类(派生类) &#xff1a; 继承方式 父类&#xff08;基类&#xff09; 继承方式共有三种&#xff1a;公共、保护、私有 父类的私有成员private无论哪种继承方式都不可以被子类使用 保护protected权限的内容在类内是可以访问&#xff0c;但是在…

Python | Leetcode Python题解之第452题用最少数量的箭引爆气球

题目&#xff1a; 题解&#xff1a; class Solution:def findMinArrowShots(self, points: List[List[int]]) -> int:if not points:return 0points.sort(keylambda balloon: balloon[1])pos points[0][1]ans 1for balloon in points:if balloon[0] > pos:pos balloo…

ubuntu18.04安装教程

window分区 制作启动盘 插入 按F12进入启动选项页面&#xff0c;选择usb启动 选择install ubuntu 进入安装页面 选择中文&#xff08;简体&#xff09; 键盘布局选择英语&#xff08;美国&#xff09; 选择正常安装 等一小会儿 选择其他选项 分区 包括500mb系统分区 1000…

通信工程师笔记

第一章 1.支撑网是使业务网正常运行,增强网络功能,提供全网服务质量以满足用户要求的网络。 2.常见的有线通信线路包括&#xff08;1&#xff09;双绞线&#xff0c;&#xff08;2&#xff09;同轴电缆&#xff0c;&#xff08;3&#xff09;光纤等&#xff0c;无线通信线路是…

鼓组编曲:鼓编写技巧之进鼓加花编写

为了方便快速查阅和运用一些教程笔记&#xff0c;个人记性有时可能不是特别好&#xff0c;所以只能疯狂做笔记了&#xff0c;制作以下图文笔记&#xff0c;仅供参考…… 鼓组加花 鼓的变动 进鼓后然后就可以动次打次了 下面是2个底鼓的加花

北京市大兴区启动乐享生活 寻味大兴 美食嘉年华 系列促销费活动

北京市大兴区启动乐享生活 寻味大兴 系列促销费活动 区商务局副局长 兰莉 致开幕辞 区餐饮行业协会会长 董志明 介绍活动内容 2024年9月30日&#xff0c;由大兴区商务局主办、大兴区餐饮行业协会承办&#xff0c;并得到高米店街道和大兴绿地缤纷城大力支持的“乐享生活 寻味大…

we3.0里的钱包是什么?

we3.0里的钱包是什么&#xff1f; 在Web3.0的语境中&#xff0c;以太坊钱包是一种专为与以太坊区块链网络及其去中心化应用&#xff08;DApps&#xff09;交互而设计的数字钱包。这种钱包不仅支持用户存储、发送和接收以太币&#xff08;ETH&#xff09;&#xff0c;还允许用户…

(十七)、Mac 安装k8s

文章目录 1、Enable Kubernetes2、查看k8s运行状态3、启用 kubernetes-dashboard3.1、如果启动成功&#xff0c;可以在浏览器访问3.2、如果没有跳转&#xff0c;需要单独安装 kubernetes-dashboard3.2.1、方式一&#xff1a;一步到位3.2.2、方式二&#xff1a;逐步进行 1、Enab…

Java网络通信—TCP

1.客户端 2.服务端

系统安全 - Linux 安全模型及实践

文章目录 总览Linux安全Linux 安全模型用户层权限管理的细节多用户环境中的权限管理文件权限与目录权限 最小权限原则的应用Linux 系统中的认证、授权和审计机制认证机制授权机制审计机制 主机入侵检测系统&#xff08;HIDS&#xff09;_ Host-based Intrusion Detection Syste…

JavaWeb酒店管理系统(详细版)

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

MongoDB入门:安装及环境变量配置

一、安装MonggoDB Windows系统安装MongoDB 1、下载MongoDB安装包 访问MongoDB官方网站&#xff0c;选择与Windows系统相匹配的MongoDB Community Server版本进行下载。 Download MongoDB Community Server | MongoDB 2、安装MongoDB 双击下载好的安装包文件&#xff0c;根…

【数据结构】图论基础

文章目录 图的概念图的基本概念图的类型图的表示方法 图的相关基本概念1. 路径&#xff08;Path&#xff09;2. 连通性&#xff08;Connectivity&#xff09;3. 图的度&#xff08;Degree&#xff09;4. 子图&#xff08;Subgraph&#xff09;5. 生成树&#xff08;Spanning Tr…

docker pull 超时Timeout失败的解决办法

当国内开发者docker pull遇到如下提示时&#xff0c;不要惊讶 [rootvm /]# docker pull postgres Using default tag: latest Error response from daemon: Get "https://registry-1.docker.io/v2/": dial tcp 128.121.146.235:443: i/o timeout [rootvm /]# 自2024…

dcatadmin 自定义登录页面

一、问题&#xff1a; 在后台管理系统中&#xff0c;不同的项目想要不同的登录页面&#xff0c;但是框架自带的登录页面就只有一个。 解决&#xff1a; 由芒果系统改造的dcatadmin登录插件&#xff0c;实现一键安装改变登录页面。 项目介绍 基于Laravel和Vue的快速开发的后台管…

c++926

1.什么是虚函数&#xff1f;什么是纯虚函数&#xff1f; 虚函数&#xff1a;被virtual关键字修饰的成员函数&#xff0c;用于实现多态性&#xff0c;通过基类访问派生类的函数。纯虚函数&#xff1a;在虚函数后面添加0&#xff0c;只有声明而没有实现&#xff0c;需要派生类提…