一、什么是C语言

C语言是一门面向过程的计算机编程语言,最常见用于底层开发。所谓计算机就是由应用软件、操作系统、驱动层、硬件等组成,在操作系统(含操作系统)之下的部分都叫做底层(下层)。

C语言是一门国际上最通用的计算机语言,为了避免因为各开发厂商根据自己的需求而构建不同的C语言体系,所以美国国家标准局制定了一套完整的美国国家标准C语言语法,为ANSI C,作为C语言最初的标准。现在最常用的C语言国际标准为c89和c90,最新的C语言标准为c11;

主流的编译器主要有Clang、GCC、WIN-TC、MSVC

注:什么是编译?

c/c++是编译型计算机语言,编译是一个对代码进行处理的动作。一个test.c文件通过编译、链接后形成可执行文件test.exe。

二、第一个C语言程序

2.1 编译器

推荐使用vs,附:vs2022安装使用教程

2.2 第一个C语言程序的书写及注意事项

第一步:打开VS;

第二步:创建项目;

(1)创建新项目;

(2)选择空项目

①修改项目名称(有条理性)

②修改文件地址(自己创建一个专门的文件夹,路径不要出现中文名)

③完成;

第三步:创建源文件(.c文件)

(1)右击源文件;

(2)添加新建项——选择c++文件,将名称改为xxx.c形式;

第四步:写代码

#include//main函数是程序的入口,一个工程中main函数有且只有一个int main(){printf("hello world");return 0;}

