C语言进阶——一文带你深度了解“C语言关键字”(中篇6)

 

本篇文章记录我学习C语言进阶知识——C语言关键字,旨在记录分享,希望我的分享能带给你不一样的收获!

目录

一、return关键字

二、const 关键字也许该被替换为 readolny

(一)、 const 修饰的只读变量

(二)、 节省空间,避免不必要的内存分配,同时提高效率

(三)、修饰一般变量 

(四)、修饰数组

(五)、修饰指针 

 (六)、修饰函数参数

(七)、修饰函数的返回值 

三、结语 

一、return关键字

刚开始学习C语言的时候,大家因该知道return关键字最重要的作用就是:终止一个函数并返回其后面跟着的值。

return (Val); //此括号可以省略。但一般不省略,尤其在返回一个表达式的值时。
return 可以返回些什么东西呢?看下面例子:
char * Func(void)
{
        char str[30];
        …
        return str;
}
str 属于局部变量,位于栈内存中,在 Func 结束的时候被释放,所以返回 str 将导致错误。


既然如此,那我们就深度来探讨一下C语言return 关键字的一些使用规则。

【规则1】return语句不可以返回指向“栈内存”的“指针”,因为该内存在函数体结束时会被自动销毁。

这里大家再来探讨一个问题:

return ;
这个语句有问题吗?如果没有问题,那返回的是什么?

  • void 函数中的 return;

如果函数的返回类型是 void,那么 return; 用于结束函数的执行。

例子:
void myFunction()

{

   ……// 执行一些操作

   return; // 结束函数,不返回任何值

}

  • void 函数中的 return;

对于返回类型不是 void 的函数(如 intfloat 等),使用 return; 是不合法的,因为这些函数需要返回一个值。

如果试图在这样的函数中使用 return;,编译器会报错。

int myFunction()

{

        …… // 执行一些操作

        return; // 错误,缺少返回值

}

二、const 关键字也许该被替换为 readolny

const 是 constant 的缩写,是恒定不变的意思,也翻译为常量、常数等。很不幸,正是因为这一点,很多人都认为被 const 修饰的值是常量。这是不精确的,精确的说应该是只读的变量,其值在编译时不能被使用,因为编译器在编译时不知道其存储的内容。或许当初这个关键字应该被替换为 readonly。那么这个关键字有什么用处和意义呢?


const 推出的初始目的,正是为了取代预编译指令,消除它的缺点,同时继承它的优点。
我们看看它与 define 宏的区别。 (很多人误以为 define 是关键字,在这里我提醒你再回到本章前面看看 32 个关键字里是否有 define)。

(一)、 const 修饰的只读变量

定义 const 只读变量,具有不可变性。
例如:
const int Max=100;
int Array[Max];
这里请在 Visual C++6.0 里分别创建.c 文件和.cpp 文件测试一下。你会发现在.c 文件中,编译器会提示出错,而在.cpp 文件中则顺利运行。为什么呢?我们知道定义一个数组必须指定其元素的个数。这也从侧面证实在 C 语言中, const 修饰的 Max 仍然是变量,只不过是只读属性罢了;而在 C++里,扩展了 const 的含义,这里就不讨论了。


注意: const 修饰的只读变量必须在定义的同时初始化,想想为什么?
留一个问题: case 语句后面是否可以是 const 修饰的只读变量呢?请动手测试一下。

【答案】 

const 修饰的只读变量必须在定义时初始化,因为它的值在初始化之后不能被修改。这样做有几个原因:

  1. 确保值不变const 变量在定义时必须初始化,这样编译器能够知道其初始值,并确保在整个程序的生命周期中不会被修改。如果没有初始值,编译器无法保证变量的不可变性。

  2. 内存管理在编译时,const 变量的值可以被直接嵌入到代码中或放置在只读存储区。如果没有初始化,编译器无法为其分配适当的存储位置或内存,导致无法确保变量值的不可变性。

  3. 程序正确性在程序运行时,const 变量的不可变性是通过初始化保证的。如果没有初始化,可能会出现未定义行为或程序错误,因为变量的值可能未被设定或被错误地修改。

在 C 和 C++ 中,case 语句后面通常需要是编译时常量(即常量表达式),而 const 修饰的只读变量可以用作 case 标签,但有一些细节需要注意:

