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

news2024/12/23 4:01:01

文章目录

  • 一、语句和语句分类
  • 二、注释
    • 🍕注释是什么?为什么写注释?
    • 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.coloradmin.cn/o/2171876.html

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

相关文章

嵌入式的核心能力-Debug调试能力(一)

一、栈回溯 引入&#xff1a;调试程序时&#xff0c;经常会发生这类错误&#xff1a; 读写某个地址&#xff0c;程序报错&#xff1b;调用某个空函数&#xff0c;导致程序报错等等。 解决方法是&#xff0c;可以利用异常处理函数去打印出“发生错误瞬间”的所有寄存器地址 …

网络编程(1)——同步读写api

一、day1 学习了服务器和客户端socket的建立、监听以及连接。 &#xff08;1&#xff09;socket的监听和连接 服务端 1&#xff09;socket——创建socket对象。 2&#xff09;bind——绑定本机ipport。 3&#xff09;listen——监听来电&#xff0c;若在监听到来电&#x…

人脸遮挡检测系统源码分享

人脸遮挡检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Vis…

基于微信小程序的特色乡村综合展示平台设计与实现(源码+文档+讲解开发)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

C++入门基础知识89(实例)——实例14【创建各类三角形图案】

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///C爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于创建各类三角形图案的相关内容&#xff…

怎样用云手机进行TikTok矩阵运营?

在运营TikTok矩阵时&#xff0c;许多用户常常面临操作复杂、设备过多等问题。如果你也感到操作繁琐&#xff0c;不妨考虑使用云手机。云手机具备丰富的功能&#xff0c;能够帮助电商卖家快速打造高效的TikTok矩阵。接下来&#xff0c;我们将详细解析这些功能如何提升你的运营效…

每日论文6—16ISCAS一种新型低电流失配和变化电流转向电荷泵

《A Novel Current Steering Charge Pump with Low Current Mismatch and Variation》16ISCAS 本文首先介绍了传统的current steering charge pump&#xff0c;如下图&#xff1a; 比起最简单的电荷泵&#xff0c;主要好处是UP和DN开关离输出节点较远&#xff0c;因此一定程度…

vue.js 原生js app端实现图片旋转、放大、缩小、拖拽

效果图&#xff1a; 旋转 放大&#xff1a;手机上可以双指放大缩小 拖拽 代码实现&#xff1a; html <div id"home" class"" v-cloak><!-- 上面三个按钮 图片自己解决 --><div class"headImage" v-if"showBtn">&l…

python控制台是什么意思

Python 控制台是一种执行命令的快速方法&#xff0c;可以访问完整的Python API、查询命令历史记录和自动补全。命令提示符是 Python 3.x 的典型操作&#xff0c;加载解释器&#xff0c;并在提示符 >>> 处接受命令。 Python 控制台是内置的用于探索Blender 的可能性的…

滑动窗口算法专题(2)

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a; 优选算法专题 想要了解滑动窗口算法的介绍&#xff0c;可以去看下面的博客&#xff1a;滑动窗口算法的介绍 目录 904. 水果成篮 438. 找到…

JMeter向kafka发送数据

项目测试服务消费Kafka能力&#xff0c;需要消费特定格式的数据&#xff0c;因此要向Kafka中灌入数据&#xff0c;给老铁们分享下jmeter向kafka发送数据方法&#xff1a; 1. 首先在jmeter如下目录中导入一个kafka相关的jar包&#xff0c;如图&#xff1a; 2. 导入之后就可以打…

Spring Task快速入门

Spring Task介绍 Spring Task 是 Spring 框架提供的一种轻量级的定时任务解决方案&#xff0c;可以按照约定时间自动执行某个代码逻辑。它主要用于在 Spring 应用程序中执行定时任务&#xff0c;提供了一种声明式的方式来配置和执行这些任务。Spring Task 支持通过注解和配置文…

易燃气体检测系统源码分享

易燃气体检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Vis…

【抓包工具】如何下载抓包工具Fiddler

目录 Fiddler简介 Fiddler下载步骤 Fiddler安装步骤 配置Fiddler抓取HTTPS Fiddler简介 Fiddler是一个http协议调试代理工具&#xff0c;它能够记录并检查所有你的电脑和互联网之间的http通讯&#xff0c;设置断点&#xff0c;查看所有的“进出”Fiddler的数据&#xff08…

数据先行 -- Scale AI如何通过AI数据服务成为独角兽

数据引领未来 ©作者|格林&玄同 来源|神州问学 引言 近期&#xff0c;OpenAI发布的o1模型得到了广泛关注&#xff0c;该模型在多个推理能力上超过了人类博士水平。AI是否真的具有思考能力&#xff1f;为了追寻这一答案&#xff0c;技术专家们发出倡议&#xff0c;向人…

【Python】入门学习2:输入函数、输出函数、转义符

一、输入函数 # 普通用法&#xff1a;小括号里写提示语句&#xff0c;用引号包裹input("请输入&#xff1a;") # 控制台会显示“请输入&#xff1a;”&#xff0c;可以在后面输入内容# 变量接收&#xff1a;可以用变量进行接收a input("请输入&#xff1a;&q…

PSO粒子群代码手搓实现—代码详解版python

PSO粒子群算法手搓实现版&#x1f680; 读了博士之后&#xff0c;送算法方向转到了控制方向&#xff0c;然后最近接触到的项目&#xff0c;要用到粒子群算法&#xff0c;然后秉持着我自己一贯的把基础代码自己手写一遍的原则&#xff0c;我自己上网找了一些视频&#xff0c;然后…

通过反思性反馈增强和提升大模型

人工智能咨询培训老师叶梓 转载标明出处 尽管通过人类反馈的强化学习&#xff08;RLHF&#xff09;在使LLMs与人类偏好对齐方面展现出潜力&#xff0c;但这种方法往往只会导致表面的对齐&#xff0c;优先考虑风格上的变化而非提升LLMs在下游任务中的表现。而且偏好的不明确可能…

【漏洞复现】公交IC卡收单管理系统 SQL注入致RCE漏洞复现

》》》产品描述《《《 公交IC卡收单 管理系统Q是城市公共交通领域中不可或缺的一部分&#xff0c;它通过集成先进的集成电路技术(IC卡)实现了乘客便捷的支付方式&#xff0c;并有效提高了公共交通运营效率。系统集成了发卡、充值、消费、数据采集、查询和注销等多个功能模块&am…

走进上海郭培高定会馆:以冠珠华脉、华珍筑就至臻至性的艺术空间

“我热爱高级时装&#xff0c;因为她是一种生命的停驻。我希望我的高级时装成为馆藏级的精品&#xff0c;殿堂级的珍宝&#xff0c;成为传世杰作。” ——郭培 中国唯一一位法国高定公会受邀会员&#xff0c;曾荣登《TIME》时代周刊全球100位最具影响力人物榜单。纽约时报评价…