运行环境:Window11 软件环境:Visual Studio 2022
目录
一、什么是C语言?
①一门通用的面向过程的计算机编程语言,广泛应用于底层开发;
②提供简易方式编译、处理低级存储器、产生少量的机器码;
③无需任何运行环境支持便能运行,具良好跨平台特性。
二、第一个C语言程序
#include <stdio.h>
int main()
{
printf("Hello,world!"\n);
return 0;
}
备注:①main函数是程序的入口;②每个工程有且仅有一个main函数。
三、数据类型
1、C语言中的数据类型
①字符型:char;②短整型:short;③整型:int;④单精度浮点型:float;
⑤长整型:long;⑥更长整型:long long;⑦双精度浮点型:double。
2、数据类型的大小
#include <stdio.h>
int main()
{
printf("%zu\n", sizeof(char)); //1
printf("%zu\n", sizeof(short)); //2
printf("%zu\n", sizeof(int)); //4
printf("%zu\n", sizeof(long)); //4
printf("%zu\n", sizeof(float)); //4
printf("%zu\n", sizeof(long long)); //8
printf("%d\n", sizeof(double)); //8
return 0;
}
其中,zu表示打印一个sizeof返回的无符号整型;这里在VS2022最好使用%zu,若使用%d可能会报错。
四、变量
1、局部变量
①在函数体内定义的变量称为局部变量;
②其作用域为变量所在局部范围(或理解为所在函数体内);
③其生命周期为:进入作用域生命周期开始,出作用域生命周期结束(这里后面考虑换种说法)。
2、全局变量
①在函数体外定义的变量成为全局变量;
②其作用域为整个工程;
③其生命周期为整个程序生命周期。
注:
①当局部变量与全局变量同名时,局部变量优先使用;
②作用域为一段程序代码中变量名可用性的代码范围;
③生命周期指变量创建到销毁之间的时间段。
#include <stdio.h>
int global = 2019;//全局变量
int main()
{
int local = 2018;//局部变量
printf("global = %d\n", global); //2018
return 0;
}
3、变量的命名
①有意义;(如 int age;float salary等)
②命名必须是字母、数字、下划线组成,不能有特殊字符,同时不能以数字开头;
(如:i①int 2b;//err ②int _2b;//success)
③变量名不能为关键字(后面有概括关键字)。
五、常量
1、字面常量
2、const修饰的常变量
3、#define定义的标识符常量
4、枚举常量
#include <stdio.h>
//举例
enum Sex
{
MALE,
FEMALE,
SECRET
};
//括号中的MALE,FEMALE,SECRET是枚举常量
int main()
{
//字面常量演示
3.14;//字面常量
1000;//字面常量
//const 修饰的常变量
const float pai = 3.14f; //这里的pai是const修饰的常变量
pai = 5.14;//是不能直接修改的!
//#define的标识符常量 演示
#define MAX 100
printf("max = %d\n", MAX);
//枚举常量演示
printf("%d\n", MALE); //0
printf("%d\n", FEMALE); //1
printf("%d\n", SECRET); //2
//注:枚举常量的默认是从0开始,依次向下递增1的
return 0;
}
注:代码中pai由于被const修饰,故在语法层面被限制无法直接改变,但实际上pai仍是一个变量,因此pai被称为是const修饰的常变量。
六、转义字符
转义字符 | 释义 |
\? |
在书写连续多个问号时使用,防止他们被解析成三字母词(现在几乎无需关注)
|
\' |
用于表示字符常量'
|
\" |
用于表示一个字符串内部的双引号
|
\\ |
用于表示一个反斜杠,防止它被解释为一个转义序列符
|
\a |
警告字符,蜂鸣
|
\b |
退格符
|
\f |
进纸符
|
\n |
换行
|
\r |
回车
|
\t |
水平制表符
|
\v |
垂直制表符
|
\ddd |
ddd表示1~3个八进制的数字。 如: \130 X
|
\xdd |
dd表示2个十六进制的数字。 如:\x30 0
|
#include <stdio.h>
int main()
{
//问题1:在屏幕上打印一个单引号',怎么做?
//问题2:在屏幕上打印一个字符串,字符串的内容是一个双引号“,怎么做?
printf("%c\n", '\'');
printf("%s\n", "\"");
return 0;
}
扩展习题:
//程序输出什么?
#include <stdio.h>
int main()
{
printf("%d\n", strlen("abcdef")); //6
// \62被解析成一个转义字符
printf("%d\n", strlen("c:\test\628\test.c")); //14 (由于/ddd表示八进制,但是\628中8不属于八进制范围,故仅有\62)
return 0;
}
七、注释
1、C语言注释风格
/*xxxxx */(缺点:不能嵌套使用)
2、C++注释风格
//xxxxx(可以注释多行也可以注释一行)
八、选择语句
①if···else;②switch等
#include <stdio.h>
int main()
{
int select = 0;
printf("就业(0)或者读研(1)?(选择1 or 0):>");
scanf("%d", &select);
if(select == 1)
{
prinf("坚持,读研有时比就业更辛苦,但有可能收获的回报更多\n");
}
else
{
printf("先拿下一个小目标\n");
}
return 0;
}
九、循环语句
①while;②for;③do···while
十、函数
#include <stdio.h>
int Add(int x, int y)
{
int z = x+y;
return z;
}
int main()
{
int num1 = 0;
int num2 = 0;
int sum = 0;
printf("输入两个操作数:>");
scanf("%d %d", &num1, &num2);
sum = Add(num1, num2);
printf("sum = %d\n", sum);
return 0;
}
注:函数的特点为简化代码,代码复用。
十一、数组
1、数组的定义
一组相同类型元素的集合。
int arr[10] = {1,2,3,4,5,6,7,8,9,10};//定义一个整形数组,最多放10个元素
2、数组下标
C语言规定:数组每个元素都有一个下标,下标是从0开始。(若数组有10个元素,则下标范围为0-9,第一个元素对应下标为0)
注:数组可以通过下标来访问。
3、数组的简单使用
#include <stdio.h>
int main()
{
int i = 0;
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
for(i=0; i<10; i++)
{
printf("%d\n", arr[i]);
}
return 0;
}
十二、操作符
1、算术操作符
①+ ②- ③* ④/ ⑤%
2、移位操作符
①>> ②<<
3、位操作符
①& ②^ ③|
4、赋值操作符
①= ②+= ③-= ④/= ⑤&= ⑥|= ⑦^= ⑧>>= ⑨<<=
5、单目操作符
! | 逻辑反 |
- | 负值 |
+ | 正值 |
& | 取地址符 |
~ | 对数的二进制取反 |
-- | 自减 |
++ | 自加 |
* | 解引用符 |
sizeof | 操作数的类型长度(以字节为单位) |
(类型) | 强制类型转换 |
6、关系操作符
> | |
>= | |
< | |
<= | |
!= | |
== |
7、逻辑操作符
&& | 逻辑与 |
|| | 逻辑或 |
8、条件操作符
exp1 ? exp2 : exp3
9、逗号表达式
exp1,exp2,exp3```expN
10、下标引用、函数调用、结构成员
[] () . ->
十三、关键字(个人觉得重要,嵌入式面试概率大)
关键字:C语言本身内置,不为自己创建,也不能自己创建。
1、关键字相关分类
Ⅰ、循环关键字
①for ②while ③do while ④break ⑤continue
Ⅱ、选择关键字
①switch ②case ③default ④if else ⑤goto
Ⅲ、数据类型关键字
①char ②short ③int ④long ⑤float ⑥double ⑦long long
⑧signed(有符号的) ⑨unsigned(无符号的) ⑩void(函数的返回类型,函数参数)
Ⅳ、其余关键字
①const (常属性) ②enum(枚举类型) ③union (联合体)(共用体)
④struct(结构体) ⑤extern(声明外部符号) ⑥register(寄存器)
⑦return(函数返回值)⑧sizeof(计算大小)
⑨static(静态的) ⑩typedef(类型重命名) volatile(易改变的)
2、重点关键字解释(个人观点)
Ⅰ、typedef(类型重命名)
#include <stdio.h>
typedef unsigned int Node;
int main() {
unsigned int num1 = 1;
printf("%d ",num1); //输出结果:1
Node num2 = num1;
printf("%d ",num2); //输出结果:1
return 0;
}
typedef struct stu{
int name;
int age;
struct stu* message;
}st;
int main(void) {
struct stu s;
st ss; //此处s,ss两个数据类型一样
return 0;
}
Ⅱ、static
C语言中,static用来修饰变量和函数,当
①修饰局部变量:静态局部变量;(注:局部变量除了作用域,不销毁;本质为改变了变量的存储位置,改变其生命周期,与程序生命周期一致。)
②修饰全局变量:静态全局变量;
(注:①静态全局变量使得全局变量的作用域被局限在当前源文件中,即外部链接属性被修改为内部链接属性,不可被其它源文件(.c文件)使用extern调用;
②普通的全局变量具有外部链接属性,可使用extern外部声明调用。)
③修饰函数 :静态函数。
(注:被static修饰的函数,若其它源文件想要使用extern调用该函数时不可行,因为被修饰后的函数体的外部链接属性就被改为内部链接属性,与全局静态变量类似。)
void test1(){
int num1 = 0;
num1++;
printf("%d ",num1);
}
void test2(){
static int num2 = 0;
num2++;
printf("%d ",num2);
}
int main(){
int n = 0;
while(n < 10){
test1();
n++;
}
printf("\n");
while(n > 0){
test2();
n--;
}
return 0;
}
//第一个while输出结果为:1 1 1 1 1 1 1 1 1 1(10个1)
//第二个while输出结果为:1 2 3 4 5 6 7 8 9 10
为什么加了static后输出结果不一样呢?
①由于num1它是一个局部变量,存储在栈中,其生命周期为当前的作用域(即当前函数体中),当主函数调用该函数时,num1被创建,并进行+1操作输出1,之后该函数作用结束后num1就会被销毁,故下一次循环进入该函数体时num1重新被创建,又输出1,故第一个while输出结果如上所示。
②被static修饰的num2,其生命周期为整个程序,当主函数调用该函数体时该变量被创建并进行+1操作,由于为静态变量,存储在静态区,不随函数体退出而销毁,因此下一次while调用该函数体时num2变量仍存在,故在原来1上+1,其值为2,以此类推,直到while循环结束,输出结果如上。
Ⅲ、register(寄存器)(一般不常用)
CPU从寄存器中获取数据,可认为CPU读取与寄存器之间读取速度更快,若用register修饰的变量会使得该变量被优先处理。
作用:当变量存放在寄存器中,其被读写的速度更快。
include <stdio.h>
int main()
{
register int num = 1;//被读写速率更快
return 0;
}
十四、预处理命令(#define)
作用:定义常量和宏。
#include <stdio.h>
//define定义标识符常量
#define MAX 10
//define定义宏
#define ADD(x, y) ((x)+(y))
#define DDA(a,b) (a+b)
#define DA(a,b) a+b
#include <stdio.h>
int main()
{
int sum = ADD(1, 2);
printf("sum = %d\n", sum); //3
sum = 10*ADD(1, 2);
printf("sum = %d\n", sum); //30
sum = 10*DDA(1, 2);
printf("sum = %d\n", sum); //30
sum = 10*DA(1, 2);
printf("sum = %d\n", sum); //12
return 0;
}
注:注意观察上方使用#define 定义宏时的格式。
十五、指针(重要)
1、内存初理解
(注:变量创建时实际上内存给变量分配了空间,每个内存单元都有地址,故变量也有地址。)
2、取变量地址
/*代码功能:取变量地址*/
#include <stdio.h>
int main()
{
int num = 10;
printf("%p\n", &num);
//打印地址,&num取出num的地址;%p是以地址的形式打印
//注:这里num的4个字节,每个字节都有地址,取出的是第一个字节的地址(较小的地址)
return 0;
}
输出结果为:0x7ffe12cb3dc8(注:此处的输出结果具有特异性)
3、地址存储(定义指针变量)
#include <stdio.h>
int main()
{
int num = 10;
int *p = #//p为一个整形指针变量,存储的是num的地址
*p = 20;//*p指的是num对象
printf("%d ",num);
return 0;
}
输出结果为:20
4、指针变量的大小
#include <stdio.h>
//指针变量的大小取决于地址的大小
//32位平台下地址是32个bit位(即4个字节)
//64位平台下地址是64个bit位(即8个字节)
int main()
{
printf("%zu\n", sizeof(char *));
printf("%zu\n", sizeof(short *));
printf("%zu\n", sizeof(int *));
printf("%zu\n", sizeof(double *));
return 0;
}
(注:VS2022中X86为32位平台,X64为64位平台)
输出结果:x64 指针变量都为8字节(64bit); x86 指针变量都为4字节(32bit)
十六、结构体
#include <stdio.h>
struct Stu
{
char name[20];//名字
int age; //年龄
char id[15]; //学号
};
int main()
{
//打印结构体信息
struct Stu s = {"柒", 20, "20240427"};
//.为结构成员访问操作符
printf("name = %s age = %d id = %s\n", s.name, s.age, s.id);
//->操作符
struct Stu *ps = &s;
printf("name = %s age = %d id = %s\n", ps->name, ps->age, ps->id);
return 0;
}
输出结果如下:
name = 柒 age = 20 id = 20240427
name = 柒 age = 20 id = 20240427