注:使用vs编译器时,由于对于vs编译器来说scanf(输入函数)和printf(输出函数)都是不安全的函数,所以在运行过程当中,会出现函数报错的现象,因此需要在代码的最开头使用宏定义(#define _CRT_SECURE_NO_WARNINGS)来防止运行报错。

解决办法:

通过:Microsoft Visual Studio\2022\Community\Common7\IDE\VC\VCProjectItems找到一个叫做newc++file.cpp文件(直接通过文件夹查找也行),将此文件复制到桌面,通过记事本打开,将#define _CRT_SECURE_NO_WARNINGS粘贴进去,保存后关闭(使用管理员权限)。将修改过的文件重新粘贴回去,替换原来的文件。

原理:

vs每次创建源文件的时候,都会先拷贝一份newc++file.cpp中的内容,所以修改此文件,即可完成输入输出不报错处理;

三、数据类型

数据类型名称大小打印数据量数据率
char字符型1B%cbitbit/s
short短整型2B%hd1Byte=8bit1Kb/s=1000b/s
int整型4B%d1KB=1024B1Mb/s=1000Kb/s
long长整型4B%ld1MB=1024KB1Gb/s=1000Mb/s
long long更长的整型8B1GB=1024MB1Tb/s=1000Gb/s
float单精度浮点型4B%f1TB=1024GB
double双精度浮点型8B%lf数据类型大小sizeof(int)

(1)以上表格打印整数类型均为十进制、无符号形式输出,如果想要了解更多,可以参考C语言类型输出语句;

(2)数据类型:定义变量/常量/数组等等;申请形式:数据类型 变量名/常量名/数组名=xxx(值)

(3)数据类型有两种,一种是系统内置的数据类型,比如说char,int等;还有一种是自定义的数据类型,比如说枚举常量。

四、常量、变量

4.1 变量与常量

对于固定不变的值,我们直接定义常量:数据类型 常量名=xxx(值);

对于可以改变的值,我们直接定义变量:数据类型 变量名=xxx(值);

4.2 变量

4.2.1 局部变量与全局变量

变量分为全局变量和局部变量,相同级别的变量不能重复定义;

当全局变量和局部变量名字重复的情况下,局部变量优先级更高;

int main(){int num1=0;int num2=0;scanf("%d %d",&num1,&num2);int sum=num1+num2;printf("%d\n",sum);return 0;}

4.2.2 变量的作用域

(1)作用域是程序设计概念,通常来说,一段程序代码所用的名字并不总是有效的。而限定这个名字的代码范围就是这个名字的作用域;

(2)局部变量的作用域:变量所在的代码块内(离得最近的一个{}中);

(3)全局变量的作用域:整个工程(如果来自不同的文件,需要用“extern 数据类型 变量名”来引用全局变量);

4.2.3 变量的生命周期

(1)变量的生命周期指的是从变量的创建到销毁之间的一个时间段

(2)局部变量的生命周期:从进入作用域时生命周期开始,到出作用域时生命周期结束;

(3)全局变量的生命周期:整个程序的生命周期;

4.3 常量的类别

4.3.1 字面常量

直接能从字面上看出来的叫做字面常量

int main(){printf("0101001");//直接能从字面上看出来的叫做字面常量return 0;}

4.3.2 以const修饰的常变量

以const修饰的常变量在C语言中只是在语法层面上限制了变量无法直接被修改,但是本质上还是一个变量,只是具有常量的属性,所以被称为常变量

int main(){const int a=0101001;//用const修饰的常变量一般情况下不可修改;printf("%d\n",a);return 0;}

4.3.3 以define定义的标识符常量

define定义的标识符常量格式为:#define 常量名值(无需;)

#define MAX 100#define STR "abcdefg"int main(){printf("%d\n",MAX);printf("%s\n",STR);RETURN 0;}

4.3.4 枚举常量

枚举常量:生活中可以一一列举出来保持不变的值;

enum Color{//三原色RED,GREEN,BLUE};int main(){enum Color a=RED;return 0;}

五、字符串、转义字符、注释

5.1 字符串

在C语言中,由双引号引起来的一串字符称为字符串字面值/字符串;在C语言中用字符数组存储字符串;

字符串的结束标志是一个\0的转义字符,在计算字符串长度的时候这个转义字符是结束标志,不算做字符串的内容;(计算字符串长度的函数:strlen()——需要引用头文件

int main(){char arr1[]="abc";char arr2[]={'a','b','c'};char arr3[]={'a','b','c','\0'};printf("%s\n",arr1);//abcprintf("%s\n",arr2);//abc烫烫烫烫烫abc(未接收到\0,因此乱码)printf("%s\n",arr3);//abcreturn 0;}

在计算机语言当中,底层的逻辑是二进制的语言,但我们通过键盘输入的并不是二进制的语言,是因为编译器通过ASCII码表查询了ASCII码值(输入的二进制数字转换为十进制)所对应的字符,从而读取。

完整的ASCII码表的链接参考:ASCII码表完整版

5.2 转义字符

在c语言中,有一些字符通过\的转义序列符,更改了他们原本所有的含义,从而获得了新的功能,这种字符我们称之为转义字符

转义字符释义
\?在书写连续多个问号的时候使用,防止被解析为三字母符
\”用于表示一个字符串内部的双引号
\\用于表示一个反斜杠,防止被解析为一个转义序列符
\dddddd表示1~3个八进制数字,如:\130(打印结果是这个八进制数字在ASCII对应的结果)
\xdddd表示2个十六进制数字,如:\x30
转义字符释义转义字符释义转义字符释义
\a警告字符,蜂鸣\t水平制表符\v垂直制表符
\b退格符\f进纸符\n换行
\’用于表示字符常量’\r回车

5.3 注释

1. 代码中有不需要的代码可以直接删除,也可以注释掉;

2.代码中有些代码对于自己和阅读者来说比较复杂,可以通过注释来解释和记忆;

3.在C语言中有(/*…*/)和(//)两种方式注释;

六、选择循环语句、函数和数组

6.1 选择语句与循环语句

C语言是结构化的程序设计语言,分为三种结构:顺序结构,选择结构,循环结构

C语言中的选择结构有:if…else语句;switch语句;

C语言中的循环结构有:while语句、do…while语句、for循环语句;

6.2 函数

函数就是为了简化函数,提高代码的复用率。C语言中的将一段实现同一个功能的代码封装成函数,这样在需要这个功能的时候,可以直接函数调用,而无需书写全部过程,提高了代码的复用率。例如:将“求两个函数的和”封装成一个函数Add,这样以后在求两数之和时,可以直接调用Add函数。

int Add(int x,int y){return x+y;//将x+y作为Add的结果返回出去;也叫返回值;}int main(){int a,b;scanf("%d %d",&a,&b);//scanf为输入函数,&为取地址符,输入需要,输出不需要。int c=Add(a,b);//接收到Add的返回值a+b;printf("%d\n",c);return 0;}

6.3数组

数组是一组相同数据类型元素的集合;

创建数组的方式:数据类型 数组名[数组容量]={元素1,元素2,…,元素n}

数组元素的下标:数组在申请元素的时候是连续的,有下标进行指向,数组的下标是从0开始的,也就是说第一个元素的下标是0,以此类推;

int main(){int arr[]={a,b,c,d,e,f,g};for(int i=0;i<7;i++}//for(初始条件;循环条件;附加条件){};i++的意思就是i=i+1;{printf("%d\n",arr[i];}return 0;}

七、操作符

7.1 算术、移位、位、赋值操作符

算术操作符+(加)-(减)*(乘)/(除)%(取模)
移位操作符>>和<<左移和右移,和二进制运算有关
位操作符&、|、^按位与、按位或、按位异或
赋值操作符=-=+=/=%=
&=(类推)>>=(类推)i+=1相当于i=i+1
int main(){int a=7/2;//结果为3,因为在C语言中的,当除号的两端都是整数的时候,执行的是整数除法float b=7/2.0;//只要两端有一个浮点数,就执行浮点数除法;int c=7%2;//取模;取模操作符的两个操作数只能是整数;printf("%d\n",a);//结果为3;printf("%.1f\n",b);//.1f的意思就是保留一位小数,.2f同理;printf("%d\n",c);//1return 0;}

7.2 单目操作符

只有一个操作数的操作符叫做单目操作符;

逻辑反操作负值+正值&取地址符
sizeof操作数类型大小~对一个数的二进制按位取反
++前置、后置++前置、后置–
*解引用操作符(类型)强制类型转换
int main(){int a=10;int b=a++;//先使用,后++;相当于b=a;a=a+1;int c=++a;//先++,后使用;相当于a=a+1;c=a;printf("%d %d\n",a,b);//a=11;b=10printf("%d %d\n",a,c);//a=12;c=12return 0;}

(1)强制类型转换的格式:数据类型 变量名=(需要强制转换的类型)值;如果把浮点数进行强制类型转换成整数,则舍弃小数部分;

(2)sizeof是获取操作数的类型大小,可以对操作数使用,也可以对操作数的数据类型使用。如果对数组使用,则可以获取数组的大小。

(3)可以通过sizeof(arr)获取整个数组的大小,通过sizeof(arr[0])获取单个元素的大小,通过sizeof(arr)/sizeof(arr[0])获取数组元素的个数;

7.3 关系操作符(均用于判断大小/是否相等)

>大于<小于!=不等于
>=大于等于<=小于等于==等于

7.4 其他操作符

(1)逻辑操作符:(&&)逻辑与操作符;(||)逻辑或操作符;

(2)条件操作符:exp1?exp2:exp3——是一个三目操作符,如果表达式为真,则取exp2的值;如果表达式为假,则取exp3的值;

(3)逗号操作符:用于逗号表达式,逗号表达式就是用逗号隔开的一串表达式,特点是从左向右依次计算,整个表达式的结果是最后一个表达式的结果

八、常用关键字、define定义常量和宏

8.1 常用关键字简介

关键字是C语言本身内置的,这些关键字都是语言本身预先设定好的,用户是不能自己创建关键字的;

charshortintlongfloatdouble
forwhiledo whilebreakcontinuegoto
switchcasedefaultconst(常属性)static(静态的)enum(枚举)
extern:声明外部符号signed:有符号的unsigned:无符号的
register:寄存器struct:结构体union:联合体(共用体)
return:函数返回值sizeof:计算大小(用%zu打印)typedef:类型重命名
void:代表无(函数的返回值,函数参数)

变量命名的规则:

(1)变量的命名必须有意义(练习除外),比如提到年龄,一般都要用age;

(2)变量命名只能由字母、下划线和数字组成,不能有特殊字符,且不能以数字开头

(3)变量的命名不能是关键字:但是可以进行大小写变化,比如For就可以;

8.2 特殊关键字讲解

8.2.1 关键字typedef

typedef是类型定义,主要指的是类型的重新定义。比如在定义无符号数时使用unsigned int太过于麻烦,可以使用(typedefunsigned int uint;)来重新定义类型,之后在定义无符号数时就可以直接用uint来定义了。

同理,type也常用于结构体定义,基本格式是:typedef 结构体名{}重定义名。之后在定义结构体时可以使用重定义名来定义了。

8.2.2 关键字static

作用:修饰变量和函数

(1)静态局部变量——用static关键字修饰局部变量

局部变量在进入函数时候创建,在出函数的时候销毁;使用static关键字对局部变量进行修饰后,在出了作用域的时候不会被销毁;

本质上:一般情况下局部变量的存储位置是在栈区中,用static关键字修饰局部变量后,改变了局部变量的存储位置,放入静态区中,从而起到保护的作用;

(2)静态全局变量——用static关键字修饰的全局变量

全局变量定义后可以在其他源文件中使用,只要用(extern 数据类型 变量名)的方式进行链接就可以了,这得益于全局变量的外部链接属性;

但是用static修饰全局变量的时候,这个全局变量的外部链接属性就变成了内部链接属性,其他源文件就不能再使用这个全局变量了。

(3)静态函数——用static关键字修饰函数

类比于静态全局变量,用static关键字修饰函数时,函数的外部链接属性变成了内部链接属性,其他源文件无法使用这个函数。

register——寄存器关键字——创建寄存器变量——register 数据类型 变量名=值;

只是建议将此变量放入寄存器中,以在大量使用时提高运行速度。(了解即可,无需掌握)

8.3 define定义常量和宏

#define MAX 1000 //define定义标识符常量;#define ADD(x,y) ((x)+(y))//宏名(宏的参数,是无类型的) (宏体)#includeint main(){int sum=ADD(2,3);printf("sum=%d\n",sum);return 0;}

define不是一个关键字,而是一个预处理指令

九、指针

9.1内存

内存是电脑上非常重要的存储器,计算机中程序的运行都是在内存上运行的。为了有效的进行内存的使用,会把内存划分为一个个较小的内存单元,每个内存单元的大小为1个字节。另外,为了有效的进行访问内存单元,会对内存单元进行编号,也就是所谓的内存单元的地址

9.2 指针与指针变量

计算机对内存单元进行编号之后,对于我们来说内存的编号 =地址 = 指针;所以当我们创建一个变量用于存放内存单元的地址,也就是指针的时候,我们就把这个变量称之为指针变量。

int main(){int a=10;//向内存申请4个字节,存储10;printf("%p\n",&a);// &是取地址操作符;int* p=&a;//p就是指针变量,int代表的是指针变量p所指的内存中的值的数据类型,*是指针变量的标志*p=20;// *是解引用操作符,意思是通过p中存放的地址,找到p所指向的对象,*p就是p指向的对象printf("%d\n",a);//也就是说,*p和a指的是同一个值,在某种意义上来说是等同的。return 0;

对于指针变量来说,指针变量所存放的地址是那个变量/数组的首地址。

9.3 指针变量的大小

(1)不管是什么类型的指针,都是在创建指针变量,指针变量就是用来存放地址的。

(2)指针变量的大小取决于一个地址存放的时候需要多大的空间;

比如:在32位机器上,存放地址需要32个bit位,也就是4个byte,所以指针变量的大小是4个字节。换到64位机器上,也就是8个字节,即指针变量大小是8个字节。

十、结构体

结构体是C语言中特别重要的知识点,结构体使得C语言有能力描述复杂类型。

对于人来说,需要姓名、性别、年龄等信息来描述一个人的具体信息,而普通的数据类型无法对这一类的集合进行描述,因此C语言就给予了自定义类型的能力,而自定义类型中有一种叫做:结构体,通过关键字struct来实现;

结构体就是把一些单一类型的值组合在一起的行为;

struct Stu//学生{//成员char name[20];int age;char sex[10];char tele[12];};void print(struct Stu* ps){printf("%s %d %s %s\n", (*ps).name, (*ps).age, (*ps).sex, (*ps).tele);printf("%s %d %s %s\n", ps->name, ps->age, ps->sex, ps->tele);//结构体指针变量->成员名}int main(){struct Stu s = {"张三",20,"男","18133442636"};printf("%s %d %s %s\n", s.name, s.age, s.sex, s.tele);print(&s);return 0;}