1. 编译时常量要求

  • 在 switch 语句的 case 标签中,必须使用编译时常量。编译时常量是指在编译时已知的常量值。这意味着 case 标签的值必须在编译时确定。

2. const 变量的使用

  • const 修饰的变量的值在程序运行时是不可修改的,但是编译器在编译阶段需要知道其具体值。只要 const 变量是在编译时能够确定其值的常量,编译器就可以接受它作为 case 标签。

const int VALUE = 5;

switch (x) {
    case VALUE:
        // 执行相关代码
        break;
    // 其他 case 标签
}
在这种情况下,如果 VALUE 在编译时是一个已知的常量值(例如常量表达式),那么它是可以作为 case 标签的。

需要注意的点

  1. const 变量初始化const 变量必须在定义时初始化,并且初始化值必须是编译时常量。

  2. 编译器支持:某些编译器可能会对 const 变量的支持有所不同,但在标准的 C 和 C++ 中,const 变量在符合编译时常量的条件下通常是可以用于 case 标签的。

  3. 避免未定义行为:确保 const 变量在编译时能够确定其值,避免使用运行时值或非编译时常量,否则会导致编译错误或未定义行为。

(二)、 节省空间,避免不必要的内存分配,同时提高效率

编译器通常不为普通 const 只读变量分配存储空间,而是将它们保存在符号表中,这使
得它成为一个编译期间的值,没有了存储与读内存的操作,使得它的效率也很高。

例如:

#define M 3
const int N=5;
......
int i=N;
int I=M;
int j=N;
int J=M;

//宏常量
//此时并未将 N 放入内存中

//此时为 N 分配内存,以后不再分配!
//预编译期间进行宏替换,分配内存
//没有内存分配
//再进行宏替换,又一次分配内存!

const 定义的只读变量从汇编的角度来看, 只是给出了对应的内存地址, 而不是像#define
一样给出的是立即数,所以, const 定义的只读变量在程序运行过程中只有一份拷贝(因为
它是全局的只读变量,存放在静态区
),而#define 定义的宏常量在内存中有若干个拷贝。
#define 宏是在预编译阶段进行替换,而 const 修饰的只读变量是在编译的时候确定其值。
#define 宏没有类型,而 const 修饰的只读变量具有特定的类型。

(三)、修饰一般变量 

一般常量是指简单类型的只读变量。这种只读变量在定义时,修饰符 const 可以用在类型说明符前,也可以用在类型说明符后。例如:
int const i=2; 或 const int i=2;

(四)、修饰数组

定义或说明一个只读数组可采用如下格式:
int const a[5]={1, 2, 3, 4, 5};或
const int a[5]={1, 2, 3, 4, 5};

(五)、修饰指针 

const int *p;
int const *p;
int *const p;

const int *const p;

// p 可变, p 指向的对象不可变
// p 可变, p 指向的对象不可变
// p 不可变, p 指向的对象可变

//指针 p 和 p 指向的对象都不可变


这里给出一个记忆和理解的方法:
先忽略类型名(编译器解析的时候也是忽略类型名),我们看 const 离哪个近。 “近水楼
台先得月”,离谁近就修饰谁。

const int *p;
int const *p;
int *const p;

const int *const p;

//const 修饰*p,p 是指针, *p 是指针指向的对象,不可变
//const 修饰*p,p 是指针, *p 是指针指向的对象,不可变
//const 修饰 p, p 不可变, p 指向的对象可变

//前一个 const 修饰*p,后一个 const 修饰 p,指针 p 和 p 指向的对象都不可变

 (六)、修饰函数参数

const 修饰符也可以修饰函数的参数,当不希望这个参数值被函数体内意外改变时使用。例如:
void Fun(const int i);
告诉编译器 i 在函数体中的不能改变, 从而防止了使用者的一些无意的或错误的修改。

(七)、修饰函数的返回值 

const 修饰符也可以修饰函数的返回值,返回值不可被改变。例如:
const int Fun (void);
在另一连接文件中引用 const 只读变量:
extern const int i; //正确的声明
extern const int j=10; //错误!只读变量的值不能改变
注意这里是声明不是定义,关于声明和定义的区别,请看关于关键字的第一篇文章。
讲了这么多讲完了吗?远没有。在 C++里,对 const 做了进一步的扩展,还有很多知识未能
讲完。有兴趣的话,不妨查找相关资料研究研究。

