推荐两个实用的网站:Gitee - 基于 Git 的代码托管和研发协作平台https://gitee.com/
【gitee(码云)的注册和代码提交【手把手】】 https://www.bilibili.com/video/BV1hf4y1W7yT?share_source=copy_web&vd_source=cca31443eb7fa266979bf6d65a232738
Visual Studio 2022 社区版 - 下载最新的免费版本 (microsoft.com)https://visualstudio.microsoft.com/zh-hans/vs/community/ VS是我们常用的集成开发环境,大家可以下载免费的社区版作为学习使用
目录:
2.0.2 如何得到 #define _CRT_SECURE_NO_WARNINGS_ 1(利用everything)
前言:
本篇博客主要介绍C语言的所有主要知识点,但是并不包含所有的知识点,只是让我们对C语言的整体知识构架有所了解。因此,大家如果在阅读过程中有问题的话可以暂时放一放,因为我在后面的分享中会搭建出C语言的完整框架。
1. 何为C语言
人和人之间交流所使用的语言有汉语、英语、法语等,动物和动物之间交流也会有它们自己的语言。C语言也一样,只不过它是人与计算机交流的语言,通过敲代码,我们来优化生活中重复性的工作,实现我们所预期的实际效果。
1.1 第一个C语言程序
#include<stdio.h>
int main()
{
printf("hello binbin\n");
return 0;
}
int main()
{
return 0;
}
#“ main()”,这是main函数(不用纠结什么是函数,后面会分享到)
#printf()是C语言中的内置函数,即“print function”,想要使用这个函数,就必须加上头文件stdio.h, .h是头文件的后缀
- main函数是程序的入口
- 在一个C语言所创建的工程当中,有且只能有一个main函数,否则计算机不知道到底要进哪一个入口
- 由于代码在执行的过程当中是逐行扫描的,即先扫描第一行,然后是第二行,依次类推
2. C语言概述
2.0 写代码
2.0.1创建工程
注意:项目名称尽量不要使用中文,中文的兼容性不是很好。
至此,我们就完成了第一次工程的创建。这个时候有的小伙伴可能会问了,为啥我创建好了没有“#define _CRT_SECURE_NO_WARNINGS_ 1”呢,首先我们要知道:scanf、strcpy、strcat 这些函数,VS都会提示不安全,为了能够正常使用,我们在.c文件的第一行,加上:#define _CRT_SECURE_NO_WARNINGS 1就可以了,,下面我们就谈一谈该怎么操作。
2.0.2 如何得到 #define _CRT_SECURE_NO_WARNINGS_ 1(利用everything)
everything 的下载链接如下:
下载 - everythinghttps://www.voidtools.com/zh-cn/downloads/
为了一劳永逸的解决以后的问题,我们可以在newc++file.cpp(利用everything搜索电脑文件) 这个文件中加入:#define _CRT_SECURE_NO_WARNINGS 1,以后新建的文件中都会自动加上:#define _CRT_SECURE_NO_WARNINGS 1
关闭VS,将这个文件复制到桌面,打开再修改,如何再拖回到原来的文件夹,这样就可以替换原文件了。
2.1 数据类型
char //字符类型 1字节
short //短整型 2字节
int //整型 4字节
long //长整型 4或8字节
long long //更长整型 8字节
float //单精度浮点数
double //双精度浮点数
由于计算的语言主要是为了解决人们遇到的问题,但是现实生活中的数据都不是单一类型的,因此为了方便使用计算机解决问题,产生了这么多种类的数据类型。那么在写代码的过程当中,我们怎么使用这些数据类型呢?我们接着往下看。
2.2 变量、常量
2.2.1 创建变量
//%d - 打印10进制的整数
//%c - 打印字符
//sizeof 是一个操作符,是计算变量的大小的
#include<stdio.h>
int main()
{
int m = 0;//好习惯:在创建变量的同时给一个初始值
printf("%d\n", m);
// //printf("%d\n", sizeof(char));
// char ch = 'w';
// printf("%c\n", ch);
// float weight = 75.5f; 一般表示float类型的时候后面要加f,否则会默认存放的double类型
// double pai = 3.14;
// int age = 18;
// double salary = 20000.0;
return 0;
}
我们可以看到,利用整型int,我们创建了一个变量m,在创建的过程当中,m向内存申请了4个字节的空间,这个空间的名字叫做m。数据类型的作用就是创建变量。
2.2.2 变量的命名
- 变量名只能由字母(大小写均可)、下划线、数字构成
- 不可以用数字开头
- 不可以使用关键字
- 变量名区分大小写
- 长度不可以超过64个字符
2.2.3 变量的分类
局部变量&全局变量
int a = 10;//全局变量
int main()
{
int b = 20;//局部变量
return 0;
}
int c = 100;//全局变量
//局部变量和全局变量名字冲突的时候,局部优先
//建议大家尽量不要冲突
实际上在另一个.c文件当中创建一个全局变量时,如果想在包含main函数的.c文件使用,就应该先作出声明,具体操作如下:
在这里也可以不用extern,直接 int m。extern是用来声明外部符号(非本.c文件内的符号),int表示声明内容的数据类型,m指声明的变量名
2.2.4 常量分类
1. 字面常量:3;100;3.14; 'a'; "abcdef";
2.const 修饰的常变量
3.#define 定义的标识符常量
#define M 100
int main()
{
int arr[M] = { 0 };
printf("%d\n", M);
//M = 200;//err
return 0;
}
//M可以是O也可以是A,它只是一个符号,我们把这个符号记作100
4.枚举常量
//enum是枚举类型,color是enum定义的变量
enum Color
{
//RED,GREEN,BLUE是枚举类型Color的可能取值,同时也是常量,所以叫枚举常量
RED,//0
GREEN,//1
BLUE//2
};
int main()
{
enum Color c = BLUE;//如果把C以整型打印出来,输出结果是2,因为BLUE对应的常量是2
int a = 0;
printf("%d\n", RED);
printf("%d\n", GREEN);
printf("%d\n", BLUE);
//RED = 100;//err
return 0;
}
//%d - 十进制的整型
//%c - 字符
//%s - 字符串
//%f - 打印float类型的浮点数
//%lf - 打印double类型的浮点数
2.2.5 变量的作用域和生命周期
作用域:
作用域(scope)是程序设计的概念,通常来说,一段程序代码中所用到的名字(变量)并不总是有效的,而限定这个名字(变量)的可用性的代码范围就是这个名字(变量)的作用域。
- 局部变量的作用域是变量所在的局部范围
- 全局变量的作用域是整个工程
生命周期:
变量的生命周期指的是变量的创建到变量的销毁之间的一个时间段。
- 局部变量的生命周期是:进入作用域生命周期开始,出作用域生命周期结束。
- 全局变量的生命周期是:整个程序的生命周期。
int main()
{
{
int a = 10;
printf("1: %d\n", a);
}//“{}”,限制了变量a的作用范围,出了{},变量a就被销毁了,存放数据的空间也还给了内存
printf("2: %d\n", a);
return 0;
}
2.3 常见关键字
类型关键字:
auto const char int enum short float long double signed unsigned static void union struct sizeof typedef viod
循环关键字:
break continue do while for
分支关键字:
if else switch case break default goto
其他关键字:
函数:return 声明外部符号:extern 寄存器:register
计算所占内存的大小:sizeof
2.3.1 typedef
typedef——类型重命名
//将unsigned int 重命名为uint_32, 所以uint_32也是一个类型名
typedef unsigned int uint_32;
int main()
{
//观察num1和num2,这两个变量的类型是一样的
unsigned int num1 = 0;
uint_32 num2 = 0;
return 0;
}
2.3.2 static
1.修饰局部变量——静态局部变量
我们可以通过以下两个代码来理解:
//代码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;
}
//输出结果是十个1
//代码2
#include <stdio.h>
void test()
{
//static修饰局部变量
static int i = 0;
i++;
printf("%d ", i);
}
int main()
{int i = 0;
for(i=0; i<10; i++)
{
test();
}
return 0;
}
//输出结果是1到10
static修饰局部变量改变了变量的生命周期,让静态局部变量出了作用域依然存在,到程序结束,生命周期才结束。
2.修饰全局变量——静态全局变量
//代码1
//add.c
int g_val = 2018;
//test.c
int main()
{
printf("%d\n", g_val);
return 0;
}
//代码2
//add.c
static int g_val = 2018;
//test.c
int main()
{
printf("%d\n", g_val);
return 0;
}
一个全局变量被static修饰,使得这个全局变量只能在本源文件内使用,不能在其他源文件内使用。
3.修饰函数——静态函数
同静态全局变量
2.4 数组
2.4.1数组的定义:一组相同类型元素的集合
int arr[10] = {1,2,3,4,5,6,7,8,9,10};//定义一个整形数组,最多放10个元素
2.4.2 数组的创建与初始化
int arr1[10] = {1,2,3,4,5,6,7,8,9,10};
int arr2[10] = { 1,2,3,4,5};//不完全初始化,剩余的默认初始化为0
char ch[5] = { 'a', 'b', 'c' };//不完全初始化,剩余默认初始化为\0
遍历数组中的元素:
#include <stdio.h>
int main()
{
int i = 0;
int arr[10] = {1,2,3,4,5,6,7,8,9,10};//10指的是元素个数
for(i=0; i<10; i++)
{
printf("%d ", arr[i]);//i表示数组中元素的下标
}
printf("\n");
return 0;
}
2.5 字符串、转义字符、注释
2.5.1 字符串
"i love bingbing"
这种由双引号(Double Quote)引起来的一串字符称为字符串字面值(String Literal),或者简称字符串。
注:字符串的结束标志是一个\0 的转义字符,也就是说字符串末尾是自带\0的(在内存里)。在计算字符串长度的时候 \0 是结束标志,不算作字符串内容。
C语言提供了一个库函数strlen(),可以计算字符串的长度,统计的是\0之前字符的个数 ,如果没有\0,那么会一直往后面找,直到找到\0。在调用这个库函数的时候需要加头文件:#include <string.h>。
strlen——string length。
int main()
{
char ch1[] = { 'a', 'b', 'c'};
char ch2[] = "abc";
int len1 = strlen(ch1);
int len2 = strlen(ch2);
printf("%d\n", len1);//运行结果是 随机数
printf("%d\n", len2);//运行结果是 3
return 0;
}
2.5.2 转义字符
转义字符 - Bing imageshttps://cn.bing.com/images/search?q=%E8%BD%AC%E4%B9%89%E5%AD%97%E7%AC%A6&form=HDRSC2&first=1&tsc=ImageHoverTitle 转义,实际上是转变含义。在c语言中,“\n”表示转至下一行输出,如果加上一个\,即“\\n”,那么\n就不再是之前的意思了,现在它只会输出\n,而不是转入到下一行输出。
#include<stdio.h>
int main()
{
printf("%c\n", 'a');
printf("%c\n", 'w');
printf("%s\n", "\"");
printf("\a");
printf("abcdef\bc");
printf("%c\n", '\073');//073是8进制数字
printf("%c\n", '\x46');//16进制数,一个16进制数用4位二进制数表达
printf("c:\\code\\test.c");
return 0;
}
字符串和转义字符都是字符,那么输出的时候都必须用单引号引用。
ASCII表
2.5.3 注释
1. 代码中有不需要的代码可以直接删除,也可以注释掉
2. 代码中有些代码比较难懂,可以加一下注释文字
注释有两种风格:
C语言风格的注释 :/*xxxxxx*/ 缺陷:不能嵌套注释
C++风格的注释: //xxxxxxxx 可以注释一行也可以注释多行
2.6 函数
函数的特点就是简化代码,代码复用。
注:scanf函数读取失败的时候会返回EOF,如果读取正常的话,返回的是读取到的数据的个数。
#include<stdio.h>
int g_a;//声明(.c文件内部的声明不用加extern,extern也可以用于声明外部函数)
//写一个test函数,void表示这个函数内无参数
void test()
{
printf("test:%d\n", g_a);
}
int g_a = 2022;//把它写在最前面就不用在前面做声明了
int main()
{
printf("%d\n", g_a);
test();//调用函数
return 0;
}
调试结果如下:
再举一个有参数的例子:
#include <stdio.h>
//定义加法函数Add()
int Add(int x, int y)
{
int z = x+y;
return z;//函数的返回值是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;
}
2.7 选择语句
- if...else...
- switch...case
int main()
{
int input = 0;
printf("你要好好学习吗(1/0)?");
scanf("%d", &input);//
if (input == 1)
printf("好技术\n");
else if (input == 0)
printf("回家卖红薯\n");
else
printf("输入错误\n");
return 0;
}
2.8 循环语句
- while语句
- for语句
- do ... while语句
int main()
{
int line = 0;
while (line<=20000)//若括号内为真,则继续执行大括号内部的代码
{
printf("敲代码: %d\n", line);
line++;
}
return 0;
}
2.9 操作符
- 算术操作符 + - * / %
- 移位操作符 >> <<
- 位操作符 & | ^
- 赋值操作符 = += -= *= /= &= ^= |= >>= <<=
- 单目操作符 ! - + & sizeof ~ -- ++ * typedef
- 关系操作符 > >= <= < == !=
- 逻辑操作符 || &&
- 条件操作符 exp1?exp2:exp3
除号的两端如果都是整数,执行的是整数除法 除号的两端至少有一个数是浮点数,才能执行浮点数的除法 / 除号 % 取模(取余),%操作的两个操作数必须都是整数a = a + 5; a += 5;这两个表达的意思是一样的sizeof是操作符,是计算变量所占内存空间的大小,单位是字节
strlen是库函数,是计算字符串的长度的,统计的是字符串中\0之前出现的字符个数
&& 两边同时为真,才为真
|| 两边同时为假,才为假
m = (a > b ? a : b) //先判断条件a>b是否成立,若成立,则返回a,否则,返回b
%zd 专门用来打印sizeof的返回值
int main()
{
int flag = 5;//在C语言中,0表示假,非0表示真
//如果flag为真,就打印hehe
if (flag)
{
printf("hehe\n");
}
if (!flag)
{
printf("haha\n");
}
return 0;
}
int main()
{
int a = 100;
int b = (a++);//后置++,先使用a,后++ //int b=a,a=a+1;
//int b = ++a;//前置++,先++,后使用
//a=a+1,b=a;
//int b = a--;
//int b = a,a=a-1;
//int b = --a;
//a=a-1,b=a;
//printf("a=%d b=%d\n", a, b);
return 0;
}
int main()
{
//(类型) - 强制类型转换
int a = (int)3.14;//这里只取整数部分
printf("%d\n", a);
return 0;
}
2.10 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;
}
2.11 结构体
2.11.1 结构体的作用:
描述复杂类型。 比如描述学生,假设学生包含:名字+年龄+性别+学号,这四项信息, 在C语言中只能使用结构体来描述。
2.11.2 结构体的定义
//定义一个结构体 strcut Stu,这个结构体包括四项信息。
struct Stu
{
char name[20];
int age;
char sex[5];
char id[15];
};
2.11.3 结构体初始化
//打印结构体信息
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);
2.12 指针
2.12.1 内存
想学好指针,我们要先弄明白什么是内存。我们要知道,程序运行的时候,会载入内存,程序中如果有数据需要存储,也会申请内存空间。内存是电脑上重要的存贮器,为了有效的使用内存,就把内存划分成一个个小的内存单元,每个内存单元的大小是1个字节。
为了能够有效的访问到内存的每个单元,就给内存单元进行了编号,这些编号(即二进制序列)被称为该内存单元的地址。在C语言中,地址,就是指针(口头说的指针大多数是指针变量的意思)。
那么问题来了,计算机有多少个内存单元呢?以64位机为例,当机器内的64根地址线通电的时候,由电信号产生64个二进制位,这六十四个二进制位所能够表示的内存单元的编号的数量(也就是二进制序列)是个,也就是说,这
个二进制序列就能够表示
个地址,也就是
个内存单元,也就是
个字节。
int a=0;
图示表示变量a为存储整型数据,向内存申请了4个字节的空间,这四个字节的空间是连续的、随机分配的。每个内存单元都有地址,所以变量也是有地址的。 取出变量地址如下:
从监视器我们可以看到,左边部分对应的是内存的地址,对第一行来说,0x012FFA90,就是变量存放数据的地址, 01 00 00 00 每两位表示的则是两个16进制数,也就是8个二进制数,就是1个字节。地址表示的时候会把二进制数转换成16进制数。二进制转换为十六进制的时候,通常以四个二进制数为一组转化成一个十六进制数。
底层核心:
取出变量的地址(&)
怎么把地址存起来(定义指针变量)
存起来之后如何找到它 (解引用操作)
#include<stdio.h>
int main()
{
int a = 1;//向内存申请4个字节
int * pa = &a;// * 说明pa是指针变量
//int 说明pa存取的是整型变量的地址 int * 一起定义了一个指向整型数据的指针变量
*pa = 20;// 如何找到存放在pa里的a的地址呢?
//解引用操作(在pa前面加一个*) - 作用就是通过pa中的地址,找到a, *pa就是a
//a = 20;
printf("%d\n", a); //输出值是20
/*printf("%p\n", &a);
printf("%p\n", pa);*/ /*打印出来的地址是一样的*/
//pa是一个变量,这个变量是用来存放地址的
//而地址又叫指针
//所以在C语言中把pa叫指针变量(指针变量是存放指针的变量)
//
/*&a;*///& 取地址操作符
printf("%p\n", &a);
/*&a 取出的是a所占内存的4个字节中第一个字节的地址
*/
printf("%d\n", sizeof(a));
return 0;
}
//a和*pa &a和pa 表示的是一个东西
//int main()
//{
// char ch = 'w';
// char* pc = &ch;
// //通过pc把ch的值改'b'
// *pc = 'b';
// printf("%c\n", *pc);//b
//
// ch = 'q';
// printf("%c\n", *pc);//q
//
// return 0;
//}
2.12.2指针变量的大小
指针变量向内存申请的地址的大小与存放的地址的原始数据类型无关,只和机器的位数有关,如果是32位机,那么指针变量存放的就是32位的地址(地址就是二进制位数,32位机器的地址是32个二进制数编码的的),大小是4个字节;如果是64位机,那么指针变量存放的就是64位的地址,大小是8个字节。
当然,要想学好编程并不能只能学习C语言,还有这些:计算机语言、算法和数据结构、操作系统、计算机网络、项目实战。这些内容我都会在往后的博客中更新完,持续一年半左右,期待大家的反馈和关注。