FreeCodeCamp-C-编程初学者笔记-全-

FreeCodeCamp C 编程初学者笔记(全)

001:C语言入门介绍 🚀

在本课程中,我们将学习C语言编程所需的一切基础知识。C语言是一门非常出色的编程语言,也是现存最古老的编程语言之一。实际上,许多现代编程语言都基于C语言。因此,无论你是想学习C语言,还是想为学习C++等语言打下基础,掌握C语言的基础都是一个非常好的选择。

课程内容概述 📚

在本课程中,我们将涵盖所有你需要了解的核心内容。首先,我会介绍如何安装文本编辑器以及如何使用C语言编译器。接着,我们将编写一些基础代码。

上一节我们介绍了课程的整体目标,本节中我们来看看我们将要学习的具体主题。

以下是本课程将涵盖的主要知识点列表:

  • 安装文本编辑器与使用C编译器。
  • 程序是什么以及程序如何工作。
  • C语言如何读取你给出的指令。
  • 更深入的知识,例如条件语句和循环。
  • 创建不同的变量。
  • C语言中可用的不同数据类型。
  • 更高级的主题,例如结构体和函数。
  • 指针的概念。

基本上,我将为你提供一个所有核心概念的完整概述。因此,在本课程结束时,你将拥有一个非常扎实的理解和坚实的基础,可以在此基础上继续深入学习和构建。

我非常高兴能为你们带来这门C语言基础课程,也非常期待你们能深入其中并开始使用这些教程。欢迎随意点击观看所有视频,希望你能学到关于C语言的一些很棒的知识。

002:Windows环境安装指南 🖥️

在本节课中,我们将学习如何在Windows系统上安装C语言编程所需的环境。我们将安装一个集成开发环境(IDE)和一个C编译器,以便开始编写和运行C程序。

概述

为了编写C程序,我们需要两个核心工具:一个用于编写代码的文本编辑器或集成开发环境(IDE),以及一个将C代码转换为计算机可执行指令的编译器。本节教程将指导您完成这两个工具的安装过程。

安装集成开发环境(IDE)

首先,我们需要一个编写C程序的环境。虽然任何文本编辑器都可以,但使用专门的集成开发环境(IDE)会更加方便。IDE是集成了代码编辑、调试和编译等功能的特殊文本编辑器。我们将安装一个名为Code::Blocks的IDE。

以下是安装Code::Blocks的步骤:

  1. 打开您的网页浏览器,访问Google搜索。
  2. 在搜索栏中输入“code blocks”,并找到官方网站 codeblocks.org
  3. 进入网站后,点击导航栏中的“Downloads”(下载)选项。
  4. 在下载页面,选择“Download the binary release”(下载二进制发行版)。这是最简单的安装方式。
  5. 根据您的操作系统(Windows、Linux或Mac)选择相应的版本。本教程以Windows为例。
  6. 在Windows选项下,找到并点击名为“codeblocks-[版本号]-mingw-setup.exe”的链接进行下载。这个安装包同时包含了Code::Blocks IDE和MinGW GCC编译器。

安装C编译器

C语言是一种编程语言,我们编写的代码(指令)需要被“编译”成计算机能够理解的机器语言。编译器就是完成这个转换工作的程序。幸运的是,我们刚才下载的Code::Blocks安装包已经包含了所需的GCC编译器。

以下是完成安装的步骤:

  1. 下载完成后,打开您的“下载”文件夹。
  2. 双击运行下载好的 codeblocks-[版本号]-mingw-setup.exe 安装程序。
  3. 按照安装向导的提示进行操作。建议接受许可协议,并保持所有安装选项为默认设置。
  4. 安装完成后,程序会询问是否运行Code::Blocks,选择运行。
  5. 首次启动时,会弹出“Compiler auto-detection”(编译器自动检测)窗口。选中列表中高亮的“GNU GCC Compiler”选项。
  6. 点击“Set as default”(设为默认),然后点击“OK”(确定)。

至此,Code::Blocks及其内置的C编译器已成功安装。您已经拥有了开始C语言编程所需的一切工具。

总结

本节课我们一起完成了C语言编程环境的搭建。我们首先了解了编写C程序需要IDE和编译器这两个核心工具。接着,我们逐步操作,下载并安装了集成了MinGW GCC编译器的Code::Blocks IDE。在接下来的课程中,我们将学习如何使用这个环境创建并运行您的第一个C程序。

003:Mac系统环境配置 🍎

在本节课程中,我们将学习如何在Mac系统上配置C语言编程环境。主要内容包括安装C编译器与集成开发环境(IDE),为后续编写和运行C程序做好准备。

概述

要在Mac上开始C语言编程,我们需要准备两个核心工具:一个用于编写代码的文本编辑器(特别是集成开发环境IDE),以及一个将C代码转换为计算机可执行指令的C编译器。本节将逐步指导你完成这两项工具的安装与配置。

安装C编译器

首先,我们需要安装C编译器。编译器的作用是将我们编写的、人类可读的C语言代码,翻译成计算机能够理解和执行的机器语言。

在Mac上,我们可以通过终端(Terminal)来检查和安装编译器。终端是一个允许我们使用文本命令与计算机交互的程序。

以下是检查与安装C编译器的步骤:

  1. 打开终端。你可以通过屏幕右上角的搜索栏,输入“terminal”并回车来打开它。
  2. 在终端窗口中,输入命令 cc -v 并回车,以检查是否已安装C编译器。
  3. 如果终端返回了编译器的版本信息(例如包含“clang”字样),说明编译器已安装,你可以跳过安装步骤。
  4. 如果未安装,请输入命令 xcode-select --install 并回车。此命令将安装Xcode的命令行工具,其中包含了C编译器。
  5. 安装完成后,再次输入 cc -v 命令进行验证,此时应能成功看到版本信息。

现在,我们已经成功安装了C编译器。

安装集成开发环境(IDE)

上一节我们介绍了C编译器,本节中我们来看看如何安装一个便于编写和管理C程序的集成开发环境(IDE)。我们将使用一款名为Code::Blocks的免费且流行的IDE。

以下是下载与安装Code::Blocks的步骤:

  1. 打开网页浏览器,访问Code::Blocks官方网站:codeblocks.org
  2. 点击页面上的“Downloads”链接。
  3. 在下载页面中,找到“Binary release”部分,点击“Download the binary release”。
  4. 在操作系统选择区域,点击“Mac OS X”选项。
  5. 页面会显示适用于Mac的安装文件信息。在右侧找到指向Sourceforge的下载链接,点击它。下载将自动开始。
  6. 下载完成后,前往“下载”文件夹,找到下载的ZIP压缩文件(通常名为CodeBlocks-*.zip)。
  7. 双击该ZIP文件进行解压。
  8. 解压后,你会看到一个名为“CodeBlocks”的应用程序图标。将其拖拽到“应用程序”(Applications)文件夹中,即完成安装。

至此,Code::Blocks IDE已安装完毕,你可以随时打开它,开始跟随本课程编写精彩的C程序了。

总结

本节课中我们一起学习了在Mac系统上配置C语言开发环境。我们首先通过终端安装或验证了C编译器,然后下载并安装了Code::Blocks集成开发环境。现在,你的Mac已经具备了编写、编译和运行C程序所需的所有基础工具。在接下来的课程中,我们将开始使用这些工具来探索C语言编程。

004:Hello World 👋

在本节课中,我们将学习如何设置第一个C语言项目,并运行一个简单的“Hello World”程序。通过这个过程,你将熟悉集成开发环境(IDE)的基本操作,并验证你的开发环境是否配置正确。

创建新项目

上一节我们介绍了C语言的基本概念,本节中我们来看看如何在Code::Blocks中创建第一个项目。

首先,打开Code::Blocks程序。这是本课程将一直使用的集成开发环境。双击图标启动程序。

程序打开后,你会看到主界面上有多个选项,例如“创建新项目”或“打开现有项目”。当我们开始编写C语言文件时,需要创建一个新项目。

以下是创建新项目的步骤:

  1. 你可以点击主界面上的“Create a new project”按钮,或者点击顶部菜单栏的 File -> New -> Project
  2. 随后会弹出一个新窗口,其中列出了多种项目类型。我们需要选择 Console application(控制台应用程序)。这是一个可以在你电脑上运行的基础C语言项目,完全符合我们的需求。
  3. 点击 Go 继续,并按照向导的提示进行操作。
  4. 在向导中,你会看到选择编程语言的选项(C或C++)。本课程使用C语言,因此请选中 C,然后点击 Next
  5. 接下来,为项目命名(例如“draft”),并选择一个文件夹来存放项目文件。你可以将其放在桌面上以便查找。
  6. 点击 Finish 完成创建。其他设置可以保持默认。

探索项目文件

现在,我们已经在Code::Blocks中创建了第一个C语言项目。

在左侧的“Management”面板中,你可以看到以项目名(如“draft”)命名的项目。展开项目,你会找到一个名为 Sources 的文件夹。

以下是项目文件的结构:

  • 点开 Sources 文件夹,你会看到一个名为 main.c 的文件。这个文件是Code::Blocks在创建项目时自动为我们生成的。
  • 右键点击 main.c 文件并选择“Open”,即可在编辑器中查看其内容。

打开后,你会看到一些默认的代码。代码顶部有 #include 指令,下方是 int main() 函数。这就是创建C项目时获得的基础程序,也是你能编写的最简单的C程序之一。这个程序的功能是在屏幕上打印出“Hello World”。

编译与运行程序

为了测试程序并确保一切工作正常,我们需要编译并运行它。

在Code::Blocks顶部的工具栏中,找到一个绿色的播放按钮,其提示信息为“Build and run”。点击这个按钮,Code::Blocks就会编译并运行当前打开的 main.c 文件。

首次运行时,可能会弹出一个提示框,显示“The project hasn‘t been built yet. Do you want to build it?”,请点击 Yes

随后,会弹出一个命令行窗口。这是程序运行时的控制台输出窗口。在这个窗口中,你会看到程序执行的结果:屏幕上打印出了 Hello world!

打印信息到屏幕是一个简单的操作,也是我们能给计算机的基本指令之一。随着课程的深入,我们将学习更多复杂的指令。本节课的主要目的是搭建C语言项目并测试 main.c 文件。只要程序能成功运行并打印出“Hello World”,就说明你的开发环境已经准备就绪,可以正式开始学习C语言编程了。

总结

本节课中我们一起学习了如何在Code::Blocks集成开发环境中创建第一个C语言控制台项目,探索了自动生成的项目文件结构,并成功编译运行了经典的“Hello World”程序,验证了开发环境的有效性。这是你C语言编程之旅的第一步。

005:绘制形状 🖼️

在本节课中,我们将学习C语言编程的基础知识,包括如何编写一个简单的程序,理解程序的基本结构,以及如何使用printf函数在屏幕上绘制形状。

概述

上一节我们完成了开发环境的搭建。本节中,我们将深入理解C程序的基本结构,并学习如何通过编写一系列指令来让计算机执行任务,最终我们将使用这些知识在屏幕上绘制一个简单的三角形。

C程序的基本结构

首先,我们来看一个基础的C程序文件。它通常包含以下几个部分:

以下是代码中的关键组成部分:

  1. #include 指令:这些指令位于文件顶部。目前,你只需知道为了使用某些功能(如打印文本),我们需要包含它们。我们将在后续课程中详细讲解其作用。
  2. main 函数:这是一个名为 main 的特殊函数。你可以将其理解为一个容器,用于存放我们的程序代码。当运行C程序时,计算机会自动寻找并执行 main 函数中的所有指令。
  3. 函数体main 函数的内容被包裹在一对花括号 {} 中。所有我们希望计算机执行的指令都写在这里面。

一个典型的 main 函数结构如下:

int main() {
    // 你的代码写在这里
    return 0;
}

程序的编译与运行

在C语言中,从编写代码到程序运行需要两个步骤:

以下是这两个关键步骤:

  1. 编译 (Build/Compile):将我们编写的C语言代码(人类可读)翻译成计算机能够直接理解和执行的机器代码。
  2. 运行 (Run):执行上一步生成的机器代码文件,让计算机开始工作。

在Code::Blocks等集成开发环境中,你可以使用 “构建并运行” 按钮一次性完成这两个步骤,这非常适合在编写代码时快速测试效果。

程序运行后,通常会弹出一个控制台窗口。我们的程序输出的所有信息(比如文字、形状)都会显示在这个窗口中。

编写你的第一条指令:printf

目前,我们掌握的核心指令是 printf。它的作用是在控制台窗口打印文本。

printf 指令的基本格式是:

printf("你想打印的文本");

注意:在C语言中,几乎每一条指令的末尾都必须加上一个分号 ;。这告诉编译器:“这条指令结束了,请开始处理下一条。”

例如,下面的代码会打印两行“Hello World”:

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

其中,\n 是一个特殊字符,代表换行。它的作用是让后续的输出从新的一行开始。

实践:用指令绘制形状 🎨

既然计算机严格按顺序执行指令,我们就可以利用多个 printf 语句,通过打印不同的字符(如 /, |, _)来组合出图形。

上一节我们了解了指令的顺序性。本节中我们来看看如何利用这一点来绘制一个三角形。

以下是绘制一个简单三角形的代码示例:

printf("   /\\\n");
printf("  /  \\\n");
printf(" /    \\\n");
printf("/______\\\n");

代码说明

  • 每一条 printf 打印一行图形。
  • 通过空格调整字符的位置,形成三角形的斜边和底边。
  • 每行末尾的 \n 确保图形换行打印。
  • 在C语言字符串中,要打印一个反斜杠 \ 本身,需要输入两个 \\

