C语言入门~又爱又恨
写在前面
果然,学完了SQL的我又想来霍霍C语言了~
环境搭建
- MacBookPro 2018 13(丐中丐版)+ Mojeve
Xcode
(在App Store就可以安装,用Xcode麻烦少很多)CLion
(edu邮箱注册,教育优惠可以免费用一年)
配置 CLion
启动CLion
后在设置中选择”Build, Execution, Deployment
“ -> “Toolchains
“,选择 “Xcode
“ 作为默认工具链。
创建新项目
在 CLion 中选择 “File
“ -> “New Project
“,在左侧菜单中选择 “C Executable
“。在右侧面板中选择项目名称、路径等信息,并设置工具链为 “Xcode
“。
写代码
创建一个新的.c
文件,输入C语言代码。CLion
提供了丰富的代码编辑功能,例如语法高亮、自动补全等。
构建和运行
在CLion中选择”Run
“ -> “Run
“来构建和运行程序。运行之后,程序的输出会显示在控制台窗口。
需要注意的是,如果在Xcode
中安装了其他编译器,也可以在CLion
中进行配置并使用。只需在CLion
的”Toolchains
“ 设置中选择其他编译器即可。
C语言入坑指南
首先当然是基本语法:
- C语言中的保留字
- 变量、常量
- 库函数的使用
- 输入、输出
- 条件控制
- 循环语句
接着学习更复杂的操作:
- 子程序设计、递归
- 数组
- 指针
- 结构体
- 文件操作
其实到了这一步,难度都不会是语言本身,而是算法、数据结构以及计算机基础。
零碎知识点
变量
整型变量(int):整型变量用于存储整数值,可以表示正数、负数和零。
整型变量在内存中占用固定的字节数,通常是4个字节。
1 |
|
浮点型变量(float和double):浮点型变量用于存储实数值,可以表示小数和指数形式的数值。
浮点型变量在内存中占用的字节数通常比整型变量多,因为它们需要存储小数部分。
C语言提供了两种浮点型变量,分别是单精度浮点型(float)和双精度浮点型(double)。
1 |
|
字符型变量(char):字符型变量用于存储单个字符,例如字母、数字或标点符号。
字符型变量在内存中占用1个字节,因为一个字符通常只需要8个比特位来表示。
1 |
|
长整型变量(long):长整型变量用于存储较大的整数值,通常占用8个字节。
它们比普通整型变量更适合用于存储非常大的整数值。
1 |
|
短整型变量(short):短整型变量用于存储较小的整数值,通常占用2个字节。
它们比普通整型变量更适合用于存储非常小的整数值。
1 |
|
常量
常量是指在程序运行时其值不会发生变化的量,它们可以帮助我们简化代码和提高程序的可读性。常量可以是整数、浮点数、字符或字符串等类型。
1、整数常量
整数常量是指不带小数部分的数字,可以是正数、负数或零。在C语言中,整数常量默认是十进制数,也可以使用其他进制表示。下面是几个整数常量的例子:
1 |
|
2、浮点数常量
浮点数常量是指带有小数部分的数字,可以是单精度浮点数(float)或双精度浮点数(double)。在C语言中,可以使用小数点或指数形式来表示浮点数常量。下面是几个浮点数常量的例子。
1 |
|
3、字符常量
字符常量是指用单引号括起来的单个字符,例如字母、数字或标点符号。在C语言中,每个字符常量在内存中占用一个字节,可以使用转义字符来表示一些特殊的字符。下面是几个字符常量的例子。
1 |
|
4、字符串常量
字符串常量是指由一串字符组成的字符数组,用双引号括起来。在C语言中,字符串常量以空字符(’\0’)结尾,占用的内存空间根据字符串的长度而定。
1 |
|
5、const关键字来定义常量
1 |
|
试图修改这个常量时,编译器会报错
6、宏定义常量
使用#define预处理指令来为一个符号(通常是一个常量)定义一个标识符,以后使用该标识符时,预处理器会自动将其替换成所定义的值。下面是一个宏定义常量的例子:
1 |
|
在这个例子中,我们定义了一个名为PI的常量,它的值为3.14159。在程序中,我们可以直接使用PI这个标识符来表示这个常量,例如:
1 |
|
在预处理之后,这个表达式会被替换成:
1 |
|
需要注意的是,宏定义是一种纯文本替换,没有数据类型,也没有作用域限制,因此它的使用可能会带来一些问题。比如,如果我们定义了一个整数常量:
1 |
|
在程序中使用这个常量时,如果不小心将它和一个整数变量相加,就可能会出现不正确的结果:
1 |
|
为了避免这种问题,建议使用const关键字来定义常量,const定义的常量有数据类型和作用域限制,可以更好地保护程序的正确性和可读性。
头文件
包含头文件。举例,如果要使用数学库中的函数,则需要包含math.h头文件。
1 |
|
调用库函数。包含math.h头文件后,可以在程序中调用库中的函数。
可以调用数学库中的sin函数来计算正弦值。
1 |
|
至于该使用哪些库、哪些函数,可以去查找文档或者直接在百度搜。
输入输出(IO)
printf() 函数用于向屏幕输出文本:
1 |
|
scanf() 函数用于从用户输入中读取值:
1 |
|
条件控制
if-else 语句用于根据条件执行不同的代码:
1 |
|
switch-case
语句也用于根据不同的条件执行不同的代码:
1 |
|
循环语句
for循环用于执行指定次数的代码:
1 |
|
while
和do-while
循环用于在条件为真时重复执行代码:
1 |
|
1 |
|
子程序设计
函数是C语言中的一种子程序。函数可以将程序分解为更小、更易于管理的块,从而使代码更易于理解和调试。
下面是一个例子,展示如何定义和调用一个函数:
1 |
|
递归
递归是一种函数调用自身的技术。它通常用于解决需要重复执行相同或类似操作的问题。
下面是一个例子,展示如何使用递归来计算阶乘:
1 |
|
在这个例子中,factorial()
函数使用递归调用自身来计算n的阶乘。在每个递归调用中,函数将n乘以factorial(n-1)
,直到n等于1。最后,递归调用返回到原始函数调用,并将计算的阶乘作为结果返回给主函数。
数组和指针
数组
- 数组是一种数据结构,可以存储多个相同类型的元素。
- 在C语言中,数组的元素可以是任何基本数据类型,如整数、浮点数、字符等。
- 在声明数组时,需要指定数组的大小。例如,下面是一个包含10个整数的数组的声明:
1 |
|
- 数组元素的访问是通过下标来实现的,下标从0开始,表示数组中的第一个元素。
1
myArray[0] = 1; // 将第一个元素设置为1
- 数组可以用于存储一系列数据,例如数字、字符串等。
指针
- 指针是一个变量,它存储了一个内存地址。
- 指针可以指向任何数据类型,例如整数、字符、数组等。
- 指针的声明需要指定指针所指向的数据类型。例如,下面是一个指向整数的指针的声明:
1
int *myPointer;
- 指针可以用于访问和修改存储在内存中的变量或数组元素的值。
1
2
3int myArray[10] = {1,2,3,4,5,6,7,8,9,10};
int *myPointer = &myArray[0]; // 指向数组的第一个元素
*myPointer = 2; // 修改第一个元素的值 - 指针可以用于动态分配内存,例如使用malloc函数来分配内存
1
int *myPointer = (int*)malloc(sizeof(int)*10); // 分配包含10个整数的内存空间
结构体
在C语言中,结构体是一种自定义的数据类型,它允许程序员将不同类型的数据组合在一起,并赋予这个组合一个自定义的名字。结构体由多个变量组成,每个变量被称为结构体的成员。结构体成员可以是各种数据类型,包括整型、浮点型、字符型等等。
下面是一个简单的例子,其中定义了一个名为Person的结构体,它包含了三个成员:name
表示人名,age
表示年龄,gender
表示性别。
1 |
|
定义了这个结构体之后,我们可以使用它来创建一个结构体变量,并访问它的成员。例如,下面的代码创建了一个名为person1
的Person
类型的变量,并初始化了它的成员。
1 |
|
在这个例子中,我们使用了结构体初始化语法来给person1
赋值。也可以通过点号运算符来访问结构体成员,例如:
1 |
|
输出为:
1 |
|
结构体数组
当我们需要定义一组相似结构体变量时,可以使用结构体数组。下面是一个例子,其中定义了一个名为Student
的结构体,它包含了两个成员:name
表示学生姓名,score
表示学生的分数。
1 |
|
接下来,我们可以定义一个Student
类型的结构体数组,其中包含三个学生的信息。
1 |
|
在这个例子中,我们定义了一个名为students
的结构体数组,它包含了三个Student
类型的结构体变量,并用结构体初始化语法对它们进行了初始化。
我们可以通过循环遍历结构体数组,并使用点号运算符来访问每个学生的姓名和分数。
1 |
|
输出为:
1 |
|
文件操作
首先创建一个名为data.txt
的文本文件,并将一些数据写入该文件。
然后,我们将使用C语言中的文件读写函数来读取该文件的内容并打印出来。
1 |
|
首先创建了一个名为data.txt
的文本文件,并将两行数据写入该文件中。然后,我们使用fopen()
函数打开该文件,将文件指针存储在fp变量中,并使用fprintf()
函数将数据写入该文件。
在写入完数据之后,我们使用fclose()
函数关闭文件指针。
接下来,我们重新打开data.txt
文件以进行读操作。使用fopen()
函数打开文件时,我们将第二个参数设置为r,表示以只读模式打开文件。然后,我们使用fgets()
函数从文件中读取数据,并将读取的数据输出到屏幕上。
最后,我们再次使用fclose()
函数关闭文件指针。
需要注意的是,在进行文件读写操作时,我们需要确保正确地打开和关闭文件指针,并对可能发生的错误进行适当的处理。
关于C语言的异常处理
注意,C语言本身不支持像其他一些语言(如Java和Python)那样的异常处理机制,但我们可以使用C语言中的一些技巧来模拟异常处理。
一个常见的做法是在代码中使用返回值来指示错误状态,并在发生错误时采取适当的行动。下面是一个简单的例子,演示了如何使用返回值来模拟异常处理。
在这个例子中,我们将定义一个名为divide()
的函数,该函数将两个整数相除,并返回结果。如果第二个参数为零,则表示除法操作不合法,此时我们将返回一个特殊的错误码-1
。
1 |
|
我们定义了一个名为divide()
的函数,它将两个整数a和b相除,并将结果存储在指向result
变量的指针中。如果b为零,则函数返回-1,表示除法操作不合法。
在main()
函数中,我们将a
设置为10,将b
设置为0,并调用divide()
函数进行除法操作。如果除法操作不合法,则函数将返回-1,此时我们将打印一条错误消息。否则,我们将打印计算结果。
通过在代码中使用返回值来模拟异常处理,我们可以在发生错误时采取适当的行动,并对用户提供友好的错误消息。当然,这种做法要求我们对可能出现的错误情况进行仔细的考虑,并在代码中进行适当的处理。