C语言入门
一、认识C语言
什么是C语言
C语言是一门通用计算机编程语言,广泛应用于底层开发。C语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。
尽管C语言提供了许多低级处理的功能,但仍然保持着良好跨平台的特性,以一个标准规格写出的 C语言程序可在许多电脑平台上进行编译,甚至包含一些嵌入式处理器(单片机或称MCU)以及超级电脑等作业平台。
二十世纪八十年代,为了避免各开发厂商用的C语言语法产生差异,由美国国家标准局为C语言制 定了一套完整的美国国家标准语法,称为ANSI C,作为C语言最初的标准。 [1] 目前2011年12月8 日,国际标准化组织(ISO)和国际电工委员会(IEC)发布的C11标准是C语言的第三个官方标 准,也是C语言的最新标准,该标准更好的支持了汉字函数名和汉字标识符,一定程度上实现了汉字编程。
C语言是一门面向过程的计算机编程语言,与C++,Java等面向对象的编程语言有所不同。 其编译器主要有Clang、GCC、WIN-TC、SUBLIME、MSVC、Turbo C等。
第一个C语言程序
注意:main函数是主函数是程序的入口,整个项目中有且仅能有一个main函数。
main函数的几种其他写法
数据类型
char //字符数据类型
short //短整型
int //整形
long //长整型
long long //更长的整形
float //单精度浮点数
double //双精度浮点数
为什么出现这么多的数据类型?
每种类型的大小是多少?

规定sizeof(long)>=sizeof(int)
计算机中的单位
在计算机中,数据存储和处理的单位有多种,主要包括以下几种:
1. 比特(bit):最小的数据单位,表示二进制中的一个位,可以是0或1。
2. 字节(byte):1字节等于8比特。字节是计算机中最常用的基本存储单位。
3. 千字节(KB, Kilobyte):1 KB = 1024 字节(在计算机科学中,通常使用二进制的1024,而不是十进制的1000)。
4. 兆字节(MB, Megabyte):1 MB = 1024 KB = 1,048,576 字节。
5. 吉字节(GB, Gigabyte):1 GB = 1024 MB = 1,073,741,824 字节。
6. 太字节(TB, Terabyte):1 TB = 1024 GB = 1,099,511,627,776 字节。
7. 拍字节(PB, Petabyte):1 PB = 1024 TB = 1,125,899,906,842,624 字节。
8. 艾字节(EB, Exabyte):1 EB = 1024 PB = 1,152,921,504,606,846,976 字节。
9. 泽字节(ZB, Zettabyte):1 ZB = 1024 EB = 1,180,591,620,717,411,303,424 字节。
10. 尧字节(YB, Yottabyte):1 YB = 1024 ZB = 1,208,925,819,614,629,174,706,176 字节。
ASCII码
ASCII码(American Standard Code for Information Interchange,美国信息交换标准代码)是为了在计算机和其他设备之间进行文本数据交换而设计的一种字符编码标准。
在代码中,字符'a'的ASCII码值是97,这使得计算机能够以数值形式存储和处理字符数据。通过使用ASCII码,计算机可以轻松地在字符和数值之间进行转换,从而实现文本数据的存储、处理和传输。
变量,常量
定义变量的方法
int age = 150;
float weight = 45.5f;
char ch = 'w';
变量的分类
局部变量,全局变量

上面的局部变量a变量的定义其实没有什么问题的,局部变量是可以和全局变量同名的(但是不建议)。当局部变量和全局变量同名的时候,局部变量优先使用。
变量的使用
变量的作用域和生命周期
作用域
- 局部变量的作用域是变量所在的局部范围。
- 全局变量的作用域是整个工程。
eg:a的作用域就是{}内
全部变量a的作用域是整个工程
跨文件使用全局变量,需要声明
生命周期
- 局部变量的生命周期是:进入作用域生命周期开始,出作用域生命周期结束。
- 全局变量的生命周期是:整个程序的生命周期。
常量
- 字面常量
- const 修饰的常变量
- #define 定义的标识符常量
- 枚举常量
eg2: a虽然被const修饰具有常属性,但是他本质还是一个变量
n是一个变量,创建数组报错,用const修饰n以后,依然报错,说明n被const修饰以后仍然是个变量,但是它具有常属性,不能被修改而已。所以我们把const修饰的变量叫做常变量。
字符串