当你运行这段程序时,计算机将从第一条 printf 开始,依次执行,最终在屏幕上显示出一个三角形。尝试改变这些行的顺序,你会发现输出的图形会变得混乱,这再次证明了指令顺序至关重要

总结

本节课中我们一起学习了C程序的核心概念。我们了解到,编写C程序就是为计算机定义一系列有序的指令。这些指令被放在 main 函数中,计算机会依次执行它们。我们掌握了使用 printf 指令输出内容的基本方法,并通过一个绘制三角形的有趣例子,实践了如何用多条指令组合完成一个具体任务。记住,分号 ; 是结束指令的标志,而指令的顺序直接决定了程序的运行结果。

006:变量 📦

在本节课中,我们将要学习C语言中一个非常核心的概念——变量。变量是程序中用于存储和表示数据的容器,它能让数据管理变得简单高效。

为什么需要变量?

在编程时,我们经常需要处理各种数据。想象一下,如果每次使用数据时都需要直接写出具体值,当需要修改时,就必须在代码中逐个查找并替换,这将非常繁琐且容易出错。变量通过将数据存储在命名的容器中来解决这个问题,我们只需修改容器中的值,所有引用该变量的地方都会自动更新。

创建和使用变量

上一节我们介绍了变量的必要性,本节中我们来看看如何在C语言中创建和使用变量。

在C语言中,创建一个变量需要告诉编译器两件事:变量要存储什么类型的数据,以及给这个变量起什么名字

以下是创建变量的基本语法格式:

数据类型 变量名 = 初始值;

创建字符串变量

字符串用于存储文本信息,例如一个人的名字。在C语言中,我们使用字符数组来表示字符串。

char characterName[] = "John";
  • char: 表示这是一个字符类型。
  • characterName: 是我们为变量起的名字。
  • []: 方括号表示这是一个字符数组,可以存储多个字符(即字符串)。
  • "John": 是存储在这个变量中的初始值。

创建整数变量

整数用于存储没有小数部分的数字,例如年龄。

int characterAge = 35;
  • int: 表示这是一个整数类型。
  • characterAge: 是变量名。
  • 35: 是存储在这个变量中的初始值。

在程序中使用变量

创建了变量之后,我们如何在程序中使用它们呢?最常见的方式是在printf函数中打印变量的值。

我们需要使用格式说明符作为占位符,告诉printf函数在何处插入变量的值。

以下是使用变量打印信息的示例:

printf("There once was a man named %s.\n", characterName);
printf("He was %d years old.\n", characterAge);
  • %s: 是字符串的格式说明符,它会被characterName变量的值(“John”)替换。
  • %d: 是整数的格式说明符,它会被characterAge变量的值(35)替换。

通过这种方式,我们打印出的故事会动态地使用变量中存储的值。

变量的优势:修改与更新

变量的最大优势在于其可修改性。我们只需在变量声明的地方修改一次值,所有引用该变量的地方都会随之改变。

例如,如果我们想将角色的名字从“John”改为“Tom”,年龄从35改为67,只需这样做:

char characterName[] = "Tom";
int characterAge = 67;

运行程序后,整个故事中所有出现名字和年龄的地方都会自动更新为新的值。这比手动查找并修改每一处要高效得多。

此外,我们还可以在程序运行过程中改变变量的值:

int characterAge = 67; // 初始年龄
printf("He was %d years old.\n", characterAge);

![](https://github.com/OpenDocCN/cs-notes-pt1-zh/raw/master/docs/fcc-c-prog-bgn/img/2fb5d479310a7858220e936ba30627af_11.png)

![](https://github.com/OpenDocCN/cs-notes-pt1-zh/raw/master/docs/fcc-c-prog-bgn/img/2fb5d479310a7858220e936ba30627af_12.png)

characterAge = 30; // 在故事中途修改年龄
printf("He did not like being %d.\n", characterAge);

这段代码会先输出年龄67,然后输出年龄30,展示了变量值在程序生命周期内可以被动态更新。

总结

本节课中我们一起学习了C语言中变量的概念和使用方法。我们了解到:

  1. 变量是数据的容器,用于存储和管理程序中的信息。
  2. 创建变量需要指定数据类型(如int, char[])和变量名
  3. 使用printf输出变量时,需要搭配对应的格式说明符%d用于整数,%s用于字符串)。
  4. 变量的核心优势在于便于维护——只需修改一处定义,即可全局更新数据,并且其值在程序中可以改变

掌握变量是编写任何复杂程序的基础。在接下来的课程中,我们将探索更多其他的数据类型。

C语言编程初学者教程:第七节:数据类型 📚

在本节课中,我们将要学习C语言中的数据类型。编写程序时,我们会处理各种信息,了解这些信息的类型至关重要。本节将介绍C语言中可以表示和使用的不同信息类型,即数据类型。

上一节我们介绍了变量的概念,本节中我们来看看可以存储在变量中的不同数据类型。在C语言中创建变量时,必须告知C语言两个关键信息:一是变量的数据类型,二是变量的名称。首先,我们来探讨最基本的数据类型——数字。

数字类型

C语言中有两种非常重要的数字类型。

  • 整数
    整数即没有小数部分的完整数字,例如1、2、3、40等。在C语言中,我们使用 int 关键字来声明整数变量。

    int age = 40;
    

    使用整数时,直接写出数字即可,无需添加引号等符号。

  • 浮点数
    浮点数是包含小数点的数字,例如2.5、3.7、40.0等。C语言中有 floatdouble 两种浮点类型。对于初学者,通常使用 double 即可,它能提供更高的精度。

    double gpa = 3.7;
    

    请注意,40 是整数,而 40.0 是浮点数。整数和浮点数是编程中最常用的两种数字类型。

字符类型

除了数字,我们还需要存储文本信息。在C语言中,可以使用 char 类型来存储单个字符。

以下是创建字符变量的方法:

char grade = 'A';

字符值必须用单引号括起来,并且只能包含一个字符,例如 ‘A’、‘b’、‘?’ 等。

字符串简介

很多时候,我们需要存储多个字符,即一串文本,这被称为“字符串”。虽然C语言没有内置的“字符串”类型,但我们可以通过字符数组来实现。

以下是创建字符串(字符数组)的基本方法:

char phrase[] = "Hello World";

这里,我们使用 char、变量名、方括号 [] 以及双引号来创建一个字符串。双引号内可以包含任意长度的文本。需要注意的是,这种字符串(字符数组)在行为上与上面介绍的基本数据类型(int, double, char)有所不同,例如其修改方式更特殊,我们将在后续课程中详细讨论数组时深入讲解。

总结

本节课中我们一起学习了C语言的基本数据类型:

  1. 整数:用于表示没有小数部分的数字,使用 int 声明。
  2. 浮点数:用于表示带小数点的数字,初学者推荐使用 double 声明。
  3. 字符:用于表示单个文本字符,使用 char 声明,值用单引号包裹。
  4. 字符串:用于表示一系列字符,通过字符数组 char[] 实现,值用双引号包裹。

掌握这些基本数据类型是构建C语言程序的重要基石。

C语言编程初学者教程:第八节:深入理解printf函数 📝

在本节课中,我们将深入学习C语言中的printf函数。我们将探讨它的基本用法、如何打印不同类型的数据,以及如何利用格式说明符来格式化输出。掌握printf是调试程序和向用户展示信息的关键。


什么是printf函数? 🤔

上一节我们介绍了C程序的基本结构,本节中我们来看看一个核心的输出函数:printf

printf是一个函数,它的主要任务是将信息打印到屏幕上。其基本语法结构如下:

printf("要打印的文本");

例如,执行printf("Hello");会在屏幕上显示“Hello”。


使用特殊字符 ✨

printf的文本中,我们可以使用特殊字符来实现特定效果。

以下是几个常用的特殊字符示例:

  • \n:换行符。例如,printf("Hello\nWorld");会分两行打印“Hello”和“World”。
  • \":打印一个双引号。由于双引号在C语言中用于标记字符串的开始和结束,要打印它本身需要使用转义字符\。例如,printf("She said, \"Hello.\"");

格式说明符与打印数据 🔢

printf的强大之处在于它能打印各种类型的数据,而不仅仅是纯文本。这需要通过格式说明符来实现。

格式说明符以百分号%开头,后跟一个字母,用于指定要打印的数据类型。基本用法如下:

printf("格式字符串", 数据1, 数据2, ...);

在格式字符串中,%所在的位置将被后面提供的数据依次替换。


常用格式说明符列表 📋

以下是几种最常用的格式说明符及其用途:

  • %d:打印整数
    • 示例:printf("My favorite number is %d", 500); 输出:My favorite number is 500
  • %f:打印浮点数(小数)。
    • 示例:printf("The value is %f", 500.9875); 输出:The value is 500.987500
  • %c:打印单个字符
    • 示例:printf("Initial: %c", 'J'); 输出:Initial: J
  • %s:打印字符串(一串文本)。
    • 示例:printf("Hello, %s!", "World"); 输出:Hello, World!


打印变量 🎯

printf结合格式说明符,最常见的用途之一是打印变量的值。

你只需要在格式字符串中放置合适的格式说明符,然后在参数列表中传入变量名即可。

int favoriteNum = 90;
char myChar = 'i';

printf("My favorite number is %d\n", favoriteNum);
printf("My character is %c", myChar);

运行上述代码将输出:

My favorite number is 90
My character is i

总结 🎓

本节课中我们一起学习了printf函数。我们了解了它的基本用法,如何通过特殊字符控制输出格式,以及如何利用%d%f%c%s等格式说明符来打印整数、浮点数、字符和字符串。最重要的是,我们学会了如何打印变量的值,这是在程序运行时获取反馈和进行调试的必备技能。

请多加练习使用printf,它是在编写更复杂程序时极其有用的工具。

009:使用数字 📊

在本节课中,我们将要学习如何在C语言中处理数字。我们将探讨如何存储数字、进行数学运算,以及整数和浮点数之间的交互方式。掌握这些基础知识对于编写任何涉及计算的程序都至关重要。

打印数字

在C语言中,我们可以使用 printf 函数来打印数字。对于浮点数(即带小数点的数字),我们使用格式说明符 %f

printf("%f", 8.9);

执行上述代码会打印出 8.9。C语言默认会以非常高的精度打印浮点数。

基本数学运算

我们可以直接在 printf 函数中进行基本的数学运算,包括加法、减法、乘法和除法。

以下是四种基本运算的示例:

  • 加法:使用加号 +。例如,5.0 + 4.5 的结果是 9.5
  • 减法:使用减号 -
  • 乘法:使用星号 *
  • 除法:使用斜杠 /

整数与浮点数的交互

上一节我们介绍了基本运算,本节中我们来看看当整数和浮点数一起运算时会发生什么。

当一个整数与一个浮点数进行运算时,整个表达式的结果将是一个浮点数。

printf("%f", 5 + 4.5); // 输出 9.5

然而,如果两个整数进行除法运算,结果将只保留整数部分

printf("%d", 5 / 4); // 输出 1,而不是 1.25

要得到完整的十进制结果,至少需要其中一个操作数是浮点数。

printf("%f", 5 / 4.0); // 输出 1.25

将数字存储在变量中

除了直接使用数字,我们还可以将它们存储在变量中,这在处理复杂计算时非常有用。

int num = 6;
printf("%d", num);

使用数学函数

C语言提供了许多内置的数学函数,它们就像可以执行特定任务的小工具。要使用它们,只需调用函数名并传入参数即可。

以下是几个常用的数学函数:

  • pow 函数:用于计算幂。例如,pow(2, 3) 计算2的3次方,结果为 8
  • sqrt 函数:用于计算平方根。例如,sqrt(36) 的结果是 6
  • ceil 函数:用于向上取整。例如,ceil(36.356) 的结果是 37
  • floor 函数:用于向下取整。例如,floor(36.656) 的结果是 36

总结

本节课中我们一起学习了C语言中数字的基本操作。我们掌握了如何打印数字、进行加减乘除运算,理解了整数与浮点数运算时的类型转换规则,学会了将数字存入变量,并介绍了几种实用的内置数学函数。你可以尝试组合使用这些概念,并在线搜索“C math functions”来探索更多功能。

010:注释 📝

在本节课中,我们将要学习C语言中一个非常实用的功能——注释。注释是代码中不会被计算机执行的特殊部分,它允许我们在程序中留下笔记、解释代码逻辑,或者临时禁用某些代码行。

什么是注释?

上一节我们介绍了代码的基本结构,本节中我们来看看如何为代码添加“说明”。在C语言中,注释是一种特殊的代码块。当程序运行时,编译器会完全忽略注释中的所有内容。这意味着你可以在注释中写下任何文字,而不会影响程序的执行。

创建一个注释,需要使用特定的起始和结束标记。在C语言中,多行注释的语法是:

/* 这里是注释内容 */

注释的用途

以下是注释最常见的两种用途:

  1. 为代码添加说明:你可以在复杂的代码行旁边添加注释,解释这段代码的功能或设计思路。这对于你自己日后回顾,或者与其他开发者协作时非常有帮助。
  2. 临时禁用代码:在调试或测试程序时,你可能希望暂时不让某段代码运行。与其直接删除它(之后可能还需要恢复),不如将其“注释掉”。这样,代码依然保留在文件中,但不会被编译执行。

如何使用注释?

让我们通过一个简单的例子来演示。假设我们有以下程序:

#include <stdio.h>

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

