⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解

这篇具有很好参考价值的文章主要介绍了⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

 ⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划🔗 《C语言趣味教程》👈 猛戳订阅!!!


  • 💭 写在前面:这是一套 C 语言趣味教学专栏,目前正在火热连载中,欢迎猛戳订阅!本专栏保证篇篇精品,继续保持本人一贯的幽默式写作风格,当然,在有趣的同时也同样会保证文章的质量,旨在能够产出 "有趣的干货" !

    本系列教程不管是零基础还是有基础的读者都可以阅读,可以先看看目录! 标题前带星号 (*) 的部分不建议初学者阅读,因为内容难免会超出当前章节的知识点,面向的是对 C 语言有一定基础或已经学过一遍的读者,初学者可自行选择跳过带星号的标题内容,等到后期再回过头来学习。

    值得一提的是,本专栏 强烈建议使用网页端阅读! 享受极度舒适的排版!你也可以展开目录,看看有没有你感兴趣的部分! 本章是本教程的开篇之作,篇幅较长且内容极为丰富 (全文近两万字),是本团队 (只有我一个人的团队) 呕心沥血耗时一周打磨出来的内容,希望需要学 C 语言的朋友可以耐下心来读一读。最后,可以订阅一下专栏防止找不到。

" 有趣的写作风格,还有特制的表情包,而且还干货满满!太下饭了!"

—— 沃兹基硕德

📜 本章目录:

Ⅰ. 你好, 世界!(Hello World)

0x00 引入:HelloWorld 的由来

0x01 代码编辑器的选用(推荐 VS2022)

0x02 创建新项目

0x03 敲下这 “跨越历史” 的 Hello World!

Ⅱ. 头文件(Header)

0x00 引入:什么是头文件?

0x01 标准输入输出库 stdio

0x02 引入头文件的方式

* 0x03 养成声明与定义分离的习惯

* 0x04 头文件保护(防止头文件重复包含)

* 0x05 条件引用技术

* 0x06 实践错误记录:#include 展开的问题

* 0x07 技巧:学会定义 _GLOBAL_H 来管理头文件

* 0x08 整理:stdio 定义的库变量、库宏和库函数

Ⅲ.  main 函数(Main Function)

0x00 引入:继续观察 HelloWorld 示例

0x01 什么是 main 函数?

0x02 常规写法: int main() 和 int main(void)

* 0x03 带参写法:int main(int argc, char *argv[])

* 0x04 颇有争议的写法:void main()

* 0x05 存在于 C89 的写法:main()

* 0x06 错误写法:mian()

* 0x07 main 函数执行前做的事

* 0x08 可以调用 main 函数吗?

Ⅳ. 深入浅出:Hello,World!

0x00 引入:再看 Hello,World!

0x01 函数体的概念(花括号匹配原则)

0x02 简单介绍一下 printf 函数

0x03 分号,语句结束的标志!

0x04 返回语句 return 

* 0x05 关于 return 后面带括号的写法

0x06 深入浅出:Hello,World!

尾记:如何学习一门编程语言?


Ⅰ. 你好, 世界!(Hello World)

  • 本章是首个章节,将通过计算机最经典的示例程序  Hello World 来展开我们的教程,考虑到 C 语言历史大家应该早已屡见不鲜,所以这里我们选择介绍 Hello World 的历史和由来。然后带着大家创建项目并敲下这最经典的代码。

0x00 引入:HelloWorld 的由来

"所有的伟大,都源于一个勇敢的开始!"

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划

❓ 思考:什么是 Hello World ?它又是怎么来的?

Hello World 是一种常见的计算机程序,通常作为一个新编程语言或平台的入门示例。

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​ 它的起源可以追溯到 1974 年,由计算机科学家 布莱恩·柯林汉 创造。

没错,就是那个 80 岁还在咔咔咔写代码的巨佬,贝尔实验室的 神仙 !

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​ 在 C 语言第一本教材《C程序设计语言》中,

他使用了 Hello World 作为一个简单的示例,来介绍 C 语言的基本语法。

他与 C 语言之父 —— 丹尼斯里奇 共同合作了撰写了这本书,K&R 就是两人名字的缩写。

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​ 同时,他还是开发 Unix 的主要贡献者,Unix 就是由柯林汉命名的!

"全员恶人?什么恶人?全员神仙!"

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​ 可以这么说,当你把 Hello World 这几个字成功打印到屏幕上时,

你的内心体验到的不仅仅是一种成功的喜悦,更重要的是,你正在亲身经历一个跨越历史的时刻!

" 编程生涯,由此开始!"

Hello World 究竟从何而来?

当 Forbes India 杂志采访柯林汉时,他本人对自己这段传奇故事中一些记忆已经有点儿模糊了。当被问及为什么选择 "Hello, World! "时,他回答道:"我只记得,我好像看过一幅漫画,讲述一枚鸡蛋和一只小鸡的故事,在那副漫画中,小鸡说了一句 Hello World " ——

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划

0x01 代码编辑器的选用(推荐 VS2022)

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​ 刚才我们了解了 Hello World 的故事,敲之前还需要做一些 "必要" 的准备!正所谓:

" 工欲善其事,必先利其器!"

我们先来对 "代码编辑器" 做一个简单的了解,我们这里指的 "编辑器" 是 集成开发环境 (IDE) 

集成开发环境(即 IDE)是一种软件应用程序,提供了一个集成的开发环境,包括代码编辑器、编译器、调试器和其他开发工具,用于简化和加速软件开发的过程。IDE 通常用于软件开发,尤其是针对特定编程语言的开发,例如 Java、Python、C++ 等。IDE 的主要优点是提供了一个集成的工作流程,使得开发人员能够更加高效地编写、测试和调试代码。IDE通常具有自动代码完成、语法高亮、代码调试、版本控制等功能,可以大大提高开发效率和代码质量。常见的 IDE 包括 Visual Studio、Eclipse、和 IntelliJ IDEA 等。

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​ 下面我先打开我的编辑器,我的代码编辑器是:

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​ 大人!时代变了!怎么还有人在用 VC6.0 啊!不会吧?

哈哈哈哈哈,怎么会!我用的可是支持脑机接口编程的 VS2077 :

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划

开个玩笑,其实是 VS2022!本系列博客 Windows 系统下一律选用 Visual Studio 2022 

我们也是非常推荐大家使用 VS2022 的,臣以为 VS2022 真乃 宇宙最强编辑器 也!

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划