字符串的结束标志是一个 \0 的转义字符。在计算字符串长度的时候 \0 是结束标志,不算作字符串内容。
eg1:ch里存储的内容,abcdef\0是初始化进去的,后面的3个\0是默认放进去的
eg2:\0的重要性
以字符串%s打印的时候,读取到\0就终止。对于arr1末尾就是\0作为结束标志,对于arr2只有找到\0才会结束打印,所以他就一直往后打印,最后可能打印到某个位置找到\0就停止了,所以中间打印出一堆随机值。对于arr3手动增加\0作为结束符,所以就正常打印。
eg3:strlen是求字符串长度的,\0是结束标志,\0不算长度
转义字符

很显然,这样是不行的,这里就需要引出转义字符,顾名思义就是转变字符的意思。

转移字符 | 释义 |
\? | 在书写连续多个问号时使用,防止他们被解析成三字母词 |
\' | 用于表示字符常量' |
\“ | 用于表示一个字符串内部的双引号 |
\\ | 用于表示一个反斜杠,防止它被解释为一个转义序列符。 |
\a | 警告字符,蜂鸣 |
\b | 退格符 |
\f | 进纸符 |
\n | 换行 |
\r | 回车 |
\t | 水平制表符 |
\v | 垂直制表符 |
\ddd | ddd表示1~3个八进制的数字。 如: \130 X |
\xdd | dd 表示 2 个十六进制数字。 如: \x30 0 |
eg1: \? ,现在的编译器已经没这个效果了,vc++6.0可以验证。三字母词就是三个符号代表一个符号
eg2:
eg3:在 printf("Hello, Worl\bld!\n"); 中,\b 将光标退回一个位置,使得字母 l 覆盖了之前的字母 l,最终输出正确的单词 World。
eg4:\r 称为回车符(Carriage Return),其作用是将光标移到当前行的行首,但不换到下一行。这意味着在输出时,\r 后面的内容会覆盖当前行从行首开始的位置。
eg5:使用 \t 将输出内容对齐,使其呈现表格形式。
每个 \t 会跳到下一个制表位,输出时看起来像是有一致的间隔。
eg6: \101、\102、\103 分别是八进制数 101、102、103,对应的十进制是 65、66、67。
这些数字对应的 ASCII 字符分别是 'A'、'B'、'C'。
eg7:
\v,\f在现代终端中都效果可能不明显,可能被视为一个空格或无效字符。实际使用也是很少。
笔试题:
注释
- 代码中有不需要的代码可以直接删除,也可以注释掉
- 代码中有些代码比较难懂,可以加一下注释文字

- C语言风格的注释 /*xxxxxx*/ 缺陷:不能嵌套注释
- C++风格的注释 //xxxxxxxx 可以注释一行也可以注释多行
选择语句
循环语句
函数
函数的特点就是简化代码,代码复用。
数组
int arr[10] = {1,2,3,4,5,6,7,8,9,10};//定义一个整形数组,最多放10个元素
比
数组的使用
操作符
+ - * / %
对于除号,如果两边都是整数,执行的是整数除法,结果还是整数;如果有一个数是 浮点数,执行的就是浮点数除法,结果就是小数;与接受除法结果变量的类型无关。
>> <<
简单说一下左移就是向左移动一位,右移就是向右移动一位,可以暂且理解成左移是乘2,右移是除2,右移在后面详细去讲解。
位操作符
& ^ |
位操作符,按2进制位进行操作
按位与 & 有0则0,没有则1
按位或 | 有1则1,没有则0
按位异或 ^ 相同为0,相异为1
ps:这里都是32个比特位,前面都是一堆0,博主为了方便只写了8位。
= += -= *= /= &= ^ = |= >>= <<=
单目操作符,只有一个操作数;eg:a+b,a和b是操作数,+是操作符,+是双目操作符
! 逻辑反操作,它的作用是将非零值转换为 0,将 0 转换为 1。- 负值+ 正值& 取地址sizeof 操作数的类型长度(以字节为单位)~ 对一个数的二进制按位取反,就是将二进制码0变为1,1变为0-- 前置、后置 --++ 前置、后置 ++* 间接访问操作符 ( 解引用操作符 )( 类型 ) 强制类型转换
逻辑反
eg:
0取反后的结果为-1
内存中存储整数的时候,存储的是二进制的补码,计算的时候采用也是补码,但是最终是以原码的形式显示的。
前置后置++
强制类型转换
>>=<<=!= 用于测试 “ 不相等 ”== 用于测试 “ 相等 ”
&& 逻辑与,表示并且,a且b|| 逻辑或,表示或者,a或者b
exp1 ? exp2 : exp3
又叫三目操作符,如果表达式1成立,结果是表达式2,否则就是表达式3
exp1 , exp2 , exp3 , …expN
逗号把一堆表达式隔开就叫做逗号表达式
下标引用、函数调用和结构成员
[] () . ->
常见关键字
auto break case char const continue default do double else enumextern float for goto if int long register return short signedsizeof static struct switch typedef union unsigned void volatile while
auto关键字
在 C 语言中,auto 关键字用于声明局部变量。实际上,所有的局部变量默认都是 auto 类型,所以使用 auto 关键字是多余的。它的作用是显式地声明一个变量为自动存储类型,但在实际编程中很少使用。
typedef关键字

