目录
前言
本文主要是有关C语言的基础知识,详细请看目录,可以让初学者看懂简单代码。
1.如何学
1.下载一个编译器,我使用的是VS2017。链接:下载地址(资源来源于公众号 伙伴神)
2.再找一个合适的学习视频;不建议使用书籍。3.要有自己的笔记使用有道云也可以。
4.每学完一个课程,一定要总结,可以写在博客中。
5.在学习代码的时候不要刻意的去记忆代码,跟着老师的思路写出代码才是最好的。
2. 什么是C语言
C语言是一门通用计算机编程语言,广泛应用于底层开发。C语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。尽管C语言提供了许多低级处理的功能,但仍然保持着良好跨平台的特性,以一个标准规格写出的
C语言程序可在许多电脑平台上进行编译,甚至包含一些嵌入式处理器(单片机或称MCU)以及超级电脑等作业平台。
二十世纪八十年代,为了避免各开发厂商用的C语言语法产生差异,由美国国家标准局为C语言制定了一套完整的美国国家标准语法,称为ANSIC,作为C语言最初的标准。 目前2011年12月8
日,国际标准化组织(ISO)和国际电工委员会(IEC)发布的C11标准是C语言的第三个官方标
准,也是C语言的最新标准,该标准更好的支持了汉字函数名和汉字标识符,一定程度上实现了汉
字编程。
C语言是一门面向过程的计算机编程语言,与C++,Java等面向对象的编程语言有所不同。
其编译器主要有Clang、GCC、WIN-TC、SUBLIME、MSVC、Turbo C等。
3.第一个C语言程序
废话不多说,咱们先来一个程序认识一下,首先使用软件创建文件分为二步
第一步 创建项目
流程 打开软件——文件——新建——项目——VisualC++——空项目——命名
建议大家将代码存储在一个专门的文件中文件名字可以是code,而且命名的方式要有一定的规律性,便于今后代码的管理。
第二步
流程 右键源文件——添加——新建项目——C++文件(.cpp)——修改文件的后缀为 (名字).C
注意
在这里一定要修改后缀,毕竟cpp表示的是C++,应该改为.C才是C语言的源文件,命名的方式如同项目命名一样不能随意命名,要有顺序,方便查看和管理 。XX,C是源文件,XX.h是头文件。
可以输入下面的程序
#include <stdio.h>
int main()
{
printf("hello world");
return 0;
}
再点击本地Windows调试器
运行结果就出来了
解释
#include <stdio.h>
//standard input output 包含头文件stdio.h 标准的输入和输出 因为代码内有printf()函数,如果没有这个头文件,程序将无法运行。
int main()// main()主函数 大家只要知道它是主函数就可以了,每一个项目里面只能有一个,唯一的。程序的运行入口,程序从main函数的第一行开始运行。
{
printf("hello world");// printf()函数 打印,将()中的内容打印到屏幕上。
return 0;}
// 函数的程序必须在{}中的范围中
4.数据类型
char //字符数据类型
short //短整型
int //整形
long //长整型
long long //更长的整形
float //单精度浮点数
double //双精度浮点数
下方有表格看的更加直观的。
4.1数据类型大小
我们使用sizeof()操作符来计算数据类型的大小,算出的单位是字节,代码如下
int main()
{
printf("%d\n", sizeof(char));
printf("%d\n", sizeof(short));
printf("%d\n", sizeof(int));
printf("%d\n", sizeof(long));
printf("%d\n", sizeof(long long));
printf("%d\n", sizeof(float));
printf("%d\n", sizeof(double));
return 0;
}
运行结果如下
这里我们再强化一下计算机中内存的大小
bit - 比特位 -计算机最小单位
8bit(比特)=1byte(字节) 现在最小的存储单位就是字节
1KB=1024byte
1MB=1024KB
1GB=1024MB
1TN=1024GB
1PB=1024TB
这里采用的2进制来计算的,2十次方等于1024(类似于十进制满十进1算法)
4.2数据类型的使用
在小节中只是详细描述如何利用数据中类型初始化变量和如何在屏幕上打印不同的数据类型的变量,关于如何输入数据给变量赋值在变量和常量中。
4.2.1初始化
数据类型 | 说明 | 大小(byte) | 输入输出格式 |
char | 字符数据类型 | 1 | %c |
short | 短整型 | 2 | %d |
int | 整形 | 4 | %d |
long | 长整型 | 4 | %d |
long long | 更长的整形 | 8 | %d |
float | 单精度浮点数 | 4 | %f |
double | 双精度浮点数 | 8 | %lf |
数据类型的使用就是创建不同类型的变量并对其进行初始化(初始化就是对变量赋值),一下a b c d均是变量,因为我们可以通过赋值的方式修改其中的值。
char a = 'c';
int b = 4;
//short long long long 类型和int数据类型大同小异
float c = 2.6f;
double d = 2.7;
在float赋值后加上f可以让编译器认为数值是单精度浮点型;在不加f的情况下,编译器会将float创建的变量默认为double类型
4.2.2输出和输入
如何输出各种类型的数据,使用printf()函数,但是对于不同类型的数据,其输出的符号也是不一样的,代码如下
printf("%c\n", a);
printf("%d\n", b);
printf("%f\n", c);
printf("%lf\n", d);
printf("%.1lf\n", d);//.1表示小数点后只保留一位小数
其中\n是换行的标志,就是没打印一个字符就换一行,float和double的类型默认打印为小数点六位。想必大家看出来了,前面是符号的类型,后面就是变量名,这就是print函数应用。
我们使用的scanf()函数对不同数据类型的变量输入值以达到修改变量的目的,代码如下:
scanf("%c\n", &a);
scanf("%d\n", &b);
scanf("%f\n", &c);
scanf("%lf\n", &d);
上述代码&这个符号是取地址的符号,大家先记住,scanf()函数的使用方式就是和printf函数差上一个&符号
输入如下:
输出如下
4.3总结
1. 整型为什么分了四种呢?
四种类型的所占的空间不同,在程序可以灵活的创建变量以达到节省内存呢空间的目的
2.在创建float数据类型的时候,应该再小数后面加上f ,不然编译器会默认数组为double类型。在数据是float和double的时候编译器输出的数字是带有六位小数的。
3。char的是按ASCLL码来存储的,因此字符类型本质上也是整型家族的。
5.变量、常量
变量就是值可以改变;
常量就是值不可以改变。
5.1如何定义变量
变量命名: 数据类型 命名 = 赋值 ;
int age = 150;
float weight = 45.5f;
char ch = 'w';
在定义float数据的时候,编译器默认为double类型,需要加上f才可以。
5.2变量的分类
局部变量 在{ }内部定义的变量
全局变量 在{ }外部定义的变量
不建议将全局变量和局部变量的名字写成一样的。
#include <stdio.h>
int main()
{
int b = 3; //局部变量
int a = 345; //局部变量
printf("%d\n", a);
return 0;
}
如上图在{ }创建的变量是局部变量。
#include <stdio.h>
int a = 34;//全局变量
int main()
{
}
如上图 在{ }创建的变量是全局变量
大家猜猜如果局部变量和全局变量命名相同的情况下,那种变量更加优先权。代码如下
#include <stdio.h>
int a = 34; //全局变量
int main()
{
int a = 345; //局部变量
printf("%d\n", a);
return 0;
}
输出结果是那个,那个就有优先权,结果如下
看输出的结果是345是局部变量的值,但是全局变量是34。这样看来是局部变量和全局变量冲突的情况下,局部变量优先。一般来说不要把设置局部和全局变量名字相同。
5.3变量的使用
#include <stdio.h>
int main()
{
int a = 0;
int b = 0;
int sum = 0;
scanf("%d %d", &a, &b);
sum = a + b;
printf("sum = %d\n", sum);
return 0;
}
scanf("%d %d", &a, &b);
scanf函数 按指定的格式输入数据,上面输入的整型变量用%d的格式,变量必须地址的形式,&是取地址符号,&a表示取地址
printf("sum = %d\n", sum);
printf函数按照指定的格式输出数据,与scanf不同的是,可以直接写变量
5.4变量的作用域和声明周期
(1)作用域
一段程序代码中所用到的名字并不总是有效/可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。
1. 局部变量的作用域是变量所在的局部范围。
2. 全局变量的作用域是整个工程。
局部变量
#include <stdio.h>
int main()
{
{
int a = 5;
}
printf("%d", a);
return 0;
}
运行上面的程序,编译器就会报错?
因为{ }就是局部变量的作用域就是变量所在{ }的局部范围,如果在{ }之外的地方使用的,编译器识别不到。
全局变量
在一个源文件中定义的全局变量,全局变量就是没有限制使用空间的变量,在不同函数内不用重新定义就可以使用
在同一源文件(.C)文件下定义
#include <stdio.h>
int a = 5;
int main()
{
printf("%d", a);
return 0;
}
运行结果为5,全局变量是作用不会受到{ }的限制。
在同一个项目中的两个源文件中
运行结果是10,
可以看出全局变量的作用范围是整个项目文件,但是要在另一个XX.C文件中使用的 需要使用extern来声明一下;若未标注,程序是不会识别的。
(2)生命周期
变量的生命周期指的是变量的创建到变量的销毁之间的一个时间段。
1. 局部变量的生命周期是:进入作用域生命周期开始,出作用域生命周期结束。
2. 全局变量的生命周期是:整个程序的生命周期
生命周期和作用域的范围是一样的。变量作用多大范围,变量就会存在多长的时间。
全局变量的作用时间直到程序执行结束。
5.5常量
C语言中的常量分为以下以下几种:
字面常量
const 修饰的常变量
#define 定义的标识符常量
枚举常量
字面常量
在程序中单独存在的符号或数字,没有意义,但是可以存在
int main()
{
1000;
'a';
3.14;
return 0;
}
const修饰的常变量
在变量的前面加上const,变量将无法进行修改,可以看作是常量,但是本质上还是变量。
代码说明
#include <stdio.h>
int main()
{
const int a= 10;
a = 20;
printf("%d", a);
return 0;
}
看上图,无法对a进行修改,是const修饰的变量的特点。
如何证明被修饰的量是变量?代码如下
int main()
{
const int a= 10;
int arr[a] = {0};
printf("%d", a);
return 0;
}
看上图中的标注,明确说数组的值要是常量,可以证明出cons修饰的变量本质上还是变量。
#define 定义的标识符常量
无法修改是直接给标识符一个数字或者字符串
#define M 10
int main()
{
int arr[M] = { 0,2,3,5};
printf("%d",arr[M-1]);
return 0;
}
代码可以正常的运行,因此#define所定义的数值是常量。
枚举常量
可以将变量一一列举,关键词为enum,
代码如下
int main()
{
enum
{male,female,secret};//括号中的male,female,secret是枚举常量
printf("%d\n", male);
printf("%d\n", female);
printf("%d", secret);
return 0;
}
枚举常量的取值是从0开始依次增加的整数。
6.字符串+转义字符+注释
6.1字符串
"hello world"
这种由双引号(Double Quote)引起来的一串字符称为字符串字面值(String Literal),或者简称字
符串。
注:字符串的结束标志是一个' \0 '的转义字符。在计算字符串长度的时候 \0 是结束标志,不算作字符串%s是专门用来打印字符串的
int main()
{
char arr1[] = "hello";
char arr2[] = { 'h','e','l','l','0' };
char arr3[] = { 'h','e','l','l','0','\0' };
printf("%s\n", arr1);
printf("%s\n", arr2);
printf("%s\n", arr3);
return 0;
}
运行结果如下
arr2为何会出现乱码?
因为在打印的时候程序一直在寻找字符串的结束标志,但是内存中的结束标志也是随机的,我们可以使用strlen()函数来证明一下'\0'在未标注的情况下,出现的位置是随机的,代码如下:
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[] = { 'h','e','l','l','0' };
char arr2[] = { 'h','e','l','l','0','\0' };
int length1 = strlen(arr1);
int length2 = strlen(arr2);
printf("%d\n", length1);
printf("%d\n", length2);
return 0;
}
运行结果
前面是arr1的,是个随机数。
结论
'\0'是字符串结束的表中,"hello"的输入形式中会自带结束标志,而单个字符标注的情况下,是没有结束字符的,因此arr2中会出现随机值。
关于strlen()函数的问题,
作用:求字符串个数的函数,在()中输入数组或者字符串
头文件: <string.h>文件中包含strlen;在使用的前一定要标注包含
6.2转义字符
转义字符的作用就是改变字符原有的意思,在这里将转移字符介绍完毕,后续不在专门介绍
转移字符 | 作用解释 |
\? | 在书写连续多个问号时使用,防止他们被解析成三字母词 |
\' | 用于表示字符常量' |
\“ | 用于表示一个字符串内部的双引号 |
\\ | 用于表示一个反斜杠,防止它被解释为一个转义序列符。 |
\a | 警告字符,蜂鸣 |
\b | 退格符 |
\f | 进纸符 |
\n | 换行 |
\r | 回车 |
\t | 水平制表符 |
\v | 垂直制表符 |
\ddd | ddd表示1~3个八进制的数字。 如: \130 X |
\xdd | dd表示2个十六进制数字。 如: \x30 0 |
\?
早期 C语言中??)被解析为 ] 三字母词 组合为一个 ] 可以改写为\?\?) 将其改变意思输出的是??)
\' \"
普通的单引号打印 \ ' 双引号 \"
printf("%c\n", '\'');// ' 打印字符
printf("%s\n", "\"");// " 打印字符串时
\\防止转义
printf("c:\test\test.c");\\c: est est.c
我要打印的是文件的目录但是 \t是水平制表符,怎么要让他失去作用呢?
printf("c:\\test\\test.c"); \\c:\test\test.c
\a
printf("\a");\\启动电脑蜂鸣器,电脑响一下
\b \f 不常用
\n 换行 在打印完成之后换行
printf("a\n");
printf("a");
\t 水平制表符 向右挪8个空格位置的位置
printf("c:\test\test.c");\\c: est est.c
\V垂直制表符,向下挪8个空格位置的位置
\ddd 后三位为8进制数字
\xdd 后两位为16进制数字
八进制数是0开头的,16 进制的数字是0x开头的
printf("%c\n", '\101');//A-65
printf("%c\n", '\x30');//48- '0'
打印的时候对应的ASCLL,首先转换10进制,找到对应的ASCLL码表可以对照
注意每一个转移组长度都为1 \t 、\32长度都为1
出题 :下面字符串的长度是:14
"c:\test\328\test.c"
\32 8是两个字符。因为\32是8进制的 8没在八进制中啊。
6.3注释
1. 代码中有不需要的代码可以直接删除,也可以注释掉
2. 代码中有些代码比较难懂,可以加一下注释文字
C++风格的注释 //xxxxxxxx,可以注释一行也可以注释多行。
//#include <stdio.h>
// int a = 34;//全局变量
// int main()
// {
// int b = 345;//局部变量
// int a = 345;//局部变量
// printf("%d\n", a);
// return 0;
// }
//
代码全部注释之后,不可在使用,相当于没有了
C语言风格的注释 /*xxxxxx*/ , 缺陷:不能嵌套注释。
7.选择语句
一个简单的选择语句带大家了解一下,如果想进一步了解的话,可以看C语言笔记(分支和循环语句)(详细+实例)_c语言编程if语句分段函数-优快云博客当然也包括循环语句的。
if(判断条件)
{
}
else
{
}
上述是if else的结构,如果判断语句为真就执行if中{ }的程序,为假就执行else下{ }的程序。
在C语言中0为假,其他均为真
#include <stdio.h>
int main()
{
int a = 0;
printf("你会做这道题吗(选择1会 or 0不会)");
scanf("%d", &a);
if (a == 1)
{
printf("会,赶紧算,算完去吃饭");
}
else
{
printf("不会,毕业去买地瓜\n");
}
return 0;
}
输入0的话会执行else中的程序
8.循环语句
while 也是一个简单的程序让大家了解一下,如果看详细的可以等等,正在总结,预计三天完成。
while(判断条件)
{
}
while(判断条件),满足判断条件进入循环。
#include <stdio.h>
int main()
{
int line = 0;
while (line <= 20000)
{
line=line+1;
printf("我要继续努力敲代码\n");
}
if (line > 20000)
printf("一定成功\n");
return 0;
}
当line变量大于20000的时候就会跳出循环,执行if语句.
最后的结果肯定是两万行我要继续努力敲代码,再加上 一定成功
9.函数
函数的特点就是简化代码,代码复用.如果想了解的更加详细可以看这个C语言笔记(函数篇一)-优快云博客
函数分为库函数和自定义函数
库函数就是存储在头文件中,要想使用函数,应该将头文件包含其中使用#include<>
自定义函数就是自己定义的,如下:定义的是一个两数求和的的函数
#include <stdio.h>
int Add(int x, int y) //函数的名字,接受传来的数值
{
int z = x+y; //进行计算
return z; //将Z的值返回到main()函数中
}
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;
}
int Add(int x, int y)
自定义函数 int 是函数返回类型,就是return后面那个值的类型,没有返回值时候用void代替。
Add是函数的名字,提的名字要有意义
(int x,int y)是形式参数,创建的变量应该和传递过来的数值是同一种数据类型。
sum = Add(num1, num2);
调用函数,并将用到的函数标出来,num1对应x,num2对应y。sum来接受来自自定义函数的返回值
10.数组
10.1数组定义
要存储1-10的数字,怎么存储?
数组的定义:一组相同类型元素的集合
int arr[10] = {1,2,3,4,5,6,7,8,9,10};//定义一个整形数组,最多放10个元素
int arr2[5] = { 'a','b','c' };
数组中可以存储不同的数据类型,符号中的[ ]是元素的多少,当然数组大小的指定必须是常量,可以指定也可以不指定。没有指定的情况下,会将初始化元素的多少当成括号中的数字,注意的是!!!两个必须有一个,不然不会创建成功。
arr2为不完全初始化 后两个元素是'\0'; 如果是int 整数类型,那么剩余的为0
10.2数组的使用
数组是有下标的,下标是从0开始的,假设数组有n个元素,最后⼀个元素的下标是n-1,下标就相当于数组元素的编号,如下:使用下标引用的操作符[ ] arr[0]表示第一个元素,以此类推如下图
访问第七个元素
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
printf("%d\n", arr[7]);//8
printf("%d\n", arr[3]);//4
return 0;
}
11操作符
详细的操作符大家可以看这个C语言笔记(操作符篇)-优快云博客。
算术操作符
+ - * / %
+ - * 正常使用条件下没有可以注意的
/的使用
(1) 在只有整型的情况下 ,例如9/2=4,整除之后直接的结果保留整数,如下方的表示()
(2)在想要输出小数点后部位零的数的时候,两个除数和被除数其中又以个要为0;
12关键字
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
关键字很多这里只介绍几个,当然在后面的内容中用的时候就慢慢认识了。
C语言提供的关键字,关键字不能被创建,不可以做变量的名字,
auto 自动的意思,每一个局部变量都是auto修饰的,基本都是可以省区去的,当然还有其他的用法,暂不考虑。
break用来跳出循环;default配合switch的使用,在没有任何case匹配的情况下,全部转接到default处,结束分支。
register 和寄存器相关的关键词,但是现在的编辑器都会自己分辨了,哪一个变量是适合进入寄存器,会自动分配的。画一个表格,可以看看存储地方的区别。
分类 | 大小 | 速度 |
寄存器 | 更小 | 速度非常快 |
高速缓存 | 几十MB | 更快读写速度 |
内存 | 8G-16G | 读写速度快 |
硬盘 | 512GB | 速度较快 |
网盘 | 2TB | 传输速度慢 |
从上到下,存储空间一次增大,但是读写速度一次变小。就硬盘和网盘之间,我们可以从网盘的西在速度,和硬盘之间文件的转移速度来看,计算机自带硬盘读写速率较高。
因此我们将大量频繁使用的数组的数据存储在寄存器中,以达到提升效率的目的。
signed有符号的,数字由正负之分的;unsigned无符号的,数字无符号之分的。
static静态的 ;struct结构体(下面会提及到),void空白的;union 联合体(共用体)。
以上仅仅只是简单的提及,关键字经常使用的,大家不用怕,使用次数多了,也就理解了。
注意!!!define,include 不是关键字,是预处理指令,算作程序。
13指针
详细篇大家可以看C语言笔记(指针篇)-优快云博客,比较详细,在这里我们只是引入指针的概念和简单的使用。
指针理解最为重要,首先我们先理解内存,内存就是计算机上的存储空间,程序运行的时候会载入内存,程序的数据存储也需要内存。内存可以理解为空间,但是这个空间被分成了许多的小份,类比于我们的宿舍公寓;每一个小份的空间大小是一样的(一个小份是8个字节),类比于每个宿舍的大小空间是一样的;每一个小份空间都有自己的编号,类比每个宿舍都有门牌号。如果不理解就请先记住。当然每一份空间存储的东西也不一样啊。
我们在聊一聊内存是如何编号的;32位的机器有32根地址线构成,在通电的情况下,电信号的识别只有0/1也就有了两种情况,32根地址线排序,0/1不停的变换有 2的三十二次方的编号,为每一个小空间编号。如图:
代码如下
int main()
{
int a = 10;
int* pa = &a; //int* 创建整型变量的指针需要加*,其他数据类型对应改变
printf("%p\n", pa); //&取地址符号,取得是a的首个字节
printf("%p", &a);
return 0;
}
14结构体
结构体其实就是创建囊括多个数据类型的一个类型
比如描述学生,学生包含: 名字+年龄+性别+学号 这几项信息。
struct Stu
{
char name[20];
int age;
char sex[20];
float score;
};
int main()
{
//打印结构体信息
struct Stu s = { "张三", 20, "男", 95.0f };
//.为结构成员访问操作符
printf(" %s %d %s %.1f\n", s.name, s.age, s.sex, s.score);
//->操作符
struct Stu *ps = &s;
printf(" %s %d %s %.1f\n", ps->name, ps->age, ps->sex, ps->score);
return 0;
}