为代码添加说明
我们可以在printf语句上方添加一个注释来解释它的作用:

#include <stdio.h>

![](https://github.com/OpenDocCN/cs-notes-pt1-zh/raw/master/docs/fcc-c-prog-bgn/img/947fb87572344f7b94ec6743611111ec_3.png)

![](https://github.com/OpenDocCN/cs-notes-pt1-zh/raw/master/docs/fcc-c-prog-bgn/img/947fb87572344f7b94ec6743611111ec_4.png)

int main() {
    /* 这行代码用于在屏幕上打印问候语 */
    printf("Hello, World!\n");
    return 0;
}

临时禁用代码
如果我们不想执行打印”Hello, World!”的这行代码,可以将其用注释标记包围起来:

#include <stdio.h>

int main() {
    /* printf("Hello, World!\n"); */
    return 0;
}

现在,当我们运行程序时,printf语句将被忽略,程序不会输出任何内容。但代码本身并没有被删除,只需移除注释标记即可轻松恢复其功能。

关于注释的最佳实践

虽然注释非常有用,但通常建议谨慎使用。过多的注释可能会让代码变得杂乱,难以阅读。一般来说,只在以下情况使用注释是良好的实践:

  • 解释一段复杂或不直观的算法逻辑。
  • 注明某段代码的临时性或待办事项(TODO)。
  • 在团队协作中,提供必要的上下文信息。

当然,这只是一个建议。你可以根据项目的实际需要和个人习惯来决定如何使用注释。

总结

本节课中我们一起学习了C语言中的注释。我们了解到,注释是以/*开始、以*/结束的文本块,它不会被编译器执行。注释主要有两个作用:一是为代码添加解释说明,二是临时禁用某些代码行以便调试。合理使用注释可以让你的代码更清晰、更易于维护。

011:常量 📘

在本节课中,我们将要学习C语言中的常量。常量是一种特殊类型的变量,其值在程序运行期间不能被修改。理解常量的概念对于编写更安全、更易维护的代码至关重要。

概述:什么是常量?

常量是C语言中一种特殊的变量,其核心特性是一旦被赋值,就不能再被修改。这意味着,当你创建一个常量并赋予它一个值后,任何试图改变这个值的操作都会导致程序出错。

上一节我们介绍了变量的基本概念,本节中我们来看看如何创建和使用不可变的变量——常量。

如何创建常量变量?

在C语言中,我们使用 const 关键字来声明一个常量。这个关键字可以放在变量类型之前或之后,但通常放在类型之前是一种更常见的做法。

以下是创建一个常量整数的基本语法:

const int NUM = 5;

或者:

int const NUM = 5;

常量与普通变量的对比

为了更好地理解常量的特性,让我们通过一个例子来对比普通变量和常量。

首先,我们创建一个普通的整数变量并修改它:

#include <stdio.h>

int main() {
    // 创建一个普通变量
    int num = 5;
    printf("%d\n", num); // 输出:5

    // 修改这个变量的值
    num = 8;
    printf("%d\n", num); // 输出:8
    return 0;
}

在这个例子中,变量 num 的值被成功地从5修改为8。

现在,让我们尝试将 num 声明为常量并修改它:

#include <stdio.h>

int main() {
    // 创建一个常量变量
    const int NUM = 5;
    printf("%d\n", NUM); // 输出:5

    // 尝试修改常量(这将导致编译错误)
    NUM = 8; // 错误:不能给常量赋值
    printf("%d\n", NUM);
    return 0;
}

当你尝试编译这段代码时,编译器会报错,因为 NUM 是一个常量,其值不能被修改。

常量的命名规范

虽然C语言本身不强制要求,但开发者社区有一个通用的最佳实践:使用全大写字母来命名常量。这样做可以使代码更易读,让人一眼就能看出某个标识符是常量。

例如:

const int FAVORITE_NUMBER = 7;
const float PI = 3.14159;
const char COMPANY_NAME[] = "TechCorp";

这种命名约定有助于区分常量和普通变量,提醒你和其他开发者不要试图修改这些值。

字面量常量

除了使用 const 关键字声明的变量常量外,程序中直接出现的固定值也被称为常量,或更具体地称为“字面量常量”。

以下是几种常见的字面量常量:

  • 整数常量:例如在代码中直接写出的 90-42100
  • 浮点数常量:例如 3.14-0.0012.0
  • 字符常量:用单引号括起来的单个字符,例如 'A''1''$'
  • 字符串常量:用双引号括起来的一系列字符,例如 "Hello, World!""Error: File not found."

例如,在下面的语句中:

printf("Hello");
printf("%d", 70);

"Hello"70 都是字面量常量。它们直接代表了固定的数据,除非你手动修改源代码,否则它们在程序中的值永远不会改变。

为什么要使用常量?

使用常量主要有以下几个好处:

  1. 提高代码安全性:防止重要的值在程序运行时被意外修改,从而避免难以调试的错误。
  2. 提升代码可读性:给一个固定的值起一个有意义的名称(如 PIMAX_USERS),比直接使用数字(如 3.14159100)更容易理解。
  3. 便于维护:如果某个固定值在程序中多个地方被使用,将其定义为常量后,只需在一个地方修改,所有引用该常量的地方都会自动更新。

总结

本节课中我们一起学习了C语言中的常量。我们了解到:

  • 常量是一种值不能被修改的变量。
  • 使用 const 关键字来声明常量,例如 const int VALUE = 10;
  • 常量的命名通常采用全大写字母的约定,以提高代码可读性。
  • 程序中直接出现的固定值(如数字、字符串)被称为字面量常量。
  • 使用常量可以提高程序的安全性、可读性和可维护性。

掌握常量的使用是编写健壮C语言程序的重要一步。在接下来的课程中,我们将继续探索C语言的其他核心概念。

012:获取用户输入 👨‍💻

在本教程中,我们将学习如何在C语言程序中获取用户的输入。许多时候,我们的程序需要处理各种信息,而这些信息常常需要从用户那里获取。我们将学习如何提示用户输入信息,如何将这些信息存储在变量中,并最终在程序中使用它们。

概述

本节我们将学习使用 scanffgets 函数来获取不同类型的用户输入,包括整数、浮点数、字符和字符串。理解这些基本输入操作是构建交互式程序的关键。

获取整数输入

首先,我们来看如何从用户那里获取一个整数。这个过程分为两步:提示用户输入,然后使用 scanf 函数读取输入。

以下是实现步骤:

  1. 使用 printf 函数向用户显示提示信息。
  2. 声明一个整型变量来存储即将输入的值。
  3. 使用 scanf 函数读取用户输入,并将其存储到之前声明的变量中。

让我们通过一个获取年龄的例子来演示:

#include <stdio.h>

int main() {
    int age;
    printf("Enter your age: ");
    scanf("%d", &age);
    printf("You are %d years old.\n", age);
    return 0;
}

在这段代码中:

  • int age; 声明了一个名为 age 的整型变量。
  • scanf("%d", &age); 中的 %d 告诉程序我们期望一个整数输入。&age 中的 & 符号(称为“取地址符”或“指针”)是必需的,它告诉 scanf 将输入的值存储到 age 变量的内存地址中。关于指针的详细内容将在后续教程中讲解。

运行程序后,它会等待你输入一个数字(例如 50),然后输出 You are 50 years old.

获取浮点数(双精度)输入

获取浮点数的过程与获取整数类似,但格式说明符不同。

以下是获取GPA(平均绩点)的示例:

#include <stdio.h>

![](https://github.com/OpenDocCN/cs-notes-pt1-zh/raw/master/docs/fcc-c-prog-bgn/img/db65679198681a3f98e0e35ecaa32aeb_4.png)

![](https://github.com/OpenDocCN/cs-notes-pt1-zh/raw/master/docs/fcc-c-prog-bgn/img/db65679198681a3f98e0e35ecaa32aeb_5.png)

int main() {
    double gpa;
    printf("Enter your GPA: ");
    scanf("%lf", &gpa); // 注意是 %lf
    printf("Your GPA is %f.\n", gpa); // 输出时用 %f
    return 0;
}

关键点:使用 scanf 读取 double 类型时,格式说明符是 %lf(long float的缩写)。而在使用 printf 输出时,格式说明符仍然是 %f。这是一个需要注意的小区别。

运行程序,输入 3.1,程序将输出 Your GPA is 3.1.

获取字符输入

获取单个字符同样简单。

以下是如何获取一个成绩等级的示例:

#include <stdio.h>

int main() {
    char grade;
    printf("Enter your grade: ");
    scanf("%c", &grade);
    printf("Your grade is %c.\n", grade);
    return 0;
}

在这段代码中,%c 是字符的格式说明符。运行程序,输入 A,程序将输出 Your grade is A.

获取字符串输入

获取字符串(一系列字符)输入略有不同,并且有更优的方法。

使用 scanf 获取字符串(及其局限性)

首先,我们看看如何使用 scanf 获取字符串。

#include <stdio.h>

![](https://github.com/OpenDocCN/cs-notes-pt1-zh/raw/master/docs/fcc-c-prog-bgn/img/db65679198681a3f98e0e35ecaa32aeb_17.png)

![](https://github.com/OpenDocCN/cs-notes-pt1-zh/raw/master/docs/fcc-c-prog-bgn/img/db65679198681a3f98e0e35ecaa32aeb_18.png)

int main() {
    char name[20]; // 声明一个能存储最多20个字符的数组
    printf("Enter your name: ");
    scanf("%s", name); // 注意,字符串变量前不需要 &
    printf("Your name is %s.\n", name);
    return 0;
}
  • char name[20]; 声明了一个字符数组(即字符串),它最多可以存储20个字符(包括字符串结束符 \0)。当你不立即给字符串赋值时,需要指定其大小,以便C语言为其分配足够的内存。
  • scanf("%s", name); 中,%s 用于读取字符串。重要:对于字符串变量(数组名),在 scanf 中不需要使用 & 符号,因为数组名本身在大多数情况下就代表了其内存地址。

局限性scanf%s 格式说明符在遇到空格、制表符或换行符时会停止读取。如果你输入 John Smith,程序只会读取 John,因为它在空格处停止了。

使用 fgets 获取整行文本(推荐)

为了解决 scanf 无法读取带空格字符串的问题,我们使用 fgets 函数。

#include <stdio.h>

int main() {
    char name[20];
    printf("Enter your name: ");
    fgets(name, 20, stdin); // 使用 fgets
    printf("Your name is %s", name);
    return 0;
}

  • fgets(name, 20, stdin); 参数解释:
    1. name:用于存储输入字符串的变量。
    2. 20:指定最多读取的字符数(包括最后的 \0)。这可以防止用户输入过长导致“缓冲区溢出”的安全问题。
    3. stdin:代表“标准输入”,通常指键盘。它告诉 fgets 从哪里获取输入。

现在,如果你输入 John Smith,程序将能完整地读取并输出。

注意fgets 会存储你按下回车键(Enter)时产生的换行符 \n。所以输出可能会多出一行。在实际应用中,你可能需要手动移除这个多余的换行符。

总结

本节课我们一起学习了在C语言中获取用户输入的基础知识:

  1. 使用 scanf 函数可以方便地获取整数%d)、浮点数%lf)和单个字符%c)。对于这些基本类型,需要在变量前使用 & 符号。
  2. 获取字符串时,scanf%s 无法处理包含空格的输入。
  3. 因此,获取字符串输入推荐使用 fgets 函数,它可以读取整行文本(包括空格),并且更安全,可以指定最大输入长度以防止缓冲区溢出。

掌握这些输入方法是创建交互式程序的第一步。你可以尝试在自己的程序中组合使用这些方法,例如同时询问用户的姓名、年龄和GPA。在后续教程中,我们还将探讨处理用户输入的更多高级技巧。

013:构建基本计算器 🧮

在本节课中,我们将学习如何使用C语言构建一个基础的计算器程序。我们将创建一个程序,允许用户输入两个数字,程序会将这两个数字相加并输出结果。通过这个过程,我们将学习如何从用户那里获取数字输入。

概述

我们将编写一个程序,它首先提示用户输入两个数字,然后使用 scanf 函数获取这些输入,将它们存储在变量中,最后进行加法运算并打印结果。我们还将探讨如何处理整数和浮点数(小数)的输入。

构建计算器步骤

1. 提示用户输入

首先,我们需要提示用户输入第一个数字。我们将使用 printf 函数来显示提示信息。

以下是实现此步骤的代码:

printf("请输入第一个数字:");

2. 获取并存储用户输入

接下来,我们需要获取用户输入的数字并将其存储起来。为此,我们将使用 scanf 函数。我们需要先声明两个变量来存储这些数字。

以下是声明变量和获取第一个数字输入的代码:

double num1;
scanf("%lf", &num1);

注意:当使用 scanf 读取非字符串类型(如整数 %d、浮点数 %lf、字符 %c)时,必须在变量名前加上 & 符号(取地址符)。这涉及到内存地址和指针的概念,我们将在后续课程中详细讲解。目前只需记住,为了将输入的值存储到变量中,这是必需的。

3. 获取第二个数字

获取第二个数字的步骤与第一个完全相同。

以下是相应的代码:

printf("请输入第二个数字:");
double num2;
scanf("%lf", &num2);

4. 进行计算并输出结果

现在我们已经有了两个数字,可以将它们相加并打印出答案了。

以下是进行计算和输出的代码:

printf("答案是:%f\n", num1 + num2);

注意:在 printf 函数中打印双精度浮点数时,我们使用 %f 格式说明符。这与 scanf 中使用的 %lf 有所不同。

完整代码示例

将以上所有步骤组合起来,就得到了我们基础计算器的完整代码:

#include <stdio.h>

int main() {
    double num1;
    double num2;

    printf("请输入第一个数字:");
    scanf("%lf", &num1);

    printf("请输入第二个数字:");
    scanf("%lf", &num2);

    printf("答案是:%f\n", num1 + num2);

    return 0;
}

程序运行示例

运行上述程序,你可能会看到如下交互过程:

请输入第一个数字:4.5
请输入第二个数字:6.7
答案是:11.200000

程序正确地将 4.5 和 6.7 相加,得到了 11.2。

当前程序的局限性

需要指出的是,我们构建的这个计算器程序还非常基础。例如,如果用户没有输入数字,而是输入了字母或单词,程序将无法正确处理,可能会导致运行错误或输出无意义的结果。

随着课程的深入,我们将学习各种方法来验证用户输入是否正确,并处理各种意外情况,从而使程序更加健壮。

总结

在本节课中,我们一起学习了如何构建一个基础的C语言计算器。我们掌握了以下核心技能:

  • 使用 printf 输出提示信息。
  • 使用 scanf 获取用户输入的数字,并理解了对非字符串类型使用 & 符号的必要性。
  • 区分了在 scanfprintf 中处理双精度浮点数 (double) 的不同格式说明符 (%lf%f)。
  • 将输入的值存储在变量中并进行基本的算术运算。

你现在已经拥有了一个可以处理小数加法的基本计算器程序。这是处理用户输入和进行数学运算的重要第一步。

014:构建Mad Libs游戏 🎮

在本节课中,我们将学习如何使用C语言构建一个简单的文字游戏——Mad Libs。我们将通过这个项目,进一步练习使用scanf函数从用户那里获取输入,并将输入的数据整合到一个故事中。


概述

Mad Libs是一种填空游戏。玩家需要提供一些特定类型的词语(如名词、动词、颜色、名人等),这些词语随后会被填入一个预设的故事模板中,从而生成一个通常很滑稽的新故事。

我们将创建一个程序,让用户输入一种颜色、一个复数名词和一位名人的名字,然后用这些词填充一首经典的小诗。


创建变量存储用户输入

首先,我们需要创建变量来存储用户将要输入的信息。由于这些信息是词语(字符串),我们需要使用字符数组来存储它们。同时,我们需要指定数组的大小,以便C语言知道需要分配多少内存。

以下是创建三个字符数组变量的代码,每个数组最多能存储20个字符(包括字符串结尾的空字符\0):

char color[20];
char pluralNoun[20];
char celebrity[20];

获取用户输入

上一节我们介绍了变量的创建,本节中我们来看看如何从用户那里获取输入。我们需要使用printf函数提示用户,然后使用scanf函数接收输入并将其存储到我们创建的变量中。

以下是提示用户并获取输入的代码:

printf("Enter a color: ");
scanf("%s", color);

printf("Enter a plural noun: ");
scanf("%s", pluralNoun);

printf("Enter a celebrity: ");
scanf("%s", celebrity);

注意:当使用scanf读取字符串时,我们不需要在变量名前使用&符号。数组名本身就可以作为其首地址使用。


构建并输出故事

现在我们已经获取了所有用户输入,接下来需要将它们填入我们的故事模板中。我们将使用printf函数,并用%s占位符来插入字符串变量。

以下是输出最终故事的代码:

printf("Roses are %s\n", color);
printf("%s are blue\n", pluralNoun);
printf("I love %s\n", celebrity);

测试程序

让我们运行程序,看看效果。假设用户输入如下:

  • 颜色:magenta
  • 复数名词:microwaves
  • 名人:Prince

程序将输出:

Roses are magenta
microwaves are blue
I love Prince

程序运行成功!我们成功获取了用户输入,并将其整合到了故事中。


处理输入中的空格

然而,我们的程序存在一个限制。scanf函数在读取字符串时,会在遇到第一个空白字符(如空格、制表符)时停止。这意味着如果用户输入的名人名字包含空格(例如“Tom Hanks”),程序只会读取“Tom”。

为了解决这个问题,我们可以将名人的输入拆分为两个部分:名和姓。

以下是修改后的变量声明和输入获取代码:

char color[20];
char pluralNoun[20];
char celebrityF[20]; // 名
char celebrityL[20]; // 姓

printf("Enter a color: ");
scanf("%s", color);

printf("Enter a plural noun: ");
scanf("%s", pluralNoun);

printf("Enter a celebrity (first and last name): ");
scanf("%s %s", celebrityF, celebrityL); // 读取两个以空格分隔的字符串

相应地,输出语句也需要修改:

printf("Roses are %s\n", color);
printf("%s are blue\n", pluralNoun);
printf("I love %s %s\n", celebrityF, celebrityL);

现在,当用户输入“Tom Hanks”时,程序就能正确输出全名了。


关于scanf的注意事项

这个修改也带来了新的考量。现在程序强制要求用户输入两个词作为名人的名字。如果用户只想输入一个词(例如“Gandhi”),程序会等待用户输入第二个词,这可能导致体验不佳。

这说明了在使用scanf时,程序员必须非常明确地规定用户输入的格式。你需要根据程序的实际需求来设计输入逻辑。


总结

本节课中我们一起学习了如何构建一个简单的Mad Libs游戏。我们回顾了以下核心概念:

  1. 使用字符数组(如char variable[20])声明字符串变量。
  2. 使用printfscanf("%s", variableName)获取用户输入的字符串。
  3. 理解scanf在读取字符串时遇到空格会停止的特性。
  4. 通过使用多个%s格式符(如scanf("%s %s", var1, var2))来读取包含空格的输入。

通过这个项目,你不仅练习了基本的输入输出操作,还了解了处理用户输入时需要考虑的细节。

015:数组 📚

在本节课中,我们将要学习C语言中一个非常重要的概念——数组。很多时候,当我们编写C程序时,需要处理大量相关的数据。为了有效地控制、管理和组织这些数据,我们可以使用数组。数组就像一个容器,可以存储多个数据值,这比创建大量单独的变量要高效得多。

什么是数组?🤔

上一节我们介绍了变量的基本概念。本节中我们来看看数组。数组本质上是一种数据结构,它允许我们在一个容器中存储多个数据值。与只能存储一个值的变量不同,一个数组可以存储成百上千甚至数百万个值。例如,你可以在一个数组中存储5个、7个、10个数字或20个字符,从而让程序中的数据变得整洁有序。

如何创建数组?🔨

创建数组与创建变量非常相似。变量用于定义一个存储单个值的容器,而数组用于定义一个可以存储任意数量值的容器。

创建数组时,首先需要告诉C语言我们想要在数组中存储什么类型的数据。例如:

  • int:创建一个存储整数的数组。
  • char:创建一个存储字符的数组。
  • double:创建一个存储双精度浮点数的数组。

以下是创建数组的最简单方法,即在声明时直接初始化其值:

int luckyNumbers[] = {4, 8, 15, 16, 23, 42};

在这行代码中:

  • int 指定了数组存储整数。
  • luckyNumbers 是数组的名称。
  • [] 方括号告诉C语言这是一个数组。
  • {4, 8, 15, 16, 23, 42} 花括号内是用逗号分隔的初始值列表。

如何访问和修改数组元素?🔍

所有存储在数组中的数据都被称为元素。为了访问特定的元素,我们需要使用元素的索引

在C语言中,数组的索引从 0 开始计数。这意味着:

  • 第一个元素(4)的索引是 0
  • 第二个元素(8)的索引是 1
  • 第三个元素(15)的索引是 2,依此类推。

我们可以通过数组名后跟方括号和索引来访问元素:

printf("%d", luckyNumbers[0]); // 这将打印出 4
printf("%d", luckyNumbers[2]); // 这将打印出 15

我们也可以像修改变量一样修改数组中的元素:

luckyNumbers[1] = 200; // 将索引1的元素(原来的8)修改为200
printf("%d", luckyNumbers[1]); // 现在将打印出 200

从概念上讲,数组就像存储了一堆没有独立名称的变量,你可以通过索引来操作它们。

如何创建空数组?📦

有时,我们在创建数组时可能还不知道要存储哪些具体值。这时,我们可以先创建一个指定容量的空数组。

以下是创建空数组的方法:

int luckyNumbers[10];

在这行代码中:

  • [10] 指定了这个整数数组最多可以容纳 10 个元素。
  • C语言会根据这个信息为数组分配足够的内存空间。

之后,我们可以再为特定索引位置的元素赋值:

luckyNumbers[1] = 80;
luckyNumbers[0] = 90;
printf("%d", luckyNumbers[1]); // 打印出 80

需要注意的是,如果尝试访问一个尚未被赋值的元素(例如初始状态下的 luckyNumbers[0]),可能会得到一个不可预知的值(在演示中显示为-2),因为它对应的内存位置还没有被初始化。

字符串就是字符数组 🧵

现在,我们可以重新审视一个之前已经使用过但未深入解释的概念:字符串

在C语言中,字符串实际上就是字符数组。例如:

char phrase[] = "Draft Academy";
// 或者
char phrase[20];

当我们创建一个字符串时,本质上就是在创建一个 char 类型的数组。C语言为了方便我们处理文本,对字符数组(字符串)提供了一些特殊的语法支持(比如用双引号初始化),但其底层原理仍然是数组。理解这一点,能让你更清楚地知道字符串是如何工作的。

总结 📝

本节课中我们一起学习了C语言中的数组。我们了解到数组是一种用于存储多个相同类型数据的数据结构。我们学习了如何创建和初始化数组,如何通过从0开始的索引来访问和修改数组中的元素,以及如何先声明一个指定大小的空数组。最后,我们还揭示了字符串的本质其实就是字符数组。掌握数组是组织和管理程序数据的关键一步。

016:函数 🧩

在本节课中,我们将要学习C语言中一个非常核心的概念——函数。函数本质上是一段执行特定任务的代码集合。通过将代码组织成函数,我们可以让程序结构更清晰,代码更易于复用和维护。

概述:什么是函数?

函数是执行特定任务的代码块。你可以将多行代码(例如五、六行甚至二十行)放入一个函数中。当你需要执行这些代码时,只需“调用”该函数即可。通常,我们会根据函数要完成的任务来为其命名。

上一节我们介绍了程序的基本结构,本节中我们来看看如何创建和使用函数。

创建你的第一个函数

实际上,我们一直在使用一个特殊的函数:main函数。main函数是程序开始运行时自动执行的函数。但我们可以创建自己的函数。

要创建一个函数,我们需要告诉C语言两件事:

  1. 函数的返回类型:即函数执行完毕后会返回什么类型的数据。目前我们先使用void,表示该函数不返回任何信息。
  2. 函数的名称:通常根据函数的功能来命名。

以下是创建一个简单函数的步骤:

void sayHi() {
    printf("Hello user\n");
}
  • void 是返回类型。
  • sayHi 是函数名。
  • 大括号 {} 内的代码是函数体,即函数要执行的操作。

调用函数

仅仅定义函数,其中的代码并不会自动执行。我们必须“调用”它。调用函数意味着告诉C语言去执行该函数内部的所有代码。

调用函数的方法很简单:写下函数名,后面加上一对圆括号 ()

int main() {
    sayHi(); // 调用 sayHi 函数
    return 0;
}

程序执行时,会先运行main函数,当遇到sayHi();这行代码时,就会跳转到sayHi函数的定义处,执行其内部的printf语句,然后再返回到main函数继续执行后续代码。

为函数添加参数

函数可以接收外部传入的信息,这称为参数。参数使得函数更加灵活和强大。

例如,我们可以改造sayHi函数,让它向特定的人问好:

void sayHi(char name[]) {
    printf("Hello %s\n", name);
}

现在,sayHi函数需要一个类型为char[](字符串)的参数,我们将其命名为name。在函数体内,我们可以使用这个name变量。

调用带参数的函数时,必须在括号内提供一个对应类型的值:

int main() {
    sayHi("Mike");
    sayHi("Tom");
    sayHi("Oscar");
    return 0;
}

这样,同一个函数就能根据我们传入的不同参数,输出不同的问候语。

使用多个参数

函数可以接受多个参数。你只需要在定义函数时,在括号内按顺序声明它们,并用逗号分隔。

以下是带两个参数的函数示例:

void sayHi(char name[], int age) {
    printf("Hello %s, you are %d\n", name, age);
}

调用时,也需要按顺序提供两个对应的值:

int main() {
    sayHi("Mike", 40);
    sayHi("Tom", 23);
    sayHi("Oscar", 70);
    return 0;
}

总结

本节课中我们一起学习了C语言函数的基础知识:

  • 函数是执行特定任务的代码块
  • 使用函数可以使代码模块化、易于复用
  • 创建函数需要指定返回类型函数名
  • 函数内的代码需要通过调用函数来执行。
  • 函数可以接收参数,这使函数能根据不同的输入执行相应的操作。
  • 一个函数可以定义多个参数,调用时必须按顺序提供所有参数的值。

理解函数是掌握结构化编程的关键。在下一节中,我们将深入探讨函数的返回类型,学习如何让函数将计算结果等信息返回给调用者。

017:return语句详解 🧮

在本节课中,我们将要学习C语言中return语句的用法。return语句是函数中的一行特殊代码,它允许函数将信息返回给调用者。通过return语句,函数可以返回操作结果、状态信息或其他任何数据。

概述

return语句在函数中扮演着重要角色。它不仅能将数据返回给调用者,还会立即终止函数的执行。本节将通过创建一个计算数字立方的函数,详细讲解return语句的使用方法、注意事项以及函数原型的概念。

创建返回值的函数

上一节我们介绍了无返回值的函数,本节中我们来看看如何创建有返回值的函数。首先需要明确函数的返回类型,这决定了函数将返回什么类型的数据。

以下是创建立方计算函数的步骤:

  1. main函数上方定义函数,确保在调用前函数已被声明。
  2. 指定返回类型为double,函数名为cube
  3. 函数接受一个double类型的参数num
  4. 在函数体内计算num的立方值。
  5. 使用return语句将计算结果返回。

对应的函数定义如下:

double cube(double num) {
    double result = num * num * num;
    return result;
}

或者,可以简化代码,直接返回表达式的结果:

double cube(double num) {
    return num * num * num;
}

调用带返回值的函数

定义好函数后,我们可以在main函数中调用它。由于cube函数返回一个double类型的值,我们可以直接将函数调用放在printf语句中打印结果。

以下是调用函数的示例代码:

#include <stdio.h>

int main() {
    printf("Answer: %f\n", cube(3.0));
    printf("Answer: %f\n", cube(7.0));
    return 0;
}

运行程序后,控制台将输出:

Answer: 27.000000
Answer: 343.000000

return语句的重要特性

return语句有一个关键特性:一旦执行,它会立即结束当前函数的执行,并将控制权交还给调用者。

这意味着,在return语句之后的任何代码都不会被执行。例如,在下面的函数中,printf("Here\n");这行代码永远不会执行。

double cube(double num) {
    return num * num * num;
    printf("Here\n"); // 这行代码永远不会执行
}

函数原型

有时,我们希望将函数定义放在main函数之后,以提高代码的可读性。但是,如果直接这样做,编译器在main函数中遇到函数调用时,会因找不到函数声明而报错。

为了解决这个问题,C语言引入了函数原型的概念。函数原型只包含函数的返回类型、名称和参数列表,并以分号结尾,它告诉编译器函数的存在及其格式。

以下是使用函数原型的示例:

#include <stdio.h>

// 函数原型
double cube(double num);

![](https://github.com/OpenDocCN/cs-notes-pt1-zh/raw/master/docs/fcc-c-prog-bgn/img/c01e1a9a6907e6c163d05278a2347f9d_6.png)

int main() {
    printf("Answer: %f\n", cube(3.0));
    return 0;
}

// 实际的函数定义放在main函数之后
double cube(double num) {
    return num * num * num;
}

通过添加函数原型double cube(double num);,即使函数定义在main函数之后,程序也能正确编译和运行。

总结

本节课中我们一起学习了C语言return语句的核心用法。我们了解到:

  • return语句用于从函数中返回一个值。
  • 它会使函数立即终止,其后的代码不会执行。
  • 在调用函数之前,必须先让编译器知道函数的存在,可以通过在main函数之前定义函数,或者使用函数原型来实现。

掌握return语句是编写模块化、可重用代码的基础,它允许函数进行计算并将结果反馈给程序的其他部分。

018:if语句详解 🧠

在本节课中,我们将要学习C语言中一个非常核心的结构——if语句。if语句能让我们的程序根据不同的条件做出决策,从而执行不同的代码块。这是一种为程序增添“智能”的强大工具。

概述

我们将通过构建一个名为 max 的函数来学习if语句。这个函数最初会比较两个数字的大小并返回较大的那个。之后,我们会扩展它,使其能够比较三个数字,并在这个过程中学习 else if、逻辑运算符(&&||)以及比较运算符等更多概念。

构建基础的双参数max函数

首先,我们创建一个函数,它接收两个整数作为参数,并返回其中较大的一个。

int max(int num1, int num2) {
    int result;
    if(num1 > num2) {
        result = num1;
    } else {
        result = num2;
    }
    return result;
}

代码解析:

  1. 函数 max 接收两个整型参数 num1num2
  2. 我们声明一个整型变量 result 来存储结果。
  3. if 语句检查条件 num1 > num2
    • 如果条件为,则执行花括号 {} 内的代码,将 num1 赋值给 result
    • 如果条件为,程序会跳过 if 块,执行 else 块内的代码,将 num2 赋值给 result
  4. 最后,函数返回 result

main 函数中调用它:

printf("%d", max(4, 10)); // 输出:10
printf("%d", max(40, 10)); // 输出:40
printf("%d", max(40, 40)); // 输出:40

这个简单的 if-else 结构已经能有效处理两个数的比较。

扩展为三参数max函数

上一节我们介绍了如何比较两个数,本节中我们来看看如何比较三个数。这需要更复杂的条件判断。

我们需要修改 max 函数以接收三个参数,并找出其中的最大值。

int max(int num1, int num2, int num3) {
    int result;
    if(num1 >= num2 && num1 >= num3) {
        result = num1;
    } else if(num2 >= num1 && num2 >= num3) {
        result = num2;
    } else {
        result = num3;
    }
    return result;
}

代码解析:

  1. 函数现在接收三个参数:num1, num2, num3
  2. 第一个 if 条件使用了逻辑与运算符 &&
    • 条件 num1 >= num2 && num1 >= num3 意味着:仅当 num1 同时大于等于 num2 大于等于 num3 时,整个表达式才为真。此时 num1 最大。
  3. 如果第一个 if 条件为假,程序会检查 else if 条件。
    • else if 允许我们在第一个条件不满足时,检查另一个条件。这里检查 num2 是否同时是最大的。
  4. 如果前两个条件都为假,则执行最后的 else 块,此时 num3 必然是最大的。
  5. 以下是调用示例:
    printf("%d", max(1, 2, 3)); // 输出:3
    printf("%d", max(10, 5, 2)); // 输出:10
    

逻辑运算符与比较运算符

在构建三参数函数时,我们使用了 &&(逻辑与)。除了它,还有另一个重要的逻辑运算符 ||(逻辑或)。同时,我们也接触了多种比较运算符。

以下是常用的比较与逻辑运算符:

  • 比较运算符
    • > 大于
    • < 小于
    • >= 大于或等于
    • <= 小于或等于
    • == 等于(注意:双等号用于比较,单等号 = 用于赋值)
    • != 不等于
  • 逻辑运算符
    • && (逻辑与):两个条件都为真时,整个表达式为真。
    • || (逻辑或):至少一个条件为真时,整个表达式为真。

让我们通过几个简单的例子来理解它们的区别:

// 使用 &&
if (3 > 2 && 2 > 5) { // 条件1为真,条件2为假 => 整体为假
    printf("True with &&\n");
} else {
    printf("False with &&\n"); // 会执行这行
}

// 使用 ||
if (3 > 2 || 2 > 5) { // 条件1为真,条件2为假 => 整体为真(因为用了||)
    printf("True with ||\n"); // 会执行这行
}

取反运算符

有时我们需要检查某个条件是否“不成立”。这时可以使用取反运算符 !

if (3 > 2) { // 条件为真
    printf("3 > 2 is true.\n");
}

![](https://github.com/OpenDocCN/cs-notes-pt1-zh/raw/master/docs/fcc-c-prog-bgn/img/efcbb718d249e309eb018e7c5d076766_8.png)

if (!(3 > 2)) { // 对真条件取反,变为假
    printf("This won't print.\n");
}

![](https://github.com/OpenDocCN/cs-notes-pt1-zh/raw/master/docs/fcc-c-prog-bgn/img/efcbb718d249e309eb018e7c5d076766_10.png)

if (!(3 < 2)) { // 对假条件取反,变为真
    printf("3 is NOT less than 2.\n"); // 会执行这行
}

! 运算符放在一个条件或表达式之前,会将其布尔值反转(真变假,假变真)。

总结

本节课中我们一起学习了C语言中 if语句 的核心用法。我们从最简单的 if-else 开始,构建了一个比较两个数字的函数。然后,我们将其扩展为比较三个数字,并引入了 else if 来进行多重条件判断。

在这个过程中,我们详细讲解了:

  • 逻辑运算符 && (与) 和 || (或) 的用法与区别。
  • 完整的比较运算符集合:>, <, >=, <=, ==, !=
  • 取反运算符 ! 的用法,它可以将一个条件的结果反转。

掌握if语句和这些运算符,是编写能够做出判断和响应的智能程序的关键一步。

019:构建更好的计算器 🧮

在本节课中,我们将学习如何使用C语言构建一个功能更完善的四则运算计算器。我们将利用之前学过的知识,如变量、用户输入和条件判断语句,来实现一个可以让用户选择进行加、减、乘、除运算的程序。


概述

在本教程中,我们将创建一个交互式计算器。程序会提示用户依次输入两个数字和一个运算符(+、-、*、/),然后根据运算符执行相应的数学运算并输出结果。如果用户输入了无效的运算符,程序会给出错误提示。


第一步:声明变量

首先,我们需要创建变量来存储用户输入的数字和运算符。我们将使用 double 类型来存储数字,以确保可以处理小数。使用 char 类型来存储单个字符的运算符。

double num1;
double num2;
char op;

第二步:获取用户输入

接下来,我们需要从用户那里获取输入。这包括第一个数字、运算符和第二个数字。

以下是获取用户输入的步骤:

  1. 获取第一个数字:使用 printf 函数提示用户,然后使用 scanf 函数将输入的值存储到 num1 变量中。
  2. 获取运算符:再次提示用户,并使用 scanf 获取一个字符。注意:在 scanf 中读取字符时,需要在 %c 前加一个空格,以避免读取到之前输入留下的换行符。
  3. 获取第二个数字:与获取第一个数字的方法相同。
printf("Enter a number: ");
scanf("%lf", &num1);

printf("Enter an operator: ");
scanf(" %c", &op); // 注意%c前的空格

printf("Enter another number: ");
scanf("%lf", &num2);

第三步:使用条件语句执行运算

现在,我们已经拥有了所有必要的数据。我们需要根据用户输入的运算符来决定执行哪种运算。这里非常适合使用 if 语句。

我们将检查 op 变量中存储的字符,并执行相应的计算:

  • 如果运算符是 +,则执行加法。
  • 如果运算符是 -,则执行减法。
  • 如果运算符是 *,则执行乘法。
  • 如果运算符是 /,则执行除法。
  • 如果运算符是其他任何字符,则输出错误信息。
if(op == '+'){
    printf("%f", num1 + num2);
}
else if(op == '-'){
    printf("%f", num1 - num2);
}
else if(op == '*'){
    printf("%f", num1 * num2);
}
else if(op == '/'){
    printf("%f", num1 / num2);
}
else {
    printf("Invalid Operator");
}

程序运行示例

让我们看看这个程序是如何工作的。

  • 示例 1:加法

    • 输入:5.9, +, 4.0
    • 输出:9.9
  • 示例 2:乘法

    • 输入:6, *, 5.7
    • 输出:34.2

  • 示例 3:无效运算符
    • 输入:5.7, g, 8
    • 输出:Invalid Operator

总结

在本节课中,我们一起构建了一个功能完整的四则运算计算器。我们回顾并应用了以下几个核心概念:

  1. 变量声明:使用 doublechar 类型存储数据。
  2. 用户输入:使用 scanf 函数获取数字和字符输入,并注意了读取字符时的特殊格式。
  3. 条件逻辑:使用 ifelse ifelse 语句根据不同的运算符执行不同的代码块,使程序能够智能地响应各种情况。

通过这个练习,你不仅巩固了基础知识,还学会了如何将这些知识组合起来解决一个实际问题。尝试修改这个程序,比如让它能够连续计算,或者增加更多运算功能(如求余数)吧!

020:switch语句 🎯

在本节课中,我们将要学习C语言中的switch语句。switch语句是一种特殊的条件判断结构,它允许我们将一个值与多个不同的值进行比较,并根据匹配的结果执行相应的代码块。通过学习switch语句,我们可以编写更简洁、更易读的条件判断代码。

概述

switch语句本质上是一种特殊的if语句,它专门用于将一个特定值与多个可能的值进行比较。与使用多个if-else if语句相比,switch语句在结构上更加清晰,特别适合处理多个离散值的匹配情况。本节我们将通过构建一个简单的成绩评级程序来演示switch语句的用法。

switch语句的基本结构

上一节我们介绍了条件判断的基本概念,本节中我们来看看如何使用switch语句来简化多条件判断。

switch语句的基本语法结构如下:

switch (expression) {
    case constant1:
        // 代码块1
        break;
    case constant2:
        // 代码块2
        break;
    // 更多case...
    default:
        // 默认代码块
}

在这个结构中:

  • expression 是需要进行判断的变量或表达式。
  • case 后面跟着一个常量值,用于与expression的结果进行比较。
  • 如果某个case的值与expression匹配,则执行该case后面的代码块。
  • break 语句用于退出整个switch结构,防止继续执行后面的case
  • default 是可选的,当没有任何case匹配时,会执行default后面的代码块,类似于if-else结构中的else

构建成绩评级程序

现在,让我们使用switch语句来构建一个程序。这个程序会根据一个表示成绩等级的字符变量,输出对应的评价信息。

首先,我们创建一个字符变量来存储成绩等级:

char grade = 'A';

接下来,我们编写switch语句来对这个成绩进行判断。以下是判断逻辑的步骤:

  1. 判断成绩是否为'A',如果是,则输出“你做得很棒!”。
  2. 判断成绩是否为'B',如果是,则输出“你做得不错!”。
  3. 判断成绩是否为'C',如果是,则输出“你做得不太好。”。
  4. 判断成绩是否为'D',如果是,则输出“你做得很差。”。
  5. 判断成绩是否为'F',如果是,则输出“你不及格。”。
  6. 如果成绩不是以上任何有效等级,则输出“无效的成绩。”。

以下是实现上述逻辑的代码:

#include <stdio.h>

int main() {
    char grade = 'A'; // 可以修改这个值来测试不同的情况

    switch (grade) {
        case 'A':
            printf("你做得很棒!\n");
            break;
        case 'B':
            printf("你做得不错!\n");
            break;
        case 'C':
            printf("你做得不太好。\n");
            break;
        case 'D':
            printf("你做得很差。\n");
            break;
        case 'F':
            printf("你不及格。\n");
            break;
        default:
            printf("无效的成绩。\n");
    }

    return 0;
}

程序运行与测试

我们可以通过修改变量grade的初始值来测试程序的不同分支。

  • grade = 'A' 时,程序输出:你做得很棒!
  • grade = 'C' 时,程序输出:你做得不太好。
  • grade = 'F' 时,程序输出:你不及格。
  • grade = 'Z' 时,程序输出:无效的成绩。

switch语句的注意事项

在使用switch语句时,有几个关键点需要注意:

  • break语句的重要性:每个case代码块末尾的break语句至关重要。如果省略break,程序会继续执行下一个case的代码块,直到遇到breakswitch结束。这种现象称为“穿透”(fall-through),除非有意为之,否则通常需要避免。
  • 适用场景switch语句最适合用于将一个变量与一系列离散的常量值进行比较。对于范围判断(如 x > 10)或复杂的布尔表达式,使用if-else语句更为合适。
  • default分支:使用default分支来处理所有未匹配的情况,可以使程序更加健壮。

总结

本节课中我们一起学习了C语言中的switch语句。我们了解到switch是一种用于多路分支选择的高效结构,它通过比较一个表达式与多个case常量来决定执行路径。我们通过一个成绩评级程序的实例,掌握了switch语句的基本语法、casebreak的用法,以及可选的default分支。虽然switch并非适用于所有条件判断场景,但在处理多个离散值匹配时,它能显著提升代码的清晰度和可维护性。

021:结构体 🏗️

在本节课中,我们将要学习C语言中的结构体。结构体是一种强大的数据结构,它允许我们将不同类型的数据组合在一起,形成一个单一的、有意义的单元。通过学习结构体,你将能够更好地组织和处理程序中的数据。

什么是结构体?

上一节我们介绍了数组,它用于存储相同类型的数据集合。本节中我们来看看结构体。结构体是一种数据结构,我们可以用它来存储不同类型的数据组。例如,在一个结构体内部,我们可以存储一个整数、一个字符串、一个字符和一个双精度浮点数。我们可以将所有不同的数据类型存储在单一的数据结构中。

结构体有非常多的用途,其中一项就是模拟现实世界的实体。我们可以在程序中模拟现实世界中的事物。在本教程中,我将向大家展示如何做到这一点。

使用结构体表示学生

我们将学习如何使用结构体在程序中表示一个学生。假设我们正在编写一个使用学生信息的软件,例如存储学生记录。我们可以使用结构体在程序中表示一个学生。

在程序中,我将在main函数上方创建一个结构体。你会看到它们如何工作以及我们如何使用它们。

以下是定义一个名为Student的结构体的方法:

struct Student {
    char name[50];
    char major[50];
    int age;
    double gpa;
};

在这个结构体中,我开始指定构成程序中一个学生的数据类型。基本上,我可以定义学生的不同属性并将它们放在这里。这将作为一种模板,稍后你会看到如何使用它。

让我们思考学生的不同属性:

  • 姓名:使用字符数组char name[50]表示,最多可容纳50个字符。
  • 专业:同样使用char major[50]
  • 年龄:使用整数int age
  • GPA:使用双精度浮点数double gpa

这样,我就创建了一个Student数据类型。我基本上允许自己在程序中表示一个学生。

创建和使用结构体变量

现在,让我们进入main函数,看看如何使用这个结构体。我可以创建这个学生结构体的一个实例,即在程序中创建一个实际的学生。

以下是创建结构体变量的方法:

struct Student student1;

现在,我创建了一个名为student1的容器,它能够存储一个姓名、一个专业、一个年龄和一个GPA。

如果你熟悉C语言中的数组,你会知道数组是一种可以保存多条信息的特殊结构,但数组中的所有信息必须是相同的数据类型,并且它们没有名称。而对于结构体,我可以拥有像这样一堆不同的数据类型,并且我可以给它们命名,如namemajoragegpa

现在,让我展示如何为这些属性赋值。

对于这个特定的学生student1,我可以给他/她赋值:

student1.age = 22;
student1.gpa = 3.2;

student1容器内部,我将这个特定学生的年龄设置为22,GPA设置为3.2。

对于字符串(姓名和专业),情况略有不同。在C语言中,字符串实际上只是一个字符数组,我们不能直接给数组赋值。我们需要使用strcpy函数。

strcpy(student1.name, "Jim");
strcpy(student1.major, "Business");

现在,student1.name的值是“Jim”,student1.major的值是“Business”。

本质上,我在这里创建了一个学生,该学生拥有我们在上面定义的所有属性。我为所有这些属性赋予了值。

访问和打印结构体数据

现在,我可以打印存储在这个结构体中的所有不同值。

例如,我可以打印GPA:

printf("%f\n", student1.gpa); // 输出 3.2

我也可以打印姓名:

printf("%s\n", student1.name); // 输出 Jim

结构体是一个非常实用的结构。另一个很酷的事情是,我们可以创建另一个学生,即创建该学生结构体的另一个实例。

以下是创建第二个学生的方法:

struct Student student2;
student2.age = 20;
student2.gpa = 2.5;
strcpy(student2.name, "Pam");
strcpy(student2.major, "Art");

现在,我有了一个完全不同的学生。如果我想,我可以打印这个学生的属性:

printf("%s\n", student2.name); // 输出 Pam

我可以根据需要创建任意多个这样的学生。这就是结构体的妙处:我可以在程序中定义学生的基本模板,然后在下面创建可以使用的单个学生。

现在,我有了这个学生变量。我可以对它做任何我想做的事情:我可以将它传递给函数,可以将其打印到屏幕上,可以在if语句中使用它。基本上,我可以像处理变量或数组一样处理它。记住,变量和数组只是容器,我们可以对它们做几乎任何事情,结构体也是如此。

总结

本节课中我们一起学习了C语言中的结构体。我们了解到结构体是一种可以组合不同数据类型的强大工具,非常适合用来模拟现实世界中的实体(如学生)。我们学习了如何定义结构体、创建结构体变量、为其成员赋值以及如何访问这些数据。你可以尝试思考其他可以在程序中建模的事物,例如一本书或一部手机,使用结构体可以存储任何类型的信息。

C语言编程初学者教程:22:while循环 🌀

在本节课中,我们将要学习C语言中的while循环。循环是一种强大的编程结构,它允许我们重复执行一段代码,直到某个条件不再满足为止。理解循环是掌握编程逻辑的关键一步。


什么是while循环?

while循环是C语言中的一种控制流语句。它的基本思想是:只要某个条件为真,就反复执行循环体内的代码块。其核心结构可以用以下伪代码表示:

while (条件为真) {
    // 要重复执行的代码
}

上一节我们介绍了条件语句,本节中我们来看看如何使用循环来重复执行任务。


创建一个基础的while循环

让我们通过一个简单的例子来理解while循环的工作原理。首先,我们需要一个变量来控制循环的次数。

以下是创建并运行一个基础while循环的步骤:

  1. 初始化变量:我们创建一个名为index的整数变量,并将其初始值设为1。
    int index = 1;
    
  2. 构建循环结构:使用while关键字,后面跟上括号()和花括号{}
    while (index <= 5) {
        // 循环体内的代码将放在这里
    }
    
    这里的条件 index <= 5 意味着只要index的值小于或等于5,循环就会继续。
  3. 编写循环体:在花括号内,我们编写需要重复执行的代码。在这个例子中,我们打印index的当前值,然后将其增加1。
    while (index <= 5) {
        printf("%d\n", index); // 打印当前index的值
        index++; // 将index的值增加1。这等价于 index = index + 1;
    }
    
  4. 运行程序:当运行这段代码时,控制台会依次输出数字1、2、3、4、5。

循环执行流程解析

  • 程序首先检查条件 index <= 5(此时index为1,条件为真)。
  • 条件为真,进入循环体:打印1,然后将index增加为2
  • 执行完循环体后,程序跳回循环开头,再次检查条件 index <= 5(此时index为2,条件仍为真)。
  • 重复此过程,直到index被增加为6
  • 再次检查条件 6 <= 5,结果为假,循环终止,程序继续执行后面的代码。


需要警惕的情况:无限循环 🔁

在编写while循环时,一个常见的错误是创建了“无限循环”。即循环的条件永远无法变为假,导致程序无法停止。

例如,如果我们移除上面例子中的 index++ 这一行:

int index = 1;
while (index <= 5) {
    printf("%d\n", index);
    // 缺少 index++,index 的值永远为1
}

程序将不停地打印数字1,直到手动终止程序。在更复杂的程序中,无限循环可能导致电脑卡顿或资源耗尽,因此务必确保循环条件有朝一日会变为假。


while循环的变体:do...while循环

除了标准的while循环,C语言还提供了do...while循环。它与while循环的关键区别在于执行顺序

  • while循环:先检查条件,条件为真才执行循环体。
  • do...while循环:先执行一次循环体,然后再检查条件。这意味着循环体至少会执行一次

其结构如下:

do {
    // 要执行的代码
} while (条件);

让我们通过一个例子来对比。假设我们将index初始化为6:

  • 使用while循环:条件 6 <= 5 立即为假,循环体一次也不会执行,没有输出。
  • 使用do...while循环:
    int index = 6;
    do {
        printf("%d\n", index);
        index++;
    } while (index <= 5);
    
    程序会先执行一次循环体,打印出6,并将index增加为7,然后检查条件 7 <= 5 为假,循环结束。

因此,do...while循环适用于那些无论条件如何,都需要至少执行一次的场景。


总结

本节课中我们一起学习了C语言中两种重要的循环结构:

  1. while循环:在每次迭代前检查条件,可能一次也不执行。
  2. do...while循环:先执行一次循环体,然后在每次迭代后检查条件,保证至少执行一次。

核心在于理解条件检查代码执行的顺序。循环是自动化重复任务的基础,在接下来的教程中,我们将运用while循环来构建一个有趣的猜数字游戏,以巩固所学知识。

023:构建猜谜游戏 🎮

在本节课中,我们将学习如何使用C语言构建一个简单的猜数字游戏。我们将综合运用到目前为止学到的知识,包括变量、循环和条件判断,来创建一个可以交互运行的程序。


概述

我们将创建一个猜数字游戏。程序会设定一个秘密数字,并允许用户反复猜测,直到猜中为止。之后,我们还会为游戏增加一个功能:限制用户的猜测次数。如果用户在规定的次数内没有猜中,游戏将结束。


第一步:基础游戏结构

首先,我们创建一个基础版本的游戏,允许用户无限次猜测,直到猜中秘密数字。

我们需要定义两个变量:

  1. secretNumber:一个整数,存储需要猜测的秘密数字。
  2. guess:一个整数,用于存储用户每次输入的数字。

以下是初始代码结构:

int secretNumber = 5;
int guess;

接下来,我们需要一个循环来持续提示用户输入,直到猜中为止。这里我们使用 while循环。循环的条件是:只要用户的猜测不等于秘密数字,就继续循环。

while (guess != secretNumber) {
    // 提示用户输入并获取猜测值
}

在循环内部,我们需要:

  1. 使用 printf 提示用户输入。
  2. 使用 scanf 获取用户输入,并存储到 guess 变量中。

循环结束后(即猜中时),打印胜利信息。

完整的代码如下:

#include <stdio.h>

int main() {
    int secretNumber = 5;
    int guess;

    while (guess != secretNumber) {
        printf("Enter a number: ");
        scanf("%d", &guess);
    }

    printf("You win!\n");
    return 0;
}

运行这个程序,用户可以一直输入数字,直到输入5,程序会输出“You win!”并结束。


第二步:增加猜测次数限制

上一节我们创建了一个可以无限猜测的基础游戏。本节中,我们来看看如何改进游戏,为用户设定猜测次数上限。

我们需要新增三个变量来管理猜测次数:

  1. guessCount:整数,记录用户已经猜测的次数,初始值为 0
  2. guessLimit:整数,设定用户最多可以猜测的次数,例如 3
  3. outOfGuesses:整数,作为一个“布尔”标志,表示用户是否用尽了猜测机会。0 表示还有机会,1 表示机会已用尽。

变量定义如下:

int guessCount = 0;
int guessLimit = 3;
int outOfGuesses = 0;

现在,我们需要修改 while 循环的逻辑。循环应在两种情况下终止:

  1. 用户猜中了数字 (guess == secretNumber)。
  2. 用户用尽了猜测次数 (outOfGuesses == 1)。

因此,循环条件应修改为:

while (guess != secretNumber && outOfGuesses == 0) {
    // 循环内的代码
}

在循环内部,我们需要在每次猜测前检查用户是否还有剩余次数。这通过一个 if 语句实现:

if (guessCount < guessLimit) {
    // 允许用户猜测:提示输入、获取输入、增加计数
} else {
    outOfGuesses = 1; // 标记为已用尽机会
}

在允许猜测的代码块中,我们需要:

  1. 提示用户输入。
  2. 使用 scanf 获取猜测值。
  3. guessCount 增加 1 (guessCount++)。

循环结束后,我们需要判断用户是因为猜中而获胜,还是因为次数用尽而失败。我们通过检查 outOfGuesses 的值来判断:

if (outOfGuesses == 1) {
    printf("Out of guesses.\n");
} else {
    printf("You win!\n");
}

完整代码与总结

以下是整合了猜测次数限制功能的完整游戏代码:

#include <stdio.h>

int main() {
    int secretNumber = 5;
    int guess;
    int guessCount = 0;
    int guessLimit = 3;
    int outOfGuesses = 0;

    while (guess != secretNumber && outOfGuesses == 0) {
        if (guessCount < guessLimit) {
            printf("Enter a number: ");
            scanf("%d", &guess);
            guessCount++;
        } else {
            outOfGuesses = 1;
        }
    }

    if (outOfGuesses == 1) {
        printf("Out of guesses.\n");
    } else {
        printf("You win!\n");
    }

    return 0;
}

本节课中我们一起学习了如何构建一个猜数字游戏。我们从基础的无限制版本开始,然后引入了变量来跟踪和限制猜测次数,并综合运用了 while 循环和 if 条件语句来控制游戏流程。这个项目展示了如何将不同的编程概念组合起来,创建一个完整且互动的小程序。

024:For循环 🔄

在本节课中,我们将学习C语言中一种特殊的循环结构——for循环。for循环允许我们使用一个索引变量来追踪当前循环的迭代次数,这在处理数组或需要计数的情况下非常有用。我们将通过对比while循环,详细讲解for循环的结构、用法及其优势。


从while循环到for循环

上一节我们介绍了while循环的基本用法。本节中,我们来看看如何将while循环转换为更简洁的for循环。

以下是一个简单的while循环示例,它打印数字1到5:

int i = 1;
while (i <= 5) {
    printf("%d\n", i);
    i++;
}

在这个循环中,变量 i 充当了索引变量的角色。它从1开始,每次循环递增1,直到其值大于5为止。i 的值告诉我们当前是第几次循环迭代。

理解for循环的结构

for循环将初始化索引变量、循环条件和更新索引变量这三个步骤整合到了一行代码中,使得结构更加紧凑。

以下是for循环的基本语法结构:

for (初始化; 循环条件; 更新操作) {
    // 循环体
}

现在,让我们将上面的while循环改写为for循环:

for (int i = 1; i <= 5; i++) {
    printf("%d\n", i);
}

这两个代码块的功能完全等价。for循环的第一部分 int i = 1 用于初始化索引变量;第二部分 i <= 5 是循环条件;第三部分 i++ 是每次循环后执行的操作。

使用for循环遍历数组

for循环一个非常常见的用途是遍历数组中的所有元素。

假设我们有一个名为 luckyNumbers 的数组:

int luckyNumbers[] = {4, 8, 15, 16, 23, 42};

在C语言中,数组的索引从0开始。因此,第一个元素 4 的索引是0,第二个元素 8 的索引是1,依此类推。

以下是使用for循环遍历该数组并打印每个元素的代码:

for (int i = 0; i < 6; i++) {
    printf("%d\n", luckyNumbers[i]);
}

代码执行过程如下:

  • 第一次循环:i = 0,打印 luckyNumbers[0],即 4
  • 第二次循环:i = 1,打印 luckyNumbers[1],即 8
  • ...
  • 第六次循环:i = 5,打印 luckyNumbers[5],即 42

通过这种方式,我们可以轻松访问和处理数组中的每一个元素。

for循环的灵活性

for循环的“更新操作”部分非常灵活,你可以执行各种操作,不仅仅是递增。

例如,你可以让索引变量每次增加2:

for (int i = 0; i < 10; i = i + 2) {
    printf("%d\n", i); // 将打印 0, 2, 4, 6, 8
}

或者进行递减操作:

for (int i = 5; i > 0; i--) {
    printf("%d\n", i); // 将打印 5, 4, 3, 2, 1
}

总结

本节课中我们一起学习了C语言中的for循环

我们首先回顾了使用索引变量的while循环,然后引入了for循环,它通过将初始化条件判断更新三个步骤集中声明,使代码更加清晰简洁。我们重点探讨了for循环在遍历数组这一常见任务中的强大和便利性。最后,我们看到了for循环更新操作的灵活性。

虽然任何for循环都能用while循环实现,但for循环在需要明确索引和计数的场景下,提供了更优雅、更易读的解决方案。掌握for循环是高效处理重复性任务,尤其是处理数组数据的关键一步。

025:二维数组与嵌套循环 📚

在本节课中,我们将要学习两个核心概念:二维数组嵌套循环。我们将首先了解什么是二维数组,然后学习如何使用嵌套循环来遍历和操作二维数组中的数据。这两个概念经常结合使用,是处理表格数据、矩阵运算等复杂数据结构的基础。

二维数组 📊

上一节我们介绍了普通的一维数组,本节中我们来看看二维数组。二维数组本质上是一个数组,但这个数组中的每一个元素本身也是一个数组。你可以把它想象成一个表格,有行和列。

创建二维数组

要创建一个二维数组,我们需要使用两对方括号 [][]。第一对方括号指定外层数组的大小(可以理解为行数),第二对方括号指定每个内层数组的大小(可以理解为列数)。

以下是创建一个二维整数数组的示例:

int nums[3][2] = {
    {1, 2},
    {3, 4},
    {5, 6}
};

在这个例子中,我们创建了一个名为 nums 的二维数组。它包含3个元素(3行),每个元素本身又是一个包含2个整数的数组(2列)。因此,这个数组的结构如下:

  • 第一行:{1, 2}
  • 第二行:{3, 4}
  • 第三行:{5, 6}

访问二维数组元素

要访问二维数组中的特定元素,我们需要使用两个索引:第一个索引指定行,第二个索引指定列。索引从0开始计数。

以下是访问元素的示例:

printf("%d", nums[0][0]); // 输出第一行第一列的元素:1
printf("%d", nums[1][1]); // 输出第二行第二列的元素:4

嵌套循环 🔄

理解了二维数组的结构后,我们来看看如何系统地遍历它的所有元素。这就需要用到嵌套循环。嵌套循环是指在一个循环的内部,又包含了另一个完整的循环。

使用嵌套循环遍历二维数组

嵌套循环非常适合用来遍历二维数组。外层循环控制行索引,内层循环控制列索引。

以下是使用嵌套 for 循环打印二维数组所有元素的代码:

int i, j;
for (i = 0; i < 3; i++) {        // 外层循环,遍历每一行
    for (j = 0; j < 2; j++) {    // 内层循环,遍历当前行的每一列
        printf("%d, ", nums[i][j]); // 打印当前元素
    }
    printf("\n"); // 每打印完一行后换行
}

让我们分析一下这段代码的执行过程:

  1. 外层循环开始,i = 0
  2. 进入内层循环,j 从 0 到 1 变化,依次打印 nums[0][0]nums[0][1](即 1, 2)。
  3. 内层循环结束,执行 printf("\n") 换行。
  4. 外层循环进入下一次迭代,i = 1
  5. 重复内层循环,打印 nums[1][0]nums[1][1](即 3, 4)。
  6. 以此类推,直到遍历完所有行和列。

运行这段代码,输出结果将是:

1, 2,
3, 4,
5, 6,

总结 🎯

本节课中我们一起学习了两个重要的C语言概念:

  1. 二维数组:它是一种数组的数组,常用于表示表格或矩阵形式的数据。通过 array[row][column] 的格式来声明和访问。
  2. 嵌套循环:它是一个循环内包含另一个循环的结构,是遍历和操作二维数组等多维数据的强大工具。通常外层循环控制“行”,内层循环控制“列”。

将二维数组与嵌套循环结合使用,可以高效地处理各种网格状数据,这是进行更复杂编程(如图形处理、游戏开发、科学计算)的基础。

026:内存地址 💾

在本节课中,我们将要学习C语言中一个核心概念:内存地址。我们将了解变量在计算机内存中是如何存储的,以及如何访问和打印出这些变量的具体内存位置。

概述

在C语言编程中,我们经常需要存储各种信息。变量、数组和结构体等都是存储信息的工具。这些数据并非凭空存在,而是被存储在计算机的物理内存(通常称为RAM)中。每个存储的数据都有一个唯一的“地址”,就像房子有门牌号一样。理解内存地址是理解C语言如何与计算机硬件交互的关键一步。

上一节我们介绍了变量的基本使用,本节中我们来看看这些变量在计算机内存中究竟位于何处。

变量与内存

当我们创建一个变量时,例如 int age = 30;,C语言会做两件事:

  1. 在内存(RAM)中找到一个空闲的位置。
  2. 将值 30 存储在这个位置。

这个存储位置就是内存地址。虽然我们在代码中通过变量名 age 来访问值 30,但计算机内部是通过该值的内存地址来找到它的。

如何访问内存地址

在C语言中,我们可以使用取址运算符 & 来获取一个变量的内存地址。

以下是访问内存地址的基本步骤:

  1. 使用 & 运算符放在变量名前。
  2. 使用 printf 函数配合 %p 格式说明符来打印这个地址。

%p 中的 “p” 代表指针(Pointer),它是专门用于打印内存地址(以十六进制格式显示)的格式符。

实践:打印变量地址

让我们通过一个例子来演示如何打印不同变量的内存地址。

#include <stdio.h>

int main() {
    int age = 30;
    double gpa = 3.4;
    char grade = 'A';

    printf("变量 age 的内存地址是:%p\n", &age);
    printf("变量 gpa 的内存地址是:%p\n", &gpa);
    printf("变量 grade 的内存地址是:%p\n", &grade);

    return 0;
}

运行这段代码,你会在控制台看到类似以下的输出(具体地址值因计算机和运行环境而异):

变量 age 的内存地址是:0x7ffd5a3b4b2c
变量 gpa 的内存地址是:0x7ffd5a3b4b30
变量 grade 的内存地址是:0x7ffd5a3b4b2b

这些以 0x 开头的十六进制数字就是各个变量值在内存中的“门牌号”。

为什么内存地址很重要?

理解内存地址非常重要,原因如下:

  • 计算机的工作方式:CPU(中央处理器)通过内存地址来读写数据。我们使用变量名是为了编程方便,但最终计算机会将其转换为对内存地址的操作。
  • 高级主题的基础:内存地址是学习后续更强大概念(如指针)的基石。指针本质上就是一个存储内存地址的变量。
  • 高效的数据处理:通过直接操作地址,可以在函数间高效地传递和修改大量数据,而无需进行耗时的数据复制。

简单来说,内存地址是连接我们编写的高级C语言代码与计算机底层硬件的桥梁。

总结

本节课中我们一起学习了C语言中的内存地址。

  1. 我们了解到,程序中定义的每个变量都存储在计算机内存的特定位置。
  2. 我们学会了使用取址运算符 & 来获取变量的内存地址。
  3. 我们掌握了使用 printf%p 格式说明符来打印这个地址的方法。

记住,虽然我们现在可以直接使用变量名,但了解其背后的内存地址机制,能帮助我们更好地理解程序是如何运行的,并为学习更复杂的C语言特性(如指针)打下坚实的基础。在接下来的教程中,我们将看到如何利用这些地址做更多有趣和强大的事情。

027:指针入门指南 🧭

在本节课中,我们将要学习C语言中一个核心概念:指针。指针是C语言中一种特殊的数据类型,它存储的是内存地址。理解指针对于深入学习C语言至关重要。

概述

指针是C语言中的一种数据类型,它代表一个内存地址。内存地址指向计算机内存中存储特定值的位置。虽然指针常被认为是复杂的概念,但实际上,它只是一种数据形式,就像整数、双精度浮点数或字符一样简单。

什么是指针?

指针本质上是一种数据类型,用于存储内存地址。内存地址是计算机内存中存储数据的物理位置。

指针的定义数据类型 *指针变量名;

例如,一个整数指针可以这样声明:int *p;

访问变量的内存地址

在C语言中,我们可以使用取地址运算符&来获取变量的内存地址。

以下是一个示例代码,展示如何获取并打印变量的内存地址:

#include <stdio.h>

int main() {
    int age = 30;
    printf("age的内存地址是: %p\n", &age);
    return 0;
}

运行这段代码,会输出age变量的内存地址,这是一个十六进制数。这个地址就是一个指针。

创建指针变量

我们可以创建专门的变量来存储指针,即存储其他变量的内存地址。

创建指针变量的步骤如下:

  1. 指定指针所指向变量的数据类型。
  2. 使用星号*声明这是一个指针变量。
  3. 为指针变量命名。
  4. 使用取地址运算符&将另一个变量的地址赋值给指针变量。

以下是创建不同类型指针变量的示例:

#include <stdio.h>

int main() {
    // 声明普通变量
    int age = 30;
    double gpa = 3.4;
    char grade = 'A';

    // 创建指针变量并存储对应变量的地址
    int *pAge = &age;     // pAge 存储了 age 的地址
    double *pGpa = &gpa;  // pGpa 存储了 gpa 的地址
    char *pGrade = &grade; // pGrade 存储了 grade 的地址

    // 打印指针(内存地址)
    printf("age的地址: %p\n", pAge);
    printf("gpa的地址: %p\n", pGpa);
    printf("grade的地址: %p\n", pGrade);

    return 0;
}

指针与数据类型的关系

指针变量在声明时,其数据类型必须与它将要指向的变量数据类型一致。这是因为不同类型的数据在内存中占用的空间大小不同,指针需要知道如何正确解释所指向的内存内容。

以下是不同类型指针的声明方式:

  • int *p; 指向整数的指针。
  • double *p; 指向双精度浮点数的指针。
  • char *p; 指向字符的指针。

总结

本节课中我们一起学习了C语言指针的基础知识。我们了解到:

  1. 指针是一种数据类型,其值是内存地址。
  2. 可以使用取地址运算符&获取任何变量的内存地址。
  3. 可以创建指针变量来专门存储这些内存地址。
  4. 声明指针时必须指明它所指向的数据类型。

记住,指针并不神秘,它只是我们程序中可以使用的另一种信息形式。掌握了指针,你就打开了高效管理内存和构建复杂数据结构的大门。在接下来的课程中,我们将学习如何使用指针来访问和修改它所指向的值。

028:取消引用指针 📌

在本节课中,我们将要学习C语言中一个核心概念:取消引用指针。指针是程序中用于存储内存地址的一种数据类型。通过取消引用指针,我们可以访问该内存地址中存储的实际值。掌握这一操作对于深入理解内存管理和数据操作至关重要。

指针基础回顾

上一节我们介绍了指针的基本概念,本节中我们来看看如何通过取消引用指针来获取内存地址中存储的值。

指针本质上是一个内存地址。在程序中,我们有时需要直接操作内存地址,这些地址在C语言中被称为指针。例如,以下代码定义了一个整型变量和一个指向该变量的指针:

int age = 30;
int *pAge = &age;

这里,age 存储整数值 30pAge 存储 age 变量的内存地址。

什么是取消引用指针?

取消引用指针意味着访问指针所指向的内存地址,并获取该地址中存储的值。这一操作通过星号(* 实现。

以下是取消引用指针的基本语法:

int value = *pAge;

这行代码将 pAge 指向的内存地址中的值(即 30)赋给 value 变量。

取消引用指针的示例

让我们通过一个完整示例来演示取消引用指针的过程:

#include <stdio.h>

int main() {
    int age = 30;
    int *pAge = &age;

    printf("内存地址: %p\n", pAge);
    printf("通过取消引用获取的值: %d\n", *pAge);

    return 0;
}

运行此程序,输出结果如下:

内存地址: 0x7ffeed42a7cc
通过取消引用获取的值: 30

可以看到,pAge 输出的是内存地址,而 *pAge 输出的是该地址中存储的值 30

多层取消引用操作

取消引用操作可以多层嵌套,进一步展示指针与值之间的关系。以下是多层取消引用的示例:

#include <stdio.h>

int main() {
    int age = 30;

    printf("直接值: %d\n", age);
    printf("地址: %p\n", &age);
    printf("取消引用一次: %d\n", *(&age));
    printf("再次获取地址: %p\n", &(*(&age)));
    printf("再次取消引用: %d\n", *(&(*(&age))));

    return 0;
}

输出结果:

直接值: 30
地址: 0x7ffeed42a7cc
取消引用一次: 30
再次获取地址: 0x7ffeed42a7cc
再次取消引用: 30

通过这个示例,可以清晰地看到:

  • &age 获取 age 的内存地址。
  • *(&age) 取消引用该地址,获取值 30
  • 多层操作最终仍指向相同的值和地址。

取消引用指针的应用场景

取消引用指针在以下场景中非常有用:

  • 动态内存分配:通过指针访问堆内存中的数据。
  • 函数参数传递:通过指针修改函数外部的变量值。
  • 数组和字符串操作:直接访问数组元素或字符串字符。

例如,通过指针修改变量值:

#include <stdio.h>

void changeValue(int *ptr) {
    *ptr = 99;
}

int main() {
    int num = 42;
    printf("修改前: %d\n", num);
    changeValue(&num);
    printf("修改后: %d\n", num);
    return 0;
}

输出:

修改前: 42
修改后: 99

注意事项

在使用取消引用指针时,需要注意以下几点:

  • 确保指针已正确初始化,指向有效的内存地址。
  • 避免对空指针(NULL)进行取消引用,这会导致程序崩溃。
  • 指针类型应与所指数据类型匹配,否则可能导致未定义行为。

总结

本节课中我们一起学习了C语言中取消引用指针的概念和操作方法。我们了解到,指针是内存地址,通过星号(*)可以取消引用指针,获取该地址中存储的实际值。我们还通过示例代码演示了单层和多层取消引用操作,并探讨了其常见应用场景和注意事项。掌握取消引用指针是深入理解C语言内存管理的关键步骤,为后续学习动态内存分配和高级数据结构打下坚实基础。

029:写入文件 📝

在本节课程中,我们将学习如何在C语言中向文件写入数据。C语言允许我们创建、修改和写入文件,这是处理数据持久化存储的重要技能。我们将涵盖创建文件、写入文件以及向文件追加内容的基本操作。

创建并打开文件

上一节我们介绍了文件的基本概念,本节中我们来看看如何实际操作文件。首先,我们需要在程序中创建一个文件指针,并使用fopen函数打开(或创建)一个文件。

FILE *fpointer;
fpointer = fopen("employees.txt", "w");

代码解释

  • FILE *fpointer;:声明一个指向FILE类型结构的指针。FILE是一个在stdio.h中定义的数据类型,用于表示文件流。
  • fopen("employees.txt", "w");:调用fopen函数。它接收两个参数:
    1. 文件名(例如 "employees.txt")。
    2. 文件模式(例如 "w")。

文件模式决定了我们对文件的操作意图。以下是三种基本模式:

  • "r"读取。打开文件用于读取数据。文件必须存在。
  • "w"写入。打开文件用于写入数据。如果文件不存在,则创建新文件;如果文件已存在,则清空其原有内容
  • "a"追加。打开文件用于在文件末尾追加数据。如果文件不存在,则创建新文件。

在本例中,我们使用"w"模式。即使employees.txt文件最初不存在,此操作也会在程序运行目录下创建它。

重要提示:操作文件后,必须使用fclose函数关闭文件。这会将数据从内存缓冲区写入磁盘,并释放相关资源。

fclose(fpointer);

向文件写入数据

成功打开文件后,我们可以使用fprintf函数向其中写入数据。fprintf函数与常用的printf函数非常相似,区别在于它需要一个文件指针作为第一个参数,以指定写入的目标文件。

以下是向文件写入多行员工信息的示例:

fprintf(fpointer, "Jim, Salesman\n");
fprintf(fpointer, "Pam, Receptionist\n");
fprintf(fpointer, "Oscar, Accounting\n");

代码解释

  • fprintf(fpointer, ...):第一个参数是文件指针fpointer,它指向我们之前打开的employees.txt文件。
  • 后续参数的格式与printf完全相同。\n代表换行符,确保每个员工信息独占一行。

运行包含以上代码的程序后,你会在程序所在目录下找到一个名为employees.txt的新文件,其内容如下:

Jim, Salesman
Pam, Receptionist
Oscar, Accounting

关于写入模式("w")的注意事项:以"w"模式打开文件并写入时,会覆盖文件的全部现有内容。例如,如果你之后只写入一行fprintf(fpointer, "Overridden");,那么employees.txt中将只剩下"Overridden"这一行文本。

向文件追加数据

如果我们不想覆盖原有内容,而是想在文件末尾添加新数据,就需要使用追加模式("a")

首先,以追加模式重新打开文件:

fpointer = fopen("employees.txt", "a");

然后,使用fprintf写入新内容。由于文件指针现在位于文件末尾,新内容会自动接在后面。为了格式清晰,我们通常先写入一个换行符。

fprintf(fpointer, "\nKelly, Customer Service");

运行程序后,employees.txt文件的内容将变为:

Jim, Salesman
Pam, Receptionist
Oscar, Accounting
Kelly, Customer Service

可以看到,"Kelly, Customer Service"被成功地添加到了文件末尾,而没有影响原有的三行数据。

总结

本节课中我们一起学习了C语言文件写入的核心操作:

  1. 创建/打开文件:使用FILE *指针 = fopen("文件名", "模式");。关键模式包括创建/覆盖写入的"w"和尾部追加的"a"
  2. 写入数据:使用fprintf(文件指针, "格式字符串", ...);函数,其用法与printf类似,但第一个参数指定了目标文件。
  3. 关闭文件:操作完成后,务必使用fclose(文件指针);来确保数据保存和资源释放。

通过组合使用"w""a"模式,配合fprintf函数,你可以创建、修改各种类型的文本文件(如.txt.html.css等),实现数据的持久化存储。记住,始终在文件操作结束时关闭文件,这是一个良好的编程习惯。

030:文件读写操作 📄

在本节课中,我们将学习如何在C语言中创建、写入、追加和读取文件。文件操作是C语言中一项强大的功能,它允许程序与计算机的文件系统进行交互,从而持久化存储数据。

概述

我们将首先学习如何创建新文件并向其中写入数据,然后了解如何向现有文件追加内容,最后学习如何从文件中读取信息。掌握这些技能将使你的程序能够处理外部数据。


创建与写入文件 ✍️

上一节我们介绍了程序的基本结构,本节中我们来看看如何操作文件。在C语言中,我们可以修改、更改甚至创建新的文件。

首先,我们需要在main函数中创建一个文件指针。文件指针是一个指向计算机上物理文件的内存地址。

FILE *fpointer;
fpointer = fopen("employees.txt", "w");
  • FILE *fpointer;: 这行代码声明了一个指向FILE类型的指针,名为fpointerFILE是一个特殊的数据类型,用于表示文件。
  • fopen("employees.txt", "w");: 这个函数用于打开一个文件。它接受两个参数:
    1. 文件名(例如 "employees.txt")。
    2. 文件模式,它告诉C语言我们想对文件做什么操作。

以下是三种最基本的文件模式:

  • "r" (Read): 以只读方式打开文件。
  • "w" (Write): 以写入方式打开文件。如果文件不存在,则创建它;如果文件已存在,则覆盖其原有内容。
  • "a" (Append): 以追加方式打开文件。将新数据添加到文件末尾,而不删除原有内容。

在本例中,我们使用"w"模式。即使employees.txt文件不存在,程序也会创建它。

非常重要的一点是,操作完文件后,必须将其关闭。这会将文件从内存中移除,并确保所有更改都被保存。

fclose(fpointer);

fclose函数接收文件指针作为参数,用于关闭对应的文件。

现在,让我们向文件中写入一些数据。我们可以使用fprintf函数,它的工作方式与熟悉的printf函数类似,但它是将内容写入文件,而非打印到控制台。

fprintf(fpointer, "Jim, Salesman\nPam, Receptionist\nOscar, Accounting\n");
  • fprintf(fpointer, ...): 第一个参数是文件指针,它告诉函数应该将数据写入哪个文件。
  • 第二个参数是格式字符串,与printf的用法完全相同。

运行此程序后,你会在程序所在的目录下找到一个名为employees.txt的新文件,其中包含我们写入的三行员工信息。

需要注意的是,每次以"w"模式运行此程序,都会覆盖文件中的全部旧内容。


向文件追加内容 ➕

上一节我们学习了如何创建和覆盖文件,本节中我们来看看如何在不删除旧数据的情况下向文件添加新内容。

如果我们想向employees.txt文件添加一名新员工,而不是重写整个文件,就需要使用追加模式。

只需将fopen中的文件模式从"w"改为"a"即可。

fpointer = fopen("employees.txt", "a");
fprintf(fpointer, "\nKelly, Customer Service");
  • "a" 模式:此模式会在文件末尾添加新数据。
  • 我们在字符串开头添加了\n(换行符),以确保新内容从新的一行开始。

运行此程序后,打开employees.txt文件,你会看到“Kelly, Customer Service”被添加到了文件末尾,而原有的员工信息保持不变。


从文件读取内容 👀

上一节我们介绍了如何写入文件,本节中我们来看看如何从文件中读取信息。

要读取文件,我们需要使用读取模式("r")。

FILE *fpointer;
fpointer = fopen("employees.txt", "r");

为了存储从文件中读取的内容,我们需要一个字符数组(字符串)。

char line[255];

现在,我们可以使用fgets函数来逐行读取文件内容。

fgets(line, 255, fpointer);
printf("%s", line);

以下是fgets函数的参数说明:

  1. line: 用于存储读取到的那一行内容的字符数组。
  2. 255: 指定最多读取多少个字符(通常与数组大小匹配,防止溢出)。
  3. fpointer: 文件指针,指向我们要读取的文件。

fgets函数每次被调用时,都会读取文件的下一行,并将文件指针移动到该行之后。因此,多次调用fgets可以依次读取文件的所有行。

例如,要读取并打印文件的前两行,可以这样做:

fgets(line, 255, fpointer); // 读取第一行
printf("%s", line);

fgets(line, 255, fpointer); // 读取第二行
printf("%s", line);

通过循环使用fgets,你可以读取整个文件的内容。


总结

本节课中我们一起学习了C语言中基本的文件操作。

  1. 写入文件 ("w" 模式): 用于创建新文件或覆盖现有文件。使用fprintf函数写入内容。
  2. 追加文件 ("a" 模式): 用于在现有文件末尾添加新内容,而不影响原有数据。
  3. 读取文件 ("r" 模式): 用于从文件中获取数据。使用fgets函数可以方便地逐行读取。

记住,使用fopen打开文件后,务必使用fclose关闭文件,这是一个良好的编程习惯。掌握了这些操作,你的程序就能与外部文件进行有效的输入输出交互了。

posted @ 2026-03-29 09:14  绝不原创的飞龙  阅读(3)  评论(0)    收藏  举报