register关键字
register意思是寄存器,寄存器是存储空间,在电脑上一般是集成到CPU上的,和内存是不同的独立的存储空间。
计算机上的存储空间?
越往上读写速度越快,价格越高。
CPU是中央处理器,早期CPU从内存中读取数据进行处理,处理完后返回内存,他俩的速度比较搭配,随着技术的发展,内存的读写速度提升不明显,但是CPU的读写速度提升的越来越快,甩了内存不止一条街。CPU处理的速度很快,但内存赶不上CPU的处理速度也没啥用,比如说,造房子和搬砖,刚开始造房子和搬砖的速度一致,你搬来一块砖,我就即使建造,但是后来我造房子的速度越来越快,但是搬砖的速度不变,无论你造的有多快,都没啥用,必须等砖来。
所以就衍生出高速缓存和寄存器,高速缓存比内存块,寄存器比高速缓存快,CPU就和寄存器交换数据。寄存器和高速缓存交换数据,高速缓存和内存交换数据。在CPU处理数据的同时,就把需要的数据一层一层的替换到寄存器中,这样就提高了整体的效率。
如果我将来能把我写的代码的变量的值放到寄存器中去,这样的话程序的效率就会很高。C语言允许这样去做。但是如果所有程序员都想把变量放到寄存器上这就是灾难,因为寄存器是的空间是有限的,所以register起到的作用仅仅是建议把变量放到寄存器中,编译器自己觉得是否放到寄存器中。
static关键字
修饰局部变量
i进入test后创建,++后变为1,出了test后又销毁,所以每次都打印1.static修饰局部变量改变了变量的生命周期,让静态局部变量出了作用域依然存在,到程序结束, 生命周期才结束。
修饰全局变量
代码一
代码二
一个全局变量被static修饰,使得这个全局变量只能在本源文件内使用, 不能在其他源文件内使用。 默认一个全局变量具有外部链接属性,如果全局变量被static修饰,使得全局变量的外部链接属性变成了内部链接属性,这个时候这个全局变量只能在本源文件内部使用,其他源文件无法链接到,也无法使用。
修饰函数
代码一函数也具有外部链接属性
代码二
代码1正常,代码2在编译的时候会出现链接性错误. 一个函数被static修饰,使得这个函数只能在本源文件内使用,不能在其他源文件内使用。函数是具有外部链接属性的,如果被static修饰,外部链接属性就变成了内部链接属性,函数只能在自己的源文件内部使用,不能在其他源文件内部使用。
#define 定义常量和宏
指针
内存
内存是电脑上特别重要的存储器,计算机中所有程序的运行都是在内存中进行的 。 比如说你买电脑的时候,就有4G/8G/16G,那么电脑是如何使用这些内存的呢?
生活中的例子,我们国家有960W的国土面积,如何使用呢,我们会发现,这些国土面积被划分成了各个省,市,自治区,省内部划分成市,市内部划分成县,区等等,区,县再划分成镇,村等,最后可能是某一个小区,单元楼等,某一个单元楼进去以后又是第几户等等,最终这么大的空间归结到一个一个小房间上。比如说现在我要找一个学生,你是xx大学xx校区xx宿舍楼xx号宿舍,我们就可以根据这个地址就可以唯一的找到一个房间,从而找到你。
计算机内存使用的时候也是一样,也会把他划分成一个一个小的内存单元,每个内存单元进行编号,这样我们就可以根据这个编号找到这个内存单元
我们怎么去落实呢?这个时候就需要两个问题去解决:
1.编号(地址)怎么产生? 这个内存单元的编号就可以称做地址(类比现实生活中的地址)
2.一个内存单元应该是多大的空间?
编号(地址)怎么产生?
机器可以分为32位和64位
32位机器就是有32根地址线/数据线,地址线就是物理上的电线,电线通电的时候就有正电和负电之分,正电就是1,负电就是0,电信号就转换成了数字信号,01组成的序列就是2进制序列。
可能是:
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0001
0000 0000 0000 0000 0000 0000 0000 0010
...............................
1000 0000 0000 0000 0000 0000 0000 0000
...............................
1111 1111 1111 1111 1111 1111 1111 1111
一共可以产生2^32次方2进制序列,这个时候我就可以用这么多序列管理内存单元,这些二进制序列就是内存单元的地址了,所以地址就产生了。第一个问题就解决了
一个内存单元应该是多大的空间?
首先明确计算机里的单位有bit,byte,kb,mb,gb,tb,pb...这些是属于比较常用的。
假设一个内存单元是一个比特位,一共就有2^32个内存单元
那么我2^32个地址最多管理0.5g的空间,但是对于32位机器1G/2G是非常常见的,所以如果一个内存单元的大小是1个比特位是很不合适的。
另外在C语言中
如果一个内存单元的大小是1个比特位,我们创建一个char类型的变量,就需要占8个格子,每个格子都给一个地址,那么8个地址就都被浪费了,更不用说其他类型的变量了,浪费非常严重,所以一个内存单元的大小是1个比特位很不合适。
那么一个内存单元的大小是1个字节呢?
这样总的内存空间就变成4G了,从大小上看是比较合适的。
如果创建一个char类型,用去一个地址,int类型用4个地址,貌似也比较合适。
那么一个内存单元的大小是1个kb呢?
1kb是1024字节,我如果创建char只需要1个字节,分配空间就很麻烦,我随便创建个变量最少也要浪费1kb的空间,所以也很不合适。
综合考虑那么一个内存单元的大小是1个字节比较合适。
eg:创建一个int变量占4个字节
那么这个a的地址是啥呢?4个内存单元中打印哪个内存单元的地址呢?
所以取出来变量a的地址是a所占空间这4个字节里面第一个字节的地址,而且这个地址是4个字节里最小的那个地址。通过这个小的地址,结合地址的连续性,就可以找到后面的3个字节。那么我取高地址不也可以找到前面3个字节嘛,当然也可以,只不过C语言规定变量的地址取的是第一个字节的地址,也就是最小的那个地址。
ps:每次编译变量a的地址都会改变,这是因为内存中的数据时刻在发生变化,这块空间现在你可以用,当你释放空间后,下一刻就有可能被别人用了。每次都是重新分配。
这时候我们就明白,地址就是一串数字,所以我们就可以把这串数字存起来
pa存放的就是a的地址,pa就是一个存放地址的变量,这样的变量就被称为指针变量。它的语法形式就是int *
00000017EC9CF814是一个地址,因为这个地址可以找到a这块空间,所以我们形象的把这个地址称为指针,指针就是地址,地址就是指针,pa存的是a的地址,也可以说pa存的是指针,pa就可以称做指针变量。
我们把这个地址存起来不仅仅是为了存储,有时候我需要用,比如生活中我知道你的地址,就可以给你寄一些东西。所以我们就要通过这个地址来找到这个变量a。
*pa 代表通过pa里面存的地址00000017EC9CF814找到它所指向的那块空间a,*pa的意思就是a
可以看出成功通过*pa更改掉a的值。
指针变量的大小
可以看出所有类型的指针变量都是4个字节,这是为什么呢?
根据之前讲的:机器可以分为32位和64位;32位机器就是有32根地址线/数据线,地址线就是物理上的电线,电线通电的时候就有正电和负电之分,正电就是1,负电就是0,电信号就转换成了数字信号,01组成的序列就是2进制序列。
每一根地址线就是一个比特位,一共32根就是32个比特位,也就是4个字节。所以要想把这些地址存起来,就需要四个字节。因此,任何指针变量他都是4个字节。
如果将机器改成64位,就会变成8个字节,因为64位机器,需要64根地址线,每根地址线需要一个比特位,64根地址线就需要64个比特位,也就是8个字节。
结构体
在C语言中如果遇到了复杂对象该怎么办呢?比如说学生,如果用简单的变量(int,float等)描述学生是完全不行。因为学生的属性比较复杂,比如有姓名,学号,年龄等,所以这个时候结构体就派上用场了。
创建结构体变量
.操作符,访问结构体变量
.操作符的使用方式是: 结构体变量名.成员名
→操作符,访问结构体变量
存在这样一种情况,你可能得到的是某个结构体变量的指针,这个时候就可以通过→操作符访问该结构体变量了。ps:我们同样可以采用先对结构体指针变量解引用,然后继续用.操作符。
入门算法题
学完以后,大家就可以去这个网站刷一刷入门级题目了。
牛客网在线编程_算法篇_语法入门题单