本次博客内容来源于鹏哥比特就业课,BV号1q54y1q79w
1、C语言的发展历史:
机器语言——>汇编语言——>B语言——>C语言
2、C语言的国际标准
C89、C90、C99、C11
美国国家标准局 ANSI C
3、创建C语言代码的过程
Step1:创建新项目
Step2:空项目
Step3:配置新项目
Step4:解决方案资源管理器——>源文件——>添加——>新建项
Step5:C++文件,名称后缀改为.c
Step6:开始编程!【运行快捷键:Fn+F5】
一个工程中可以有多个.c文件,但是每个.c文件只能有一个主函数int main()
4、数据类型
4.1 各种数据类型的大小
注:C语言标准 sizeof(long)≥sizeof(int)!
5、常量和变量
常量:不变的量
变量:顾名思义,值会改变的量
5.1 变量的定义
int age = 150;
float weight = 45.5f; //注意要有f,因为编译器默认小数类型为double,不加f会导致精度丢失而报错
char ch = 'w';
5.2 全局变量和局部变量
全局变量:在{}外部定义的变量
局部变量:在{}内部定义的变量
由此可见当局部变量和全局变量相冲突时,全局变量会被屏蔽,此时起作用的是局部变量。
5.3 变量使用举例
#include <stdio.h>
int main()
{
int num1 = 0;
int num2 = 0;
int sum = 0;
printf("输入两个操作数:>");
scanf("%d %d", &num1, &num2);
sum = num1 + num2;
printf("sum = %d\n", sum);
return 0;
}
但这样在visual studio上会报错
原因:scanf是标准C语言提供的函数,而scanf_s是VS编译器提供的函数。VS认为scanf这个函数不安全
解决方法:源文件最上边加
#define _CRT_SECURE_NO_WARNINGS 1
不建议使用scanf_s,因为只有VS编译器可以识别此函数,别的编译器 (如gcc)并无法识别此函数,这样会降低程序的可移植性。
Tips:为了使得每次打开VS后源程序第一行自动添加#define _CRT_SECURE_NO_WARNINGS 1这一行,我们可以用notepad++打开 C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\VC\VCProjectItems\newc++file.cpp文件
选择“是”
然后用ctrl+S保存。
从此每新建.c文件时第一行都会自动添加 #define _CRT_SECURE_NO_WARNINGS 1
5.4 变量的生命周期和作用域
5.5 常量
![4115c41f19284b14a3448af9169e7290.png](https://img-blog.csdnimg.cn/4115c41f19284b14a3448af9169e7290.png)
由此可见常变量是不可以修改的。
由此可见由const修饰的常变量的本质还是变量。const 修饰的常变量在C语言中只是在语法层面限制了变量不能直接被改变,但是本质上还是一个变量的,所以叫常变量。
(3) #define 定义的标识符常量
和const对比,可以发现#define定义的是常量
(4)枚举常量
#include<stdio.h>
enum SEX
{
MALE,
FEMALE,
SECERT
};
int main()
{
enum SEX s1 = MALE;
printf("%d\n", MALE);
printf("%d\n", FEMALE);
printf("%d\n", SECERT);
return 0;
}
注:枚举常量的默认是从0开始,依次向下递增1的
变量是可以改的,但是常量本身是不可以被更改的。
6、字符串 转义字符 注释
6.1 字符串
#include<stdio.h>
int main()
{
char arr1[] = "abc";
char arr2[] = { 'a','b','c' };
printf("%s\n", arr1);
printf("%s\n", arr2);
return 0;
}
我们打印一下arr1和arr2的长度
运行发现,arr1正常输出,但arr2不是正常输出。
下面进行调试。
按Fn+F10,进入调试界面。
调试——>监视——>监视1
按下Fn+F10,一步一步进行调试,观察arr1、arr2.
我们发现arr2比arr1少了一个元素,即“\0”(字符串结束标志),在数值上是0。
因此可以解释arr2错误输出的问题。因为arr2并没有字符结束标志,因此编译器会不停地打印字符和计算长度,由此arr2就输出了“abc烫烫烫烫...”,并且长度是42,可以推测在第43个位置上碰到了\0。
我们在arr2后面加"\0”,或者0,即可正常输出。
6.2 转义字符
转义字符(Escape character):C中定义了一些字母前加"\"来表示常见的那些不能显示的ASCII字符,如\0,\t,\n等,就称为转义字符,因为后面的字符,都不是它本来的ASCII字符意思了。
常见的转义字符如下:
看下面一段代码,能否打印出我们想要的路径?
#include <stdio.h>
int main()
{
printf("c:\code\test.c\n");
return 0;
}
实际运行结果:
这是因为这里的\c和\t被编译器识别为了转义字符。
为了输出正确的路径,我们需要在\c和\t前面再加一个\,以消去转义。
转义字符的长度是1,下面看一道常见的大厂笔试题:
//程序输出什么?
#include <stdio.h>
int main()
{
printf("%d\n", strlen("abcdef"));
printf("%d\n", strlen("c:\test\628\test.c"));
return 0;
}
运行结果:
解释为什么第二个长度是14:
1 | c |
2 | : |
3 | \t |
4 | e |
5 | s |
6 | t |
7 | \62 |
8 | 8 |
9 | \t |
10 | e |
11 | s |
12 | t |
13 | . |
14 | c |
下面看另一个问题:
解释:
\t是转义字符,为水平制表符。
\54是转义字符,54转化为10进制为44,对应ascii表为 ,(逗号)
\ddd |
ddd表示1~3个八进制的数字,将这个八进制数字转化为10进制后,去对应ascii码表寻找其所对应的字符
|
\xdd | xdd表示2个十六进制的数字,将这个十六进制数字转化为10进制后,去对应ascii码表寻找其所对应的字符 |
如果我只想输出一个“,应该怎么编写代码?
看下面的代码是否可行?
//程序输出什么?
#include <stdio.h>
int main()
{
printf("%s\n", """);
return 0;
}
我们看一下运行情况
原因:连续输入三个”,编译器会自动将前两个进行配对,因此第三个“编译器认为是多余的。
解决方法:在”""中间的”号之前加\,消去转义。
6.3 注释
7、循环语句
//while循环的实例
#include <stdio.h>
int main()
{
printf("加入比特\n");
int line = 0;
while(line<=20000)
{
line++;
printf("我要继续努力敲代码\n");
}
if(line>20000)
printf("好offer\n");
return 0;
}
8、函数
#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;
}
9、数组
9.1 数组的定义
int arr[10] = {1,2,3,4,5,6,7,8,9,10};//定义一个整形数组,最多放10个元素
9.2 数组的下标
int arr[10] = {0};
//如果数组10个元素,下标的范围是0-9
![4cf605f52e0749a68d558e0418fbf566.png](https://img-blog.csdnimg.cn/4cf605f52e0749a68d558e0418fbf566.png)
9.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 ", arr[i]);
}
printf("\n");
return 0;
}
10、操作符
10.1 算术操作符
+ | 加 |
- | 减 |
* | 乘 |
/ | 除 |
% | 取余 |
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int a = 9;
float b = 9.0;
printf("%d\n", a / 2);
printf("%f\n", b / 2);
printf("%d\n", a % 2);
return 0;
}
10.2 移位操作符
>> | 右移 |
<< | 左移 |
10.3 位操作符
& | 按位与 |
^ | 按位异或 |
| | 按位或 |
10.4 赋值操作符
= | 赋值 |
a += 1; | a = a + 1; |
a -= 1; | a = a - 1; |
a *= 2; | a = a * 2; |
a /= 2; | a = a / 2 ; |
a &=b; | a = a & b; |
a ^= b; | a = a ^b; |
a |= b; | a = a | b; |
a >>= 1; | a = a >> 1; |
a <<= 1; | a = a << 1; |
10.5 单目操作符
(1) ! 逻辑反操作
0 表示假,非0就是真
#include<stdio.h>
int main()
{
int a = 0;
printf("%d\n", !a);//1
return 0;
}
(2) sizeof 操作数的类型长度(以字节为单位)
sizeof是一个操作符,不是函数,用来计算类型或者变量的大小。
#include<stdio.h>
int main()
{
//sizeof是一个操作符
//不是函数
//计算类型或者变量的大小的
int a = 10;
printf("%d\n", sizeof(int));
printf("%d\n", sizeof(a));
return 0;
}
printf("%d\n", sizeof int );//代码报错!
printf("%d\n", sizeof a );//代码不报错
用途举例:计算数组元素个数
#include<stdio.h>
int main()
{
//10*4 = 40
int arr[10] = { 0 };
printf("%d\n", sizeof(arr));//计算的是数组的总大小,单位是字节
printf("%d\n", sizeof(arr[0]));//4
int sz = sizeof(arr) / sizeof(arr[0]);
printf("%d\n", sz);
return 0;
}
(3) ~ 按位取反
#include<stdio.h>
int main()
{
int a = 0;
printf("%d\n", ~a);
//~ 按位取反
return 0;
}
查看结果:
原因:整数在计算机中以补码的形式存储。int类型是4个字节,int a = 0;表明a=00000000_00000000_00000000_00000000。而printf输出的是原码。对a按位取反得到11111111_11111111_11111111_11111111,其原码为10000000_00000000_00000000_00000001,表示-1,因此输出为-1.
(4) (类型) 强制类型转换符
#include<stdio.h>
int main()
{
//强制类型转换
int a = (int)3.14;//正确
int a = 3.14;//报错
printf("%d\n", a);
return 0;
}
(5) -- ++
#include<stdio.h>
int main()
{
int a = 10;
int b = a++;//后置++,先使用,再++
printf("%d\n", b);//10
printf("%d\n", a);//11
int c = 10;
int d = ++c;//前置++ - 先++,后使用
printf("%d\n", d);//11
printf("%d\n", c);//11
return 0;
}
(6) 关系运算符
> | 大于 |
>= | 大于等于 |
< | 小于 |
<= | 小于等于 |
!= | 判断“不等于” |
== | 判断“等于” |
(7) 逻辑操作符
&& | 逻辑与 |
|| | 逻辑或 |
0为假,非0为真
(8) 条件操作符
[] | 数组下标 |
() | 函数调用 |
. | 结构成员 |
-> | 结构成员 |
11、常见关键字
auto break case char const continue default do double else enum
extern float for goto if int long register return short signed
sizeof static struct switch typedef union unsigned void volatile while
注:define、include不是关键字,是预处理指令。
C语言提供的关键字
1. C语言提供的,不能自己创建关键字
2. 变量名不能是关键字
auto 自动的,每个局部变量都是auto,可省略
extern 用于声明外部变量
register 寄存器关键字。计算机读取寄存器的速度快,但寄存器空间有限,不建议大量使用。
signed 有符号数
unsigned 无符号数
union 联合体
void 空
struct 结构体
static 静态的
11.1 typedef 类型定义
#include<stdio.h>
typedef unsigned int u_int;
int main()
{
unsigned int a = 1;
u_int b = 1;
return 0;
}
11.2 static 静态的
![05a06a4fceb14654991da82c58aaca9b.png](https://img-blog.csdnimg.cn/05a06a4fceb14654991da82c58aaca9b.png)
//代码1
#include<stdio.h>
void test()
{
int i = 0;
i++;
printf("%d ", i);
}
int main()
{
int i = 0;
for (i = 0; i < 10; i++)
{
test();
}
return 0;
}
//代码2
#include<stdio.h>
void test()
{
static int i = 0;//static修饰局部变量
i++;
printf("%d ", i);
}
int main()
{
int i = 0;
for (i = 0; i < 10; i++)
{
test();
}
return 0;
}
(2)static修饰全局变量:一个全局变量被static修饰,使得这个全局变量只能在本源文件内使用,不能在其他源文件内使用。
全局变量,在其他源文件内部可以被使用,是因为全局变量具有外部链接属性,但是被static修饰之后,就变成了内部链接属性,其他源文件就不能链接到这个静态的全局变量了!
//代码2
//test1.c
static int year = 2022;
//test2.c
#include<stdio.h>
int main()
{
extern int year;
printf("%d\n", year);
return 0;
}
代码2在编译的时候会出现连接性错误。
(3) static修饰函数:一个函数被static修饰,使得这个函数只能在本源文件内使用,不能在其他源文件内使用。
//代码1
//add.c
int Add(int x, int y) {
return c+y; }
//test.c
int main()
{
printf("%d\n", Add(2, 3));
return 0;
}
//代码2
//add.c
static int Add(int x, int y) {
return c+y; }
//test.c
int main()
{
printf("%d\n", Add(2, 3));
return 0;
}
代码1正常,代码2出现链接错误。
本质上: static是将函数的外部链接属性变成了内部链接属性!(和static修饰全局变量一样!)
12、define定义常量和宏
//define定义标识符常量
#define MAX 1000
//define定义宏
#define ADD(x, y) ((x)+(y))
#include <stdio.h>
int main()
{
int sum = ADD(2, 3);
printf("sum = %d\n", sum);
sum = 10*ADD(2, 3);
printf("sum = %d\n", sum);
return 0;
}
13、指针
13.1 内存
![af6e934b0223406887d9330c03443c32.png](https://img-blog.csdnimg.cn/af6e934b0223406887d9330c03443c32.png)
//int main()
//{
// int a = 10;//a在内存中要分配空间的 - 4个字节
// printf("%p\n", &a);//%p 专门用来打印地址的
//
// int * pa = &a;//pa是用来存放地址的,在C语言中pa叫是指针变量
//
// //* 说明 pa是指针变量
// //int 说明pa执行的对象是int类型的
//
// char ch = 'w';
// char * pc = &ch;
//
// return 0;
//}
13.2 指针变量的大小
因为指针变量存放的内容是地址,所以在32位机上指针变量的大小是32位,也就是4个字节;同理,在64位机上是8个字节。
int main()
{
printf("%d\n", sizeof(char *));
printf("%d\n", sizeof(short *));
printf("%d\n", sizeof(int *));
printf("%d\n", sizeof(double *));
return 0;
}
14、结构体
结构体可以让C语言创建新的类型出来
例如创建一个学生
struct Stu
{
char name[20];//名字
int age; //年龄
char sex[5]; //性别
char id[15]; //学号
};
结构体初始化
//初始化结构体信息
struct Stu s = {"张三", 20, "男", "20180101"};
//.为结构成员访问操作符
printf("name = %s age = %d sex = %s id = %s\n", s.name, s.age, s.sex, s.id);
//->操作符
struct Stu *ps = &s;
printf("name = %s age = %d sex = %s id = %s\n", ps->name, ps->age, ps->sex, ps- >id);
. | 结构体变量.结构体成员 |
-> | 指针变量->结构体成员 |
int main()
{
struct Stu s = {"张三", 20, 85.5};//结构体的创建和初始化
printf("1: %s %d %lf\n", s.name, s.age, s.score);//结构体变量.成员变量
struct Stu * ps = &s;
printf("2: %s %d %lf\n", (*ps).name, (*ps).age, (*ps).score);//可以这么写,但是略微复杂
printf("3: %s %d %lf\n", ps->name, ps->age, ps->score);
return 0;
}