三、结语 

关于本次C语言关键字的进阶知识就分享到此了,“学如逆水行舟,不进则退”,愿我们一起努力,逐梦不止,砥砺前行!

 

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

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

相关文章

腾讯云COS和阿里云OSS在Springboot中的使用

引言:之前本来是用OSS做存储的,但是上线小程序发现OSS貌似消费比COS多一些,所以之前做了技术搬迁,最近想起,打算做个笔记记录一下,这里省去在阿里云注册OSS或腾讯云中注册COS应用了。 一、OSS 1、配置yml …

C ++ 也可以搭建Web?高性能的 C++ Web 开发框架 CPPCMS + MySQL 实现快速入门案例

什么是CPPCMS? CppCMS 是一个高性能的 C Web 开发框架,专为构建快速、动态的网页应用而设计,特别适合高并发和低延迟的场景。其设计理念类似于 Python 的 Django 或 Ruby on Rails,但针对 C 提供了更细粒度的控制和更高效的性能。…

Golang | Leetcode Golang题解之第330题按要求补齐数组

题目&#xff1a; 题解&#xff1a; func minPatches(nums []int, n int) (patches int) {for i, x : 0, 1; x < n; {if i < len(nums) && nums[i] < x {x nums[i]i} else {x * 2patches}}return }

【Python学习手册(第四版)】学习笔记19-函数的高级话题

个人总结难免疏漏&#xff0c;请多包涵。更多内容请查看原文。本文以及学习笔记系列仅用于个人学习、研究交流。 本文主要介绍函数相关的高级概念&#xff1a;递归函数、函数注解、lambda表达式函数&#xff0c;常用函数工具如map、filter、reduce&#xff0c;以及通用的函数设…

【超音速 专利 CN117576413A】种锂电池测试数据绑定方法、设备及存储介质

申请号CN202010618671.X公开号&#xff08;公开&#xff09;CN111967546A申请日2020.11.20申请人&#xff08;公开&#xff09;广州超音速自动化科技股份有限公司(833753)发明人&#xff08;公开&#xff09;张俊峰(总&#xff09;; 叶长春(总&#xff09;; 蓝明观 术语 治具…

【MySQL】数据库约束和多表查询

目录 1.前言 2.数据库约束 2.1约束类型 2.2 NULL约束 2.3 NUIQUE&#xff1a;唯一约束 2.4 DEFAULT&#xff1a;默认值约束 2.5 PRIMARY KEY&#xff1a;主键约束 2.6 FOREIGN KEY&#xff1a;外键约束 1.7 CHECK约束 3.表的设计 3.1一对一 3.2一对多 3.3多对多 …

vue3-02-vue3中的组件通信

目录 组件通信一、vue3组件通信和vue2的区别二、父子通信2.1 props通信1&#xff09;父→子传递数据&#xff08;父组件向子组件传递数据&#xff09;2&#xff09;子→父传递数据 2.2 v-model1&#xff09;v-model的本质2&#xff09;给modelValue起别名3&#xff09;$event 2…

用Python制作开心消消乐游戏|附源码

制作一个完整的“开心消消乐”风格的游戏在Python中是一个相对复杂的项目&#xff0c;因为它涉及到图形界面、游戏逻辑、动画效果以及用户交互等多个方面。不过&#xff0c;我可以为你提供一个简化的版本和概念框架&#xff0c;帮助你理解如何开始这个项目&#xff0c;并提供一…

英伟达元宇宙平台Omniverse的学习,技术调研

NVIDIA Omniverse™ 是一个基于 USD (Universal Scene Description) 的可扩展平台&#xff0c;可使个人和团队更快地构建自定义 3D 工作流并模拟大型虚拟世界。 Omniverse&#xff1a;三维设计协同、模拟的开发平台&#xff0c;实现3D实时渲染&#xff0c;RTX光线追踪技术 协…

职场英语培训柯桥外语学校学外语学英语到银泰泓畅学校

“工作量太大了”怎么说&#xff1f; 导致加班有一个非常大的因素就是&#xff1a; “工作量太大了&#xff01;” “ 注意&#xff1a;形容工作量太大不使用“big”一词&#xff0c;要用heavy&#xff0c;相应的要说工作量较小&#xff0c;可以用light. 工作量大/小 &…

