初识C语言
- 什么是C语言:
- 环境配置(VS2019介绍):
- 你的第一个C语言程序
- 常量与变量
- 变量的分类
- 局部变量与全局变量的对比
- 变量的使用:
- 变量的作用域和生命周期(重要)
- 生命周期
- 常量
- 字符串+转义字符+注释
- 转义字符
- ASCII码
- 选择语句
- 循环语句
- 函数
- 数组
- 操作符
- 算术操作符
- 移位操作符
- 位操作符
- 赋值操作符
- 单目操作符(只有一个操作数)
- 关系操作符
- 逻辑操作符
- 条件操作符
- 逗号表达式
- 下标引用、函数调用操作符
- 常见关键字
- typedef
- register
- static
- #define定义常量和宏
- 指针
- 结构体
目标:基本理解C语言的基本知识
什么是C语言:
C语言是一门面向过程的、抽象化的通用程序设计语言,广泛应用于底层开发。C语言能以简易的方式编译、处理低级存储器。C语言是仅产生少量的机器语言以及不需要任何运行环境支持便能运行的高效率程序设计语言。尽管C语言提供了许多低级处理的功能,但仍然保持着跨平台的特性,以一个标准规格写出的C语言程序可在包括类似嵌入式处理器以及超级计算机等作业平台的许多计算机平台上进行编译。 ——引自百度百科
C语言是一门高级语言,计算机中的语言进化过程:
C语言国际标准的统一(ANSI C)
作用:统一标准,在C语言刚出现时,每个公司有每个公司的标准,各不相同,导致C语言的普适性差,所以在人们日益强烈地要求对C语言进行标准化。
如果未统一标准,我们会看见孔径不一样的插座,因为每个国家的标准都不一样,导致我们的充电器不统一。
1983年,美国国家标准协会(ANSI)组成了一个委员会,创立了 C语言 的一套标准。
该标准在1989年完成,被称作ANSI C,也称C89标准。
环境配置(VS2019介绍):
Visual Studio 2019(又称MSVC)是微软旗下的一款 集成开发环境,它拥有编辑器,编译器,调试器等众多功能。
我们来学习一下如何配置VS2019:
Visual Studio: 面向软件开发人员和 Teams 的 IDE 和代码编辑器 (microsoft.com)这是Visual Studio的中文官网,大家可以从官网下载最新的Visual Studio。
下载安装后,请打开Visual Studio.
你将会看到VS 的欢迎界面:
点击创建新项目
我们一般创建的是空项目,点击空项目进行创建。
上方是我们的项目名称,下方是我们的项目路径。
**注意:**项目名称不要用汉字、特殊符号、空格。尽量以日期命名。
项目路径单独创建一个保存代码的地方,不用默认路径。
点击创建后,会来到代码编辑区,不过这里仍是一片空白,找到你的解决方案资源管理器。
在源文件处右键选择添加“新建项”
选择“C++文件”,并在名称栏处起好名字。
注意:.c文件是我们C语言的源文件,.h文件是我们C语言的头文件。
你的第一个C语言程序
我们这就进入了代码区.
写C语言规范:
先写项目所要包含的头文件
再写int main()(因为main函数称为主函数,主函数是一个项目的入口,如果主函数结束,项目也运行完毕)
#include<stdio.h>
int main()
{
//代码
return 0;
}
试着在你的代码区输入如下代码
#include<stdio.h>
int main()
{
printf("Hello World!\n");
return 0;
}
这里我们引入了printf
printf是C语言中进行打印输出的库函数,那么既然他是库函数,那么库函数的使用需要什么呢?
需要包含头文件
#include<stdio.h>
stdio又是什么呢?
std :standard 的缩写。
i: input (输入的简写)
o: output(输出的简写)
这是我们学习的第一个头文件。
打个比方:如果我需要借用一下小明的东西,那我是不是需要给小明打一声招呼?
包含头文件也是这个作用,我需要调用库里的函数,我需要和标准库说一声“欸 哥们,用一下你的函数,谢谢了”。
在VS2019中,编译+链接+运行的快捷键是ctrl+F5,调试是F10,接下来我们会用到。
我们接着往下走
#include<stdio.h>
int main()
{
printf("Hello World!\n");
return 0;
}
看到了int main()
main代表主要,所以这是我们的主函数。
主函数是整个程序的入口,如果我们有多个main函数,那程序就不知道如何入手了。
所以 每个工程只能有一个main函数。
那么main前面的int 是什么呢?
int 是函数返回参数类型
我们来看一个函数的标准定义
void Function(形式参数列表)
第一个关键字是函数的返回值类型,我们这里写的是void ,它代表返回空类型。
Function是函数名,()括号里是形式参数列表。
一个工程只能有一个main函数,但大家看下图,我新建了一个文件,如果再写一个main函数行不行呢?
答案是否定的,我们来区分一下工程和文件。
c语言中工程跟文件区别为:主体不同、编译不同、命名空间不同。
一、主体不同
1、工程:工程本身就是一个主体,包含多个代码文件、资源文件等。
2、文件:文件属于工程的一部分,在创建工程时伴随产生,并可继续增加。
二、编译不同
1、工程:工程可以直接进行编译和运行。
2、文件:文件不可以直接进行编译和运行,需要有完整的工程才可执行。
三、命名空间不同
1、工程:工程的命名空间以建立工程时输入的工程名为主。
2、文件:文件依附于所在的工程,命名空间对应工程的命名空间。
计算机的出现就是为了解决我们现实中的问题。
那么计算机是如何描述问题的呢?
这里我们引入数据类型。
C语言提供的数据类型:
大家看完这个表可能有一点疑问,long为什么和int所占的字节数一样呢?long不是长整型吗?理应大于int呀。
C语言中规定 sizeof(long)>=sizeof(int)即可。
sizeof是我们测量一个数据类型/变量大小的函数。
既然讲到了sizeof,那么计算机中存储单位是什么呢?
是字节。
下面这个表格是各个单位数的换算。
比特位存储一个0或1。
一下是他们的单位换算。
1Byte == 8Bits
1KB ==1024Bytes
1MB == 1024KB
1GB == 1024MB
1TB ==1024GB
1PB ==1048576GB
sizeof 1表示什么呢?
为了严谨性,排除格式控制符的干扰,我选择用C++演示。
可以看到sizeof(1)是4个字节,为什么呢?因为它是一个整型数据,所以返回4个字节。
我们来看一下各个类型所占的字节数。
32位与64位对比
警告处理 %d 64位用:
%u是无符号整型类型输出控制符。
C语言库提供的类型 叫做C语言内置类型。
自己创建的类型 叫做自定义类型。
常量与变量
定义:常量表示不变的数据量 变量表示可变的数据量
那么如何定义一个变量呢?
int a = 0;
上面的代码是我推荐的定义变量的方法。 在定义的同时完成了初始化,因为如果不初始化变量,我们从内存中去空间地址时,拿到的是随机值,初始化就可以避免取出随机值的情况。
变量的分类
1.局部变量
2.全局变量
3.自由变量
C语言中以花括号为范围限制,在函数体花括号外的为全局变量,在花括号内部的叫做局部变量,凡是跨了自己的作用域的变量都叫自由变量。
在我们进行变量值输出时,除了格式控制符的其他字符如何输出呢?
int a = 100;
printf("a的值 = %d",a);
如上代码,除格式控制符的其他字符直接写在**“ ”**内,也即原样输出。
局部变量与全局变量的对比
如果我们有一天将全局变量和局部变量的名字定义成一样的,那么编译器该如果选择呢?
如下图:
我们看到编译器输出了局部变量。
规则:若全局变量与局部变量名字重复,则执行局部优先法则。
局部变量就是在一段范围内起作用的变量,如果出了这个范围,那么局部变量将会失效。
变量的使用:
完成两个整数的相加
#include<stdio.h>
int main()
{
int a = 0;
int b = 0;
int sum = 0;
scanf("%d %d",&a,&b);
sum = a+b;
printf("%d\n",sum);
return 0;
}
这里我们看到了scanf这个库函数,注意 : 此函数是从键盘读取输入,在后面声明变量时需要加上取地址符号**&**。
变量如何使用呢?
即 需要变量就创建变量,去完成各种类型的操作。
遇到问题就查,你会变成更优秀的自己。
变量的作用域和生命周期(重要)
作用域概念:在哪里可以使用哪里就是它的作用域。
全局作用域:整个工程都可使用。
演示:
extern 这个关键字是声明外部引用的意思。
生命周期
定义:变量创建到销毁的时间段。
出作用域, 没必要存在——局部生命周期
全局:整个工程的生命周期(与工程共存亡)
程序的生命周期是main函数的生命周期。
常量
不变的量就是常量
- 字面常量
- const修饰的常变量
- #define定义的标识符常量
- 枚举常量
//1.字面常量
20;
3.14
'a'//字符常量
"abc"//字符串常量
//2.const——常属性 语法层面被修饰者不能被修改。
//const是关键字
int num = 10;
//此时num可以被修改
**const** int num = 10;//此时num不可被修改 重新赋值会报错 但是num本质是变量
吗,
int arr[10] = {0};
//证明本质是变量
int n = 10;
int arr[n] = {0};//无法创建
//3.#define 定义的标识符常量
#include<stdio.h>
#define M 100 //记清楚顺序
int a = M;
printf("%d",a);
//4.枚举常量 一一列举
enum Sex{
MALE,
FEMALE,
SECRET
};
int main(){
enum Sex s = MALE;
printf("%d",s);
return 0;
}
字符串+转义字符+注释
C语言中没有字符串类型
“abc”——字符串
char arr[] = "abc";//隐藏有\0
char arr2[3] = {'a','b','c'};//无\0 加'\0'就一样了
printf("%s\n",arr);
printf("%s\n",arr2);//后面会有随机值 因为没有\0结束标志
F10进行代码调试
开监视窗观察
‘ \0 ’ 是字符串的结束标志,不算做字符串的内容
//求字符串长度
strlen ——库函数 include<string.h>
strlen(arr); 控制符——%d
strlen计算的是\0之前出现的字符的个数
一个汉字占两个字符
转义字符
转变原来的意思。
转义字符 | 意义 | ASCII码值(十进制) |
---|---|---|
\a | 响铃(BEL) | 007 |
\b | 退格(BS) ,将当前位置移到前一列 | 008 |
\f | 换页(FF),将当前位置移到下页开头 | 012 |
\n | 换行(LF) ,将当前位置移到下一行开头 | 010 |
\r | 回车(CR) ,将当前位置移到本行开头 | 013 |
\t | 水平制表(HT) (跳到下一个TAB位置) | 009 |
\v | 垂直制表(VT) | 011 |
\ | 代表一个反斜线字符’‘’ | 092 |
’ | 代表一个单引号(撇号)字符 | 039 |
" | 代表一个双引号字符 | 034 |
? | 代表一个问号 防止被解析成三字母词 | 063 |
\0 | 空字符(NUL) | 000 |
\ddd | 1到3位八进制数所代表的任意字符 | 三位八进制 |
\xdd | dd为十六进制所代表的任意字符 | 十六进制 |
%d打印整型
%s打印字符串
%c打印字符
printf("C:\\test\\test.c");
换行符就是另起一新行,光标在新行的开头;
回车符就是光标回到一旧行的开头(即光标目前所在的行为旧行)
printf("%c\n",'\130');//\130代表的是
//把130这个八进制数字转换成10进制后得到的88作为ASCII码值代表的字符
1 3 0
8^2 8^1 8^0
64+24 == 88 —— X
printf("%c\n",'\x31');
//31这个16进制转换成10进制所代表的ASCII码
//49 —— '1'
ASCII码
printf("%d\n",strlen("c:\test\628\test.c"));//14
//\t算一个字符 但是它的效果是多个字符
ctrl+kc 注释
CTRL+ku取消注释
1.注释用来解释代码
2.注释掉一些不需要的代码
选择语句
实现分治效果
if()
{
}
else if()
{
}
else
{
}
循环语句
while(line<20000)
{
printf("敲代码\n");
line++;
}
if(line<20000)
{
printf("好好学习\n");
}
else
printf("拿到心仪的offer");
return 0;
while
for
do while
C语言是一种结构化的程序设计语言
顺序结构、选择结构、循环结构。
函数
为了提高复用性 封装起来 哪里都可以用
int Add(int a,int b)
{
return a+b;
}
int num1 = 0;
int num2 = 0;
scanf("%d %d",&num1,&num2);
sum = Add(num1,num2);
printf("%d",sum);
把函数想象成一个工厂。
原材料经过工厂输出产品
数组
能够存放一组相同类型的元素
int arr[10] = {1,2,3,4,5,6,7,8};//定义数组
int arr2[100] = {1};//第一个元素是1,后面的元素默认为0.
//下标 0~99 下标从0开始
//输出写循环
while(i<99)
{
printf("%d",arr[i]);//访问数组
i++;
}
C99 引入变长数组 可以用变量定义数组
操作符
算术操作符
+ - * / %
printf("%d",7/3);//2...1
//两边都是整型,出来结果也是整型
printf("%d",7.0/3);
//只要出现小数就执行小数除法。
printf("%d",7%3);
//1 取余操作(取模)
移位操作符
>> << //移动的是二进制位
位操作符
& ^ |
按位与 按位异或 按位或
赋值操作符
= += -= /= *= %= &= ^= |= >>= <<=
复合赋值符
单目操作符(只有一个操作数)
+ ——两个操作数 双目操作符
只有一个操作数
! - + & sizeof ~ -- ++ * (类型)
逻辑非 负 正 取地址 类型长度 二进制位按位取反
C语言中,0表示假,非0表示真
int flag = 0;
if(!flag)
{
printf("hehe\n");
}
return 0;
sizeof//求类型大小或变量大小
int a = 10;
printf("%d",sizeof(a));//单位是字节
int a = 10;
int b = ++a;//前置++ 先++后使用
int c = a++;//后置++ 先使用后++ //int c = a; a = a+1;
//a会改变原值
printf("a = %d,b = %d,c = %d",a,b,c)//12 11 10
int a = (int)3.14;//强制类型转换
关系操作符
前提是可以比较
> < >= <= != ==
逻辑操作符
&& ||
逻辑与 逻辑或
只关注真和假
int a = 3;
int b = 4;
if((a == 3) && (b==4))//两边都得满足才算满足
{
printf("hehe\n");
}
if((a == 3) ||(b == 5))//一边满足就满足
{
printf("haha\n");
}
条件操作符
exp1 ? exp2 : exp3 (三目操作符)
如果exp1成立,则是exp2
反之,exp3
int a = 3;
int b = 5;
int c= 0;
printf("%d",((a>b) ? (a) : (b) ));//括号括起来是为了表达它是一个表达式
逗号表达式
exp1,exp2,exp3,...expn
int a = 3;
int b = 20;
int c = 0;
int d = (a-=3,b+=a,c=a-b,b=a-4);//表达式会从左到右以此计算,
//整个表达式结果是最后一个表达式的结果
所以d就是-4
下标引用、函数调用操作符
[ ] 下标引用操作符,操作数:数组名和下标
arr[10] = 1;
int Add(int a,int b)
{
return a+b;
}
int main()
{
int m = Add(3,5)// ()函数调用操作符,操作数:函数名,3,5
}
常见关键字
auto
int main()
{
auto int a = 10;//局部变量自动创建自动销毁
}
break
switch、循环语句会用到
case - switch
continue - 循环
default - switch语句
goto - 它将控制流程无条件地转到另一条语句
register - 寄存器
signed - 有符号的
unsigned - 无符号的
typedef - 类型重命名
union - 联合体
typedef
unsigned int num = 10;
typedef unsigned int uint;//起别名
register
int num = 10;//4个字节
register int num2 = 20;// 建议将20放在寄存器中
CPU从寄存器里拿数据,因为读取速度很快,提高了处理速度。
从底向上依次传数据。
static
更改存储位置
可以修饰局部变量、
全局变量、
函数
void test()
{
int a = 5;
a++;
printf("%d",a);
}
int i = 0;
while(i<10)
{
test();
i++;
}
//打印出来10个6
void test()
{
static int a = 5;//只在第一次创建,以后就不创建了
a++;
printf("%d",a);
}
int i = 0;
while(i<10)
{
test();
i++;
}
//打印出来6-15
//因为不销毁了,保留上一次的值。
//局部变量就变成了静态局部变量,出了局部作用域,不会销毁,生命周期延长,下一次进入函数依然存在。
//static修饰的局部变量存储在静态区(修改了存储位置,作用域没有发生变化)
//本来局部变量在栈区,被static修饰放在了静态区,从而导致出了作用域不会销毁
//仍然可以被改变
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LmJk6eqT-1668236760731)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/cde816bf-3f6f-487a-b9c9-d20347d2aa29/Untitled.png)]
静态区中的数据的生命周期是和程序的生命周期一致的,程序结束,静态数据的生命周期也就到了。
main函数结束,程序就结束。
static 修饰全局变量
static int g_val = 2021;
extern int g_val;//声明外部符号
//另一个文件
int main()
{
printf("%d",g_val);//无法被使用
return 0;
}
一个全局变量是具有外部链接属性的,但是被static 修饰后,外部链接属性就变成了内部链接属性。
只能在自己所在的源文件里使用,不能在其他文件内部使用。
static 修饰函数
代码是从main函数进入,从上至下扫描的。
static int Add(int x.int y)//也没有外部链接属性了,只能在自己所在的源文件使用,其他文件无法使用
{
int z = x+y;
return z;
}
//声明来自外部的符号
extern int Add(int x,int y);
int main()
{
int a = 10;
int b = 20;
int ret = Add(a,b);
printf("%d\n",ret);
}
#define定义常量和宏
#define MAX 100 //一般全大写
int main()
{
int m = MAX;
printf("%d",m);
return 0;
}
int main()
{
//预处理阶段会变成
int m = 100;
printf("%d",m);
}
#define 定义宏
//int get_max(int x,int y)
//{
// int z = 0;
// z = (x > y ? x : y);
// return z;
//}
//宏
//好像函数一样
**#define MAX(x,y) ((x) > (y) ? (x) : (y))**
int main()
{
int a = 10;
int b = 20;
//int m = MAX(a,b);//int m = (a>b?a:b)
printf("较大值:%d",m);
}
指针
内存
内存单元单位是字节
内存单元是有编号的,编号就是内存单元的地址。
32位 有2^32个字节
int main()
{
int a = 10;//4byte
printf("%p",&a);//**地址为了我们方便找到空间
//地址就是一个数字 就是个编号**
return 0;
}
int a = 10;
int *pa = &a;//pa用来存放地址,所以pa叫做指针变量
//拿的都是起始地址
内存单元的编号就是地址,地址也叫做指针。
char ch = 'w';
char *pc = &ch;
*pc;//*解引用操作符,它的意思就是通过pc中存放的地址,找到pc指向的内容。
//相当于ch
地址、内存中的数据(16进制) 以文本形式解析内存中的数据
指针变量的大小
int a =10;
char ch = 'w';
int* pa = &a;
char* pc = &ch;
printf("%d\n",sizeof(pa));
printf("%d\n",sizeof(pc));
因为是32位,32个二进制位序列是4个字节
64位是8个字节
所以指针大小取决于平台。
结构体
描述复杂类型
学生 名字+年龄+性别+学号
//结构体类型(图纸)
struct stu
{
char name[20];
int age;
char sex[5];
char id[15];
}
void Print(struct stu* ps)
{
printf("%s %d %s %s",(*ps).name,(*ps).age,(*ps).sex,(*ps).id);
printf("%s %d %s %s",ps->name,ps->age,ps->sex,ps->id);
//结构体指针->结构体成员
}
int main()
{
//结构体变量-实例化了(房子)
struct stu s1 = {"name",18,"男","2201"};
printf("%s",s1.name);
//结构体变量.结构体成员
Print(&s1);
//输入结构体数据
scanf("%s %d %s %s",s1.name,&(s1.age),s1.sex,s1.id);//name本身就是数组 数组名就是地址
}
typedef struct stu
{
char name[20];
int age;
char sex[5];
char id[15];
}stu;