" 强烈建议安装,用过都说好,下载链接我贴到下面了。"

🔗 VS 官网:Visual Studio 2022 IDE - 适用于软件开发人员的编程工具

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划

学习阶段我们使用免费的 Community2022 版本 (社区版) 就完全够用了,大家可以自行下载。

关于为什么选用 VS


关于 Visual Studio 的安装,网上有很多很不错的教学视频,简易大家跟着视频去安装。 安装过程还是没有什么难度的,喝杯咖啡的功夫就可以搞定了!和安装 Java 环境比真的容易太多,Java 还要手动配置环境,设置电脑环境变量等一系列杂七杂八的工作…… 而 Visual Studio 非常人性化地一条龙服务,几乎帮你包揽了这一切!(还有个编辑器叫CLion,J家的开包即用的编辑器,但本专栏还是选用了 VS)

此外,微软还有一个叫 Vscode 的神器,这个环境的准备就复杂得多,我们也不简易新手一上来就用 Vscode(虽然我当年系统性学C的时候就直接捣鼓了 Vscode 环境),安装环境的过程是非常劝退人的,所以也不建议。值得一提的是,Vscode 属于轻量化的编辑器,并不是 IDE!

当然有些学校可能会要求大家使用 Dev C++,那个也是个不错的编辑器,但是还是建议大家去使用 Visual Studio,因为后续章节中会附带一些基础调试的教学,是基于 Visual Studio 的,本专栏在 Window 下也都是采用 Visual Studio 来给大家做教学演示的,所以为了更好地贴合本专栏进行系统性地学习,尽量选用 Visual Studio! (ps:再多说一句:如果你学校推荐的编译器是 VC6.0 + 和用到包浆的 PPT,额…… )

* 当然,为了更方便大家系统性地学习,后期我会更新一篇 VS 的安装教程的。

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​下面,我们将认为读者已经安装好了 VS2022,并带着大家手把手敲出 Hello,World!

📌 注意:所以为了更好地贴合本专栏进行系统性地学习,尽量选用 Visual Studio 

0x02 创建新项目

 首先,找到桌面快捷方式,双击打开 Visual Studio 2022

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划(简约而不失优雅的加载页面...)

 进入下方页面后,点击右下角的 创建新项目 (N)

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划

 然后点击 空项目

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划

随后到了配置新项目,这里创建项目名称,演示阶段名字自行取,之后点击 创建 (C) 

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划

创建完新项目后,我们找到 解决方案资源管理器,右键 "源文件",点击 "添加新建项" :

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​名称我们就取为 test.c,然后点 添加(A),我们的工程就会在指定的位置很好地创建出来:

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​ 这里的 .c 文件 和 .h 以及 VS 默认的 .cpp 后缀是什么?我们来简单介绍一下:

简而言之,.c 文件用于 C 语言编程,.cpp 文件用于 C++ 编程:

  • .c 是 C 源代码文件的扩展名。
  • .cpp 是 C++ 源代码文件的扩展名。
  • .h 是头文件 (header file) ,包含在 C 或 C++ 程序中,用于声明函数、变量和数据结构等,以便在程序的其他部分中使用。

(这些我们在后期讲解 编译链接 时都会详细讲解,这里只需要 .c 是 C 语言源文件的后缀即可)

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​创建完毕后,我们就可以在 test.c 下打代码了:

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​ 至此,我们要做的准备工作基本就完成了,下面我们就要开始敲 Hello,World 了!

0x03 敲下这 “跨越历史” 的 Hello World!

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​ 如果你是一个初学者,我们很能理解你迫切的想要敲出 Hello,World 的心情!

我们现在就拉出本教程的第一个代码 —— Hello,World,来让大家 一睹芳容 !

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划

" 手动播放劲爆的新宝岛 bgm,敲下这令人激动的第一个代码!"

💬 代码演示:C 语言经典示例程序 —— Hello,World

#include <stdio.h>

int main()
{
	printf("Hello, World!\n");

	return 0;
}

你可以手动将代码打到源文件中,也可以直接点击右上角 "复制" 按钮,将代码粘贴到源文件中。

下面我们准备运行这段代码,点击顶部菜单栏 调试 (D) → 开始执行(不调试) 

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​ 当然你也可以使用快捷键运行,输入 Ctrl + F5 运行代码:

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划

我们也推荐大家使用!因为作为键盘侠,使用快捷键会很 cool !

运行后就会弹出一个窗口 —— Microsoft Visual Stidio 调试控制台:

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划

我们可以看到,我们的 Hello, World! 在控制台上出现了,这是因为我们调用了打印函数 printf

#include <stdio.h>

int main()
{
	printf("Hello, World!\n");  👈 打印 Hello,World

	return 0;
}

(如果是零基础读者,看不明白这段代码,这都没有关系,我们会深入浅出地慢慢讲解)

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​ 只会敲 Hello World 的我瑟瑟发抖……

至此,我们的 Hello World 就敲完了,我们也成功的将这段话输出到了我们的显示器上。

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​下面我们会慢慢地、深入浅出地讲解刚才的 Hello World 代码:

#include <stdio.h>

int main()
{
	printf("Hello, World!\n");  

	return 0;
}

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​ 等讲解完这些必要的知识点后,我们再回来看这段代码,就会非常地清楚 ~

Ⅱ. 头文件(Header)

  • 围绕着 HelloWorld 继续推进,理解第一行代码我们需要先知道什么是头文件,以及我们引入的 stdio 库,这里我们会详细的讲解各种头文件的知识点,包含了头文件保护、声明定义分离、#include 展开等内容。

0x00 引入:什么是头文件?

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​下面是 HelloWorld 示例程序的第一行代码:

#include <stdio.h>    // 引入头文件 stdio 库