数据中心互连的关键要素和核心技术

数据中心互连&#xff08;DCI&#xff09;依靠其关键要素和核心技术进行的高效、可靠和高速的连接&#xff0c;实现了数据中心跨区域连接的即时通信和数据交换&#xff0c;成为了现代数字通信基础设施的重要组成部分。从光模块和多路复用设备到网络协议和管理系统&#xff0c;D…

Leetcode75-5 反转字符串的元音字母

本质上来说就是反转字符串 一部分需要反转 一部分不动 思路: 1.用String字符串倒序拼接 就是过滤掉不是元音字符 然后把所有的字符&#xff08;非元音的直接复制过来 元音字母直接从反转的字符串里边复制即可&#xff09; 2.看了题解发现自己写的啰嗦了 就是一个双指针问题用…

酒店行业如何利用XML进行营销短信

随着信息社会的到来&#xff0c;消费者获得会所的服务也从单纯的电话方式&#xff0c;逐渐转变为电话、互联网、传真&#xff0c;群发短信等多种媒体并行的方式。今天着重介绍下酒店行业如何利用短信平台进行营销。 群发短信业务对酒店起到的效率&#xff1a;根据新产品或服务向…

java实现解析pdf格式发票

为了减少用户工作量及误操作的可能性&#xff0c;需要实现用户上传PDF格式的发票&#xff0c;系统通过解析PDF文件获取发票内容&#xff0c;并直接将其写入表单。以下文章记录了功能实现的代码。 发票样式 发票内容解析 引用Maven 使用pdfbox <dependency><groupI…

Spring Boot - 在Spring Boot中实现灵活的API版本控制(下)_ 封装场景启动器Starter

文章目录 Pre设计思路ApiVersion 功能特性使用示例配置示例 ProjectStarter Code自定义注解 ApiVersion配置属性类用于管理API版本自动配置基于Spring MVC的API版本控制实现WebMvcRegistrations接口&#xff0c;用于自定义WebMvc的注册逻辑扩展RequestMappingHandlerMapping的类…

前端CSS画图形

我以前一直很好奇&#xff0c;这些下拉菜单中的小箭头是怎么实现的&#xff0c;直到我看到了进阶的CSS。 OK&#xff0c;let me tell you hao to do. 想要实现这个效果&#xff0c;方法很多&#xff0c;我知道的就两个&#xff1a; 图片作弊法&#xff0c;CSS妙用法 图片作弊…

uni-app 开发App时调用uni-push 实现在线系统消息推送通知 保姆教程

一、引言 在开发App时避免不了需要推送系统通知&#xff0c;以提高用户的使用体验。在自己的一个工具型的小app上全流程接入了uni-push2.0的推送能力&#xff0c;做个记录&#xff0c;以防后期需要用到。在阅读本教程前最好先看看官方文档&#xff0c;结合官方文档使用&#xf…

下载免费设计素材,有这7个网站就够了

7个免费设计素材网站&#xff0c;这些网站提供了大量的免费资源&#xff0c;包括图片、字体、图标、模板等&#xff0c;涵盖了多种风格和主题&#xff0c;能够满足不同设计师和创作者的需求。无论是用于个人项目还是商业用途&#xff0c;这些网站都能给你提供丰富的选择&#x…

10步搞定Python爬虫从零到精通!

学习Python网络爬虫可以分为以下几个步骤&#xff0c;每一步都包括必要的细节和示例代码&#xff0c;以帮助你从零开始掌握这一技能。 第一步&#xff1a;理解网络爬虫基础 什么是网络爬虫&#xff1f; 网络爬虫是一种自动化程序,用来从互联网上收集数据.它通过发送 HTTP 请求…

【数据结构】五、树:7.哈夫曼树、哈夫曼编码

3.哈夫曼树和哈夫曼编码 文章目录 3.哈夫曼树和哈夫曼编码3.1带权路径长度3.2哈夫曼树的定义和原理3.3哈夫曼树的构造代码实现 3.4特点3.5哈夫曼编码压缩比代码实现 3.6哈夫曼树-C 3.1带权路径长度 #mermaid-svg-yeVKyVnDwvdIc5ML {font-family:"trebuchet ms",verda…