* 注:两个斜杠 ( // ) 后面的内容属于「注释」,我们会在下一章进行讲解!

这一行代码的意思是 "引入头文件 stdio.h 库",我们先来简单介绍一下什么是 头文件 (header)。

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划

📚 概念:头文件, [英] header,[繁] 標頭檔

后缀为 .h 的文件被称为 "头文件" ,因为头文件的英文是 header,所以缩写为 .h

包含了 C 语言函数声明和宏定义,被多个源文件中引用共享。

头文件分为两种,一种是 "程序员自己编写的头文件",另一种是 "编译器自带的头文件" 。

关于头文件的一些细节


在 C 语言中,头文件是一个文件。头文件通常是源代码的形式,由编译器在处理另一个源文件时自动包含进来。程序员通过编译器指令将头文件包含进其他源文件的开始。

一个头文件包含类、子程序、变量和其他标识符的前置声明,需要在一个以上源文件中生命的标识符可以放在一个头文件中,并在需要的地方包含该头文件。头文件作为一种包含功能函数、数据接口声明的载体文件,主要用于保存程序的声明。

早期的编程语言如 Basic、Fortran 并没有头文件的概念。

我们使用 #include 来引用头文件,这是一个 C 预处理指令,对于预处理的知识我们后期会讲解。

#include         引入头文件

我们的 Hello World 示例代码中,就是使用了 #include 来引用头文件的,引用的是 stdio.h 

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​ 这是什么?下面,我们就来介绍一下这个 stdio.h

0x01 标准输入输出库 stdio

stdio.h 是编译器自带的头文件,其中 .h 我们刚才说过,是扩展名,被称之为头文件。

stdio 全称 standard input & output,即标准输入输出,我们称之为 C 标准库,直接看图记忆:

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划

因为我们的 HelloWorld 示例程序需要用到 printf 这个函数,所以我们需要引入 stdio.h

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​ 之所以叫做 stdio 是因为 standard input & output,而它表示了这库中最经典的两个函数:

  • printf() :标准输入函数(input)
  • scanf() :标准输出函数(output)

(对于这两个函数,我们后续会详细讲解)

📜 了解:stdio.h 的文件说明

/*
*stdio.h
*This file has no copyright assigned and is placed in the Public Domain.
*This file is a part of the mingw-runtime package.
*Now arranty is given;refer to the file DISCLAIMER within the package.
*
*Definitions of types and proto types of functions for 
*standard inputand output.
*
*NOTE:The file manipulation functions provided by Microsoft seem to
*work with either slash(/) or backslash(\) as the directory separator.
*
*/

0x02 引入头文件的方式

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​ 我们前面讲了,我们使用 #include 来引用头文件,这个 # 是预处理指令。

预处理指令 # 可用于宏定义、文件包含 和 条件编译。

刚才我们介绍了 stdio.h 库,现在我们再来观察 HelloWorld 示例程序的第一行代码:

#include <stdio.h>

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​ 我们可以看到 #include 后面使用了两个尖括号 < > 包住了 stdio.h

尖括号中引入的头文件基本都是 C 语言中各种各样的 库函数,刚才学习的 stdio 就是其中之一。

这行代码中,我们通过 #include <> 去引入了标准输入输出库 stdio。

头文件的引入除了尖括号 < > ,还有双引号 " " 形式的引入:

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划

🔍 两种引用方式的区别:头文件用 < > 引入和用 " " 引入的区别

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​首先,< >" " 包含头文件的本质区别是查找策略区别。

 尖括号 < > 的查找策略:直接去标准路径下去查找,用来引用标准库的头文件。

#include <文件>   // 编译器将从标准库目录开始搜索

双引号 " " 的查找策略:先在源文件所在的目录下查找。如果该头文件未找到,则在库函数的头文件目录下查找。如果仍然找不到,则提示编译错误。用来引用非标准库的头文件。

#include "文件"   // 编译器将从用户的工作目录开始搜索

❓ 思考:那可不可以用双引号 " " 包含库文件?

#include "stdio.h"

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​ 当然,库文件也是可以使用 " " 包含的,但是不建议库文件用 " " 形式引入!

#include <stdio.h> 是库文件,你用引号形式引入 #include "stdio.h" 也是可以的,

但是这样查找的效率就会大打折扣,因为会先从源文件所在目录下去找一遍,然后再去找。

我们既然明确知道自己是要使用库文件了,我们自然就直接使用尖括号才是正常的。

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​而且这样也不容易区分是库文件还是本地文件。

(看到尖括号引入就知道是库文件,看到引号引入的就知道是本地文件,还是很香的)

① Linux环境 标准头文件的路径:

/usr/include

② VS环境 标准头文件的路径:

C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include

* 0x03 养成声明与定义分离的习惯

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​要做到声明与定义相分离,头文件中应当只存放声明,而不存放定义。

为了养成模块化编程的好习惯,我们尽量把代码分开写,声明放到头文件中,定义放到源文件中。

VS 下,在解决方案资源管理器中:

  • 在 "头文件" 文件夹中右键取文件名以 .h 结尾即可创建头文件。
  • 在 "源文件" 文件夹中右键取文件名以 .c 结尾即可创建源文件。

C++ 语法中,类的成员函数可以在声明的同时被定义,并自动成为内联函数。这带来了书写上的便利,但也造成了风格的不一致,弊大于利。建议将成员函数的定义与声明分离开来。

* 0x04 头文件保护(防止头文件重复包含)

"使用头文件保护技术,能够有效提升代码的一致性和可维护性……"

当需要引入多个头文件时,头文件引用条目达到十几条以上时,难免会出现重复引用的失误。

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​ 比如下面这个代码,仔细观察你会发现不小心引入了两次 stdio:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <cstdio>
#include <memory>
#include <cstdlib>
#include <random>
#include <cstdio>
#include <stdio.h>     ← 引入两次了
#include <utility>
#include <cstring>
#include <vector>
#include <functional>
...

这就是典型的重复引用错误,此时编译器会处理两次头文件的内容,从而产生错误。

为了防止这种情况的发生,经典的做法是将文件的整个内容都放到条件编译语句中。

具体做法是使用预处理指令 #ifndef#define#endif 来避免重复包含:

#ifndef STDIO_H
#define STDIO_H

// stdio.h 的内容

#endif

这里我们使用了包装器 #ifndef,当再次引用头文件时条件为假,因为 STDIO_H 已经定义。

如此一来,预处理器会检查 STDIO_H 是否以及定义,如果没有定义就会进入 #ifndef 块内;

如果已经定义,此时预处理器会跳过文件的整个类容,编译器就会将其忽略不计。

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​ 该技术我们称之为 头文件保护 (header guards) ,可以有效确保头文件只被包含一次。

⚡ 如果嫌麻烦,还有一种非常简单的方法:

#pragma once // 让头文件即使被包含多次,也只包含一份

(具体的讲解我们会在后面的预处理章节进行更加深刻细致的讲解)

因此,为了预防头文件被重复引入,建议使用 ifndef / define / endif 结构产生与处理块。

* 0x05 条件引用技术

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​条件引用是一种根据特定条件来选择性包含或排除代码的技术。

如果需要从多个不同的头文件选择一个引用到程序中,此时就需要用 "有条件引用" 来达成目的。

举个例子,现在我们需要指定不同的操作系统上使用的配置参数:

#if SYSTEM_1
   # include "system_1.h"
#elif SYSTEM_2
   # include "system_2.h"
#elif SYSTEM_3
   ...
#endif

当头文件较多时,此这么做显然不妥,我们可以预处理器使用宏来定义头文件的名称。

这种方法就是 有条件引用,不用头文件的名称作为 #include 的直接参数,

而只需要用宏名称代替即可,因为 SYS_H 会拓展,预处理器会查找 sys_1.h 

 #define SYS_H "sys_1.h"
 ...
 #include SYS_H

(SYSTEM_H 可通过 -D 选项被 Makefile 定义)

* 0x06 实践错误记录:#include 展开的问题

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​ #include 的展开是有特点的,下面我将通过一个实践中碰到的例子,来讲解展开的特点。

💭 举个例子:下面我们手动定义了一颗二叉树(Queue.c)

​
#define _CRT_SECURE_NO_WARNINGS 1
#include "Queue.h"

typedef char BTDataType;
typedef struct BinaryTreeNode {
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
	BTDataType data;
} BTNode;

//#include "Queue.h"  解决方案?

/* 创建新节点 */
BTNode* BuyNode(BTDataType x) {
	BTNode* new_node = (BTNode*)malloc(sizeof(BTNode));
	if (new_node == NULL) {
		printf("malloc failed!\n");
		exit(-1);
	}
	new_node->data = x;
	new_node->left = new_node->right = NULL;

	return new_node;
}

/* 手动创建二叉树 */
BTNode* CreateBinaryTree() {
	BTNode* nodeA = BuyNode('A');
	BTNode* nodeB = BuyNode('B');
	BTNode* nodeC = BuyNode('C');
	BTNode* nodeD = BuyNode('D');
	BTNode* nodeE = BuyNode('E');
	BTNode* nodeF = BuyNode('F');

	nodeA->left = nodeB;
	nodeA->right = nodeC;
	nodeB->left = nodeD;
	nodeC->left = nodeE;
	nodeC->right = nodeF;

	return nodeA;
}

我们可以看到,我们 #include 引入了 Queue.h 文件,由于是我们的数据类型是 BTNode

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​所以我们需要修改一下 Queue.h 中的 QueueDataType

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>

typedef BTNode* QueueDataType;

typedef struct QueueNode {
	struct QueueNode* next;
	QueueDataType data;
} QueueNode;

typedef struct Queue {
	QueueNode* pHead;
	QueueNode* pTail;
} Queue;

void QueueInit(Queue* pQ);                    //队列初始化
void QueueDestroy(Queue* pQ);                 //销毁队列
bool QueueIfEmpty(Queue* pQ);                 //判断队列是否为空
void QueuePush(Queue* pQ, QueueDataType x);   //入队
void QueuePop(Queue* pQ);                     //出队
QueueDataType QueueFront(Queue* pQ);          //返回队头数据
QueueDataType QueueBack(Queue* pQ);           //返回队尾数据
int QueueSize(Queue* pQ);                     //求队列大小

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​此时令人瞠目结舌的问题就出现了,我们运行代码就会产生报错:

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​我们来冷静分析一下这个报错,分析完你会发现分析了个寂寞……

报错说又缺少 " { " 又缺少 " ) " 的,这明显是胡说八道。

我们的编译器在这里就显得没有这么智能了,报的错都开始胡言乱语了。

❓ 思考:这里产生问题的原因是什么呢?(提示:想想编译器的原则)

💡 编译器原则:编译器认识 int,是因为 int 是一个内置类型。但是 BTNode* 编译器并不认识,

就需要 "往上面" 去找这个类型。这里显然往上找,是找不到它的定义的,所以编译器会报错。

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划

如果你要用这个类型,你就需要先定义这个类型。

test.c 文件中 #include "Queue.h" ,相当于把这里的代码拷贝过去了。

此时,由于 BTNode* 会在上面展开,导致找不到 BTNode* 

❓ 思考:我把 #include 移到 定义类型的代码 的后面,可以解决问题吗?

可以!遗憾的是只能解决这里 typedef BTNode* 的问题,还有 Queue.c 里的问题……

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​ 那我们该怎么做,才能彻底解决呢? 

🔑 解决方案:使用前置声明。这样就不会带来问题了,满足了先声明后使用。

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划

💬 代码演示:使用 "前置声明" 修改后的 Queue.h

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>

// 前置声明
struct BinaryTreeNode;
typedef struct BinaryTreeNode* QueueDataType;

typedef struct QueueNode {
	struct QueueNode* next;
	QueueDataType data;
} QueueNode;

typedef struct Queue {
	QueueNode* pHead;
	QueueNode* pTail;
} Queue;

void QueueInit(Queue* pQ);                    //队列初始化
void QueueDestroy(Queue* pQ);                 //销毁队列
bool QueueIfEmpty(Queue* pQ);                 //判断队列是否为空
void QueuePush(Queue* pQ, QueueDataType x);   //入队
void QueuePop(Queue* pQ);                     //出队
QueueDataType QueueFront(Queue* pQ);          //返回队头数据
QueueDataType QueueBack(Queue* pQ);           //返回队尾数据
int QueueSize(Queue* pQ);                     //求队列大小

此时问题就解决了,头文件展开后不会引发报错问题。

* 0x07 技巧:学会定义 _GLOBAL_H 来管理头文件

"有效避免头文件过多,乱七八糟,不方便管理的问题。"

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​如果一个工程中有大量的 .h 文件 和 .c 文件,此时难免会很乱。

此时我们可以选择用一个 global.h 的头文件来把所有 .h 文件 "打包" 起来,

在除 global.h 文件外的头文件中包含此文件,这样我们就可以有条不紊地管理好所有的头文件了。

#ifndef _GLOBAL_H
#define _GLOBAL_H

#include <cstdio>
#include <memory>
#include <cstdlib>
#include <random>
#include <cstdio>
#include <utility>
#include <cstring>
#include <vector>
#include <iostream>
#include <functional>
...

* 0x08 整理:stdio 定义的库变量、库宏和库函数

📃 专栏阅读贴士

当标题前出现 *(星号)时,则说明该部分知识点是面向对 C 语言已经有一定基础的读者阅读的,讲解时难免会穿插不属于本章范围的内容。如果你是一名初学者,可以选择跳过。

对 stdio 有过一些了解的读者可能会知道 stdio.h 定义了 3 个变量类型,以及一些宏和各种函数。

对于库中的变量、宏和函数,我们一般称之为 库变量库宏 和 库函数

库变量 (Library Variable):

头文件在 stdio.h 中定义了 3 个变量类型,分别是 FILEsize_t fpos_t 类型。

FILE
size_t
fpos_t
  • FILE 类型:存储文件流信息的对象类型(文件章节我们会详细讲解)。
  • size_t 类型:无符号整数类型,为关键字 sizeof 的返回结果。
  • fpos_t 类型:存储文件中任何位置的对象类型。

 库宏 (Libary Micro):以下是 stdio.h 中定义的宏,一共有 16 种,我们先简单介绍一下。

1. NULL

NULL:空指针常量的值。

2. BUFSIZ

BUFSIZ:该宏为整数,代表了 setbuf 函数使用的缓冲区大小。

3. EOF

EOF:文件结束标志 EndOfFile,表示文件结束的负整数,非常常见!后续我们学习 getchar 函数时会详细讲解。

4. FOPEN_MAX

FOPEN_MAX:该宏为整数,代表了系统可以同时打开的文件数量。

5. FILENAME_MAX

FILENAME_MAX:该宏为整数,代表了字符数组可以存储的文件名最大长度,如果事先没有任何限制,则该值为推荐的最大值。

6. L_tmpnam

L_tmpnam:该宏为整数,代表了字符数组可以存储的由 tmpnam 函数创建的临时文件名的最大长度。

7. _IOFBF
8. _IOLBF
9. _IONBF

拓展了带有特定值的整型常量表达式,适用于 setvbuf 的第三个参数。

10. SEEK_CUR
11. SEEK_END
12. SEEK_SET

fseek 函数中使用,用于在一个文件中定位不同的位置。

13. TMP_MAX

tmpnam 函数可生成的独特文件名的最大数量。

14. stderr
15. stdin
16. stdout

FILE 类型的指针,标准错误、标准输出和标准输出流。

库函数 (Libary Funciton):共有 42 种函数,我们会在后续章节将一些常用的函数进行介绍。

Ⅲ.  main 函数(Main Function)

  • 介绍完头文件后,下面我们将讲解 C 程序中最为重要的 main 函数,掌握 main 函数的特点与特性,探讨 main 函数的各种写法形式,并对这些写法进行说明讲解。

0x00 引入:继续观察 HelloWorld 示例

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​ 刚才我们讲解了 #include <stdio.h>,下面我们来看第三行代码,int main() 

#include <stdio.h>

int main()
{
	printf("Hello, World!\n");

	return 0;
}

首先,int 表示整型,这里表示 main 函数的返回值为整型。(下一章我们会讲解数据类型)

* [注] int 是英文单词 integer 的缩写,意思是 "整数"。

int 后面跟着的 main 就表示了 main 函数,我们先了解下什么是 函数 (function) :

这里的函数可不是数学中的函数,在 C 语言中,函数是一种可重复使用的代码块,用于执行特定的任务。它是程序的基本组成部分,用于模块化和组织代码,使程序更易于理解、调试和维护。

0x01 什么是 main 函数?

📚 概念:main 函数,又称主函数,每个 C 程序都必须有一个 main 函数。

#include <stdio.h>

int main()       👈 程序从这里执行
{
	return 0;
}

主函数是程序执行的起点,你的程序会从这里开始执行,每次执行程序都从 main 函数开始。

一个工程中可以有多个 .c 文件,但多个 .c 文件中只能有一个 main 函数,main 函数具有唯一性。

"一个程序不能没有主函数,就像山东不能没有曹县!"

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划

🔺 铁律:main函数是程序的入口,主函数有且仅有一个!

一个 C 语言程序的执行,从 main 函数开始,到 main 函数结束。 如何理解呢?

你可以把 main 函数想象成入口,一切都从这里开始执行,最后肯定也是要从这出去的。

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​main 函数的返回类型取决于 main 标识符前是什么数据类型,比如这里是 int:

int main() 
{
    return 0;
}

那么该主函数就存在一个整型类型的返回值,我们需要使用 return 去返回(我们后续再说)。

在我们的演示代码 HelloWorld 中,我们可以看到,main 后面跟了一个括号,

括号中定义了函数的参数类型,而我们演示代码中,括号中是什么都没有的。

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​ 我们可以在括号里面加上一个 void,就像这样:

int main(void)

void 也是数据类型,表示无类型,演示代码中为了演示简单化,我们把括号中的 void 省略掉了。

这里 在括号中加上 void 表示函数不接受任何参数, 后面接上的花括号,就是 函数体 了:

#include <stdio.h>        

int main(void)    // 主函数的返回类型是 int,主函数 void 不接受任何参数
{
	printf("Hello, World!\n");

	return 0;     // 由于主函数要求返回整型,这里 return 0
}

C 语言规定,在一个源程序中,main 函数的位置可以任意。

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​下面我先列举一些大家常见的主函数形式,然后我们再慢慢评价。

约定俗成型(目前主流的写法):

int main()
int main(void)

 什么都不返回型(颇有争议):

void main()
void main(void)

带参型(带参形式,标准的 main 函数,带两参数):

int main(int argc, char **argv)
int main (int argc, char *argv[], char *envp[])

 超级简单型(存在于 C89 标准中的写法,没有返回值,没有入参):

main()

// Brian W. Kernighan 和 Dennis M. Ritchie 的经典巨著 
// The C programming Language 用的就是 main()。

直接报错型(相信 90% 的程序员都犯过这个错误):

int mian()

0x02 常规写法: int main() 和 int main(void)

" 约定俗成型,这应该是现在最普遍的写法了。"

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​ 我们平时写 main 函数的时 main 函数参数一般都不写,即括号里什么都不填。

或者填上一个 void 表示主函数不接受任何参数:

int main()
int main(void)

📌 注意:值得注意的是,int main() 和 int main(void) 这两种写法是存在区别的!

  • int main():参数列表没有被 void 限制死,可以传入参数,程序需要返回值。
  • int main(void):不能传入参数,如果输入参数就会报错,程序必须要有返回值。

这两种写法中,更加建议加 void 的写法,因为是 C89/C99/C11 标准文档中提供的写法之一:

int main(void) { /* ... */ }

* 0x03 带参写法:int main(int argc, char *argv[])

" VS下输入 main 然后回车后就能自动补全的标准写法 "

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​该写法也是  C89/C99/C11 标准文档中提供的标准写法,也是很常见的一种写法:

int main(int argc, char *argv[]) { /* ... */ }

参数列表中,argc 是一个整数参数,表示传递给程序的命令行参数的数量。

argv 是一个指向字符指针数组的指针,用于存储命令行参数的字符串。

  • argv[0]通常是程序的名称或路径。
  • argv[1到 argv[argc-1是传递给程序的其他命令行参数。

💬 代码演示:int main(int argc, char *argv[]) 

#include <stdio.h>

int main(int argc, char *argv[]) 
{
    printf("命令行参数的数量:%d\n", argc);
    printf("第一个参数(程序名称):%s\n", argv[0]);

    for (int i = 1; i < argc; i++) 
    {
        printf("参数 %d: %s\n", i, argv[i]);
    }

    return 0;
}

* 0x04 颇有争议的写法:void main()

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​ 首先抛出一个事实 —— C/C++ 中从来没有定义过 void main()

C++ 之父本贾尼在他的主页上的 FAQ 中明确地写着 ——

The definition void main() {/*...*/} is not and never has been C++, nor has it even been C.

(void main 从来就不存在于 C++ 或者 C)

void main 这种写法究竟规不规范?这个广为大家所知的 void main 究竟是怎么回事?

void main()
void main(void)

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​光从语法角度上来看,C 语言里是可以编译运行 void main 的。

因为 C 中的函数只关注函数名,而关注其返回类型,在找入口函数时仅仅在找 "main" 而已。

从汇编角度来看,返回值即函数返回时寄存器  的值,因此  中总是有值的。

和变量一样,不主动赋值给的是随机数,因此 void main 即使返回类型是 void,也是有返回值的。

很多人说这种写法都是 "谭C" 带的,事实上并非如此,因为早在上世纪就已然出现了这种写法。

"还有甩锅给谭C的,更是无稽之谈,难道微软和 Borland 的工程师也是跟谭C学的?"

—— 电脑博物馆站长

 ⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​ 当然,一些编译器 void main 是可通过编译的,比如 VC6.0 

有人说 void main 其实挺合理的,编写单片机的话你 return 给值给谁?

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​此时出现了一个非常炸裂的回答:你可以不收,我不能不给。

哈哈哈哈,看来写代码也讲人情世故!return 什么无所谓,我就是要个态度 ~ 

最后,对 void main 感兴趣的朋友可以看此帖:

🔗 链接:C 语言的「void main」是怎么一代代传下来的? - 知乎

* 0x05 存在于 C89 的写法:main()

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​C89 标准中支持这种只丢一个 main() 的写法:

main()

C 语言中是调用者负责清栈任务,因此 main 函数不写返回参数依然是可以的。

你看到有人直接扔一个 main() 但是不报错,事实上也只是编辑器支持而已。

* 0x06 错误写法:mian()

" 因为真的很有趣,所以我不得不提一提。"

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​相信很多人都犯过这个错误,不小心把 main 打成了 mian……

int mian(void)    

相信很多程序员在职业生涯中都犯过这个错误,看了半天没看出问题到底出在哪里:

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划

编译器只会去找 main,你不小心写成 mian 编译器会说没找到 main 函数的。

🔺 总结:我们只需老老实实地遵循 C 语言标准文档的两种写法,就行了。

int main(void) { /* ... */ }
int main(int argc, char *argv[]) { /* ... */ }

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​ 可以保障代码的通用性和可移植性,没有 bug,岂不美哉?

* 0x07 main 函数执行前做的事

待更新……

* 0x08 可以调用 main 函数吗?

 ❓ 思考:用户可不可以调用 main 函数?

这个问题乍一看会让人觉得,不可以吧……main 函数怎么可以让用户调呢: 

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划

很多人都没有想过这个问题,但事实上是可以的,main 函数是可以递归的。

可以是可以,但是调用会一直输出,直至栈溢出(触发 StackOverflow )。

VS 下触发警告:warning C4717: “main”: 如递归所有控件路径,函数将导致运行时堆栈溢出。

💬 代码演示:调用 main()

#include <stdio.h>

int main()
{
	printf("柠檬叶子C\n");
	main();

	return 0;
}

🚩 运行结果如下:

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划

Ⅳ. 深入浅出:Hello,World!

  • 最后,我们讲讲 Hello World 示例程序中剩下来的部分知识点,引出函数体的概念,简单介绍一下 printf 函数,谈论语句结束的标志(分号),最后讲解 return 语句。这些知识点讲完后,我们串联前面讲的内容,就能很清楚地理解 Hello World 了。

0x00 引入:再看 Hello,World!

" 通过这小小的 Hello,World 来展开我们的教学,岂不美哉?"

#include <stdio.h>

int main(void)
{
	printf("Hello, World!\n");

	return 0;
}

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​ 我们刚才讲解了头文件和 main 函数,

现在大家应该能理解 #include <stdio.h>int main() 的含义了。

下面我们来细说一下 main() 后面接的花括号 { },所以我们先要介绍一下函数体的概念。

再介绍一下 printf 函数,以及 return 语句,我们的 Hello World 示例程序就可以 "浅出" 了。

0x01 函数体的概念(花括号匹配原则)

📚 概念:定义一个函数功能的所有代码组成的整体,称为 函数体 (Function Body) 。

函数体是用花括号括起来的若干语句,他们完成了一个函数的具体功能。

(函数声明与函数体组成函数定义,我们会在函数章节详细讲解)

💭 举个例子:比如下面的 main 函数下面跟着一对花括号,花括号内的内容就是函数体了。

#include <stdio.h>

int main(void)
{
	printf("Hello, World!\n");

	return 0;
}

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​一对花括号 { } 由 左花括号 {  和 右花括号 } 组成,左花括号匹配右花括号。

比如这里的 main 函数,其 函数体包括左花括号和与之匹配的右花括号之间的任何内容

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划

0x02 简单介绍一下 printf 函数

printf("Hello, World!\n");

printf 函数,该函数是 stdio.h 中的库函数,因此在使用前需要使用 #include 引入 stdio.h

这里我们就简单介绍一下,printf 后面跟着 () ,括号中的内容用双引号括出,

双引号内的内容可以输出到 控制台,所以我们的 Hello,World 示例程序运行后控制台会显示:

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划

所以,你可以把它叫做 "打印函数",通过 printf 函数将 Hello,World 打印到了控制台上:

printf("需要打印到控制台的内容");

❓ 这里的 \n 为什么没有被打印出来?

因为 \n 是转义字符,用于换行,关于转义字符的知识我们会放到下一章进行系统性讲解。

0x03 分号,语句结束的标志!

 ⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​ 在我们日常生活中, "句号" 表示一段话的结束。

而在 C 语言中,语句的结束用 ; 表示,分号是语句结束的标志,表示一条语句的结束。

​可以看到,我们的 printf() 函数后面就有一个 分号 ;

printf("Hello,World\n");   👈 加分号
return 0;    👈 加分号

当一条语句结束时,我们需要手动给它加上分号,表明该语句结束。

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划

不加分号会报错,人难免是会忘的,如果忘记加了编译器会提示:

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划

随着敲代码越来越熟练,忘记加分号的情况会越来越少的,就像你写作文不会忘记加句号一样。

遗漏分号会引发 C2143 号报错:error C2143: 语法错误: 缺少“;” 

当然了,也不能在不该加分号的地方加分号!

如果你在 main() 后面直接加分号,那就表示语句直接结束了,后面的 { } 就会让编译器一脸懵……

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划

所以,分号是初学者最容易犯错的地方,多用了会错少用了也会错。

但是不用担心,在后续学习过程中慢慢就会掌握了。(比如 do...while 语句 while 结尾要加分号)

0x04 返回语句 return 

我们前面说了,因为我们的 main 函数的返回值类型定义的是 int,所以我们需要 return 一个值:

#include <stdio.h>

int main(void)
{
	printf("Hello, World!\n");

	return 0;
}

📚 概念:在C 语言中,return 用于表示函数的返回值,用来将函数的结果返回给调用它的程序。

return 返回值;

因此,这里我们 return 一个 0,表示程序正常退出。

* 0x05 关于 return 后面带括号的写法

值得一提的是,return 后面 "不带括号" 和 "带括号" 的写法,都是正确的。

return 表达式;    ✅ 常规写法
return (表达式);  ✅ 也是可以的

但是为了简单起见,一般我们不去写,当然写了也不会错,这取决于个人的编程习惯。

比如下面这两行实际效果是一样的:

return 10 + 20;
return (10 + 20);

我见过一些老的微软大佬写的代码里,return 是这么写的:

return( 0);     // 括号直接顶着return

* 💬 举个例子:库函数 src/strlen.c

size_t __cdecl strlen (
        const char * str
        )
{
        const char *eos = str;
 
        while( *eos++ ) ;
 
        return( eos - str - 1 );    👈 表达式
}

0x06 深入浅出:Hello,World!

现在,我们已经解释完所有 Hello,World 的细节了,并且把其中的知识点都讲的差不多了。

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​ 现在我们再回到最初的起点,再次感受那个跨越历史的时刻……

#include <stdio.h>

int main(void)
{
	printf("Hello, World!\n");

	return 0;
}

经过本章的学习后,你也应该会有一个大概的认识了。

我们通过这 Hello World 来展开了我们的教学专栏,介绍了头文件、主函数和一些基础概念。

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划​ 这样的开篇方式我们构思了很久很久,希望能得到大家的喜爱!

C 语言之父 丹尼斯里奇 的曾言:

" C 诡异离奇,缺陷重重,却获得了巨大的成功。"

C 语言无疑是改变人类历史的最伟大发明之一……

在计算机蓬勃发展的今天,我们是站在了巨人的肩膀上,得以让我们看得更高,行的更远……

学习 C 语言的过程是漫长且枯燥的,一定要有一个非常强大的心理状态。

👑 翁凯老师说:在计算机里头没有任何黑魔法!

学计算机一定要有一个非常强大的心理状态,计算机的所有东西都是人做出来的,别人能想的出来,我也一定能想得出来,在计算机的世界里没有任何的黑魔法,所有的东西只不过是我现在不知道而已,总有一天我会把所有的细节、所有的内部的东西全搞明白的。

尾记:如何学习一门编程语言?

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划

我的编程母语是易语言(一款中文编程语言),我的编程启蒙导师是觅风。

觅风老师在他的 《易语言视频教程》中说过:

" 兴趣是最好的老师。"

如果你对编程感兴趣,那么这条路及时很艰难,你也会有无穷无尽的力量。

其次就是多动手,代码眼看千遍不如手敲一遍,多动手去实操,毕竟:

" 纸上得来终觉浅,绝知此事要躬行。"

然后就是多看源码,看看高手是怎么写代码的,大有裨益。

最后,遇到问题要深入了解,要具备对编程知识的求知欲,对问题要有钻研精神。

⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解,?《C语言趣味教程》,c语言,头文件,main函数,原力计划

  • 网制焦,实不严,没毕业,零经验,面八家,十offer,三万二,外包也,两万七,自研也,明日有,多面试。说寒冬,年年有,计算机,月过万,现不学,没机会,趁红利,狠赚笔。
📌 [ 笔者 ]   王亦优 | 雷向明
📃 [ 更新 ]   2023.6.29(初稿)| 2023.7.1(审稿结束)
❌ [ 勘误 ]   /* 暂无 */
📜 [ 声明 ]   由于作者水平有限,本文有错误和不准确之处在所难免,
              本人也很想知道这些错误,恳望读者批评指正!

📜 参考文献:文章来源地址https://www.toymoban.com/news/detail-527296.html

  • - C++reference[EB/OL]. []. http://www.cplusplus.com/reference/.
  • - Microsoft. MSDN(Microsoft Developer Network)[EB/OL]. []. .
  • - 百度百科[EB/OL]. []. https://baike.baidu.com/.
  • - 维基百科[EB/OL]. []. https://zh.wikipedia.org/wiki/Wikipedia
  • - R. Neapolitan, Foundations of Algorithms (5th ed.), Jones & Bartlett, 2015.
  • - B. 比特科技. C/C++[EB/OL]. 2021[2021.8.31]
  • - 林锐博士. 《高质量C/C++编程指南》[M]. 1.0. 电子工业, 2001.7.24.
  • - 陈正冲. 《C语言深度解剖》[M]. 第三版. 北京航空航天大学出版社, 2019.
  • - 侯捷. 《STL源码剖析》[M]. 华中科技大学出版社, 2002.
  • - T. Cormen《算法导论》(第三版),麻省理工学院出版社,2009年。
  • - T. Roughgarden, Algorithms Illuminated, Part 1~3, Soundlikeyourself Publishing, 2018.
  • - J. Kleinberg&E. Tardos, Algorithm Design, Addison Wesley, 2005.
  • - R. Sedgewick&K. Wayne,《算法》(第四版),Addison-Wesley,2011
  • - S. Dasgupta,《算法》,McGraw-Hill教育出版社,2006。
  • - S. Baase&A. Van Gelder, Computer Algorithms: 设计与分析简介》,Addison Wesley,2000。
  • - E. Horowitz,《C语言中的数据结构基础》,计算机科学出版社,1993
  • - S. Skiena, The Algorithm Design Manual (2nd ed.), Springer, 2008.
  • - A. Aho, J. Hopcroft, and J. Ullman, Design and Analysis of Algorithms, Addison-Wesley, 1974.
  • - M. Weiss, Data Structure and Algorithm Analysis in C (2nd ed.), Pearson, 1997.
  • - A. Levitin, Introduction to the Design and Analysis of Algorithms, Addison Wesley, 2003. - A. Aho, J. 
  • - E. Horowitz, S. Sahni and S. Rajasekaran, Computer Algorithms/C++, Computer Science Press, 1997.
  • - R. Sedgewick, Algorithms in C: 第1-4部分(第三版),Addison-Wesley,1998
  • - R. Sedgewick,《C语言中的算法》。第5部分(第3版),Addison-Wesley,2002

到了这里,关于⚡【C语言趣味教程】(1):深入浅出 HelloWorld | 通过 HelloWorld 展开教学 | 头文件详解 | main 函数详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 深入浅出循环语句—【C语言】

      分支语句博客: http://t.csdn.cn/U2kZF 目录 ​编辑 前言:我们先来了解一下break 、continue在循环中的作用 1. while循环  while循环中的break  while循环中的continue  2. for循环 for循环省略出错举例:  for循环中的break  for循环中的continue 3. do   while循环 利用do while循环打印1~10   d

    2024年02月04日
    浏览(105)
  • 深入浅出C语言—【函数】下

    函数和函数之间可以根据实际的需求进行组合的,也就是互相调用的。 注意: 函数可以嵌套调用,但是不能嵌套定义。 把一个函数的返回值作为另外一个函数的参数。 上面的strlen函数是求数组长度的库函数, 特别注意的是,当数组为字符数组时,数组的末尾会自动放一个

    2024年02月17日
    浏览(82)
  • 深入浅出C语言—【函数】上

       目录 1.函数的概念 2.C语言函数的分类 2.1 库函数 2.1.1 strcpy库函数举例学习方式 2.1.2 库函数扩展知识 2.2 自定义函数 2.2.1求两个整数中的较大值 3. 函数的参数 3.1 实际参数(实参) 3.2 形式参数(形参) 4. 函数的调用 4.1 传值调用 4.2 传址调用 老铁们,网址自取,记得一键

    2024年02月07日
    浏览(77)
  • 深入浅出分支语句—【C语言】

    目录 前言:为什么要学习分支和循环语句呢? 1. 语句的分类 2. 分支语句(选择语句) 2.1 if-else语句 注意点:if-else语句后面不加{},默认只能跟一条语句 2.2  switch语句  注意点: 因为C语言是一门结构化的程序设计语言,具有三种结构:顺序结构、选择结构、循环结构,这三

    2024年02月02日
    浏览(96)
  • 深入浅出:大语言模型的视觉解析

    一系列工具与文章的汇编,直观易懂地解读复杂的 AI 概念 图片由作者利用 unDraw.co 的免费插图制作 在当今世界,大语言模型(LLM)成为了热门话题。几乎每天都有新的语言模型问世,让人们在 AI 领域怀有一种“不容错过”的紧迫感。尽管如此,许多人仍对大语言模型的基础

    2024年01月19日
    浏览(46)
  • 深入浅出对话系统——自然语言理解模块

    首先回顾一下自然语言理解的概念。 自然语言理解(Natural Language Understanding)包含三个子模块: 其中领域识别和意图识别都是分类问题,而语义槽填充属于序列标注问题。所以,在自然语言理解中,我们要解决两个分类任务和一个序列标注任务。既然其中两个问题都属于分类任

    2024年02月08日
    浏览(90)
  • 深入浅出堆—C语言版【数据结构】

    二叉树概念博客 :http://t.csdn.cn/XIW84 目录 1. 了解堆 1.1 堆的概念 1.2 堆的性质: 1.3 堆的结构图片 1.3.1 小堆 1.3.2 大堆 2. 堆的实现 2.1 插入数据进堆 2.2 向上调整函数 2.3 堆的删除 2.4 向下调整 3. 堆的应用 3.1 建堆(两种方式) 3.1.1 建堆方式1 3.1.2 建堆方式2 3.2 堆排序  3.3 堆的

    2024年02月04日
    浏览(49)
  • 深入浅出对话系统——基于预训练语言模型的对话管理

    主要讲解三篇论文,主要思想是把自然语言理解、对话管理和自然语言生成三部分整合到一起。 数据集 CamRest676 MultiWOZ 都是用的自回归语言模型 causal GPT-2、Transformer Decoder 一个概念:delexicalization 通过相应的占位符替换特定的槽值 占位符作为特定的token,不关心具体的取值

    2024年02月16日
    浏览(74)
  • 深入浅出二叉树— C语言版【数据结构】

    目录 ​编辑 1.树概念及结构 1.1树的概念 1.2 树的相关概念 ​1.3 树的表示 2.二叉树概念及结构   2.1概念 2.2 特殊的二叉树 2.3 二叉树的性质  2.4 简单二叉树题目练习  2.5 二叉树的存储结构 2.5.1 顺序存储——堆 2.5.2 链式存储 树是一种 非线性的数据结构 ,它是由n(n=0)个有

    2024年02月03日
    浏览(78)
  • Git入门图文教程(深入浅出,详细了解Git,以及操作)

    Git是当前最先进、最主流的 分布式 版本控制系统,免费、开源!核心能力就是版本控制。再具体一点,就是面向代码文件的版本控制,代码的任何修改历史都会被记录管理起来,意味着可以恢复到到以前的任意时刻状态。支持跨区域多人协作编辑,是团队项目开发的必备基

    2024年02月08日
    浏览(60)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包