目录
第一章 C语言入门
一、程序
程序的执行
二、C语言
1.C语言的几个常用版本
2.C语言的特点
3.IDE
4.C语言标准库
三、c程序运行机制
四、c程序的主体结构
注意事项
五、常用的转义字符
六、注释(comment)
七、c程序代码规范
第二章 变量
一、变量的定义
注意事项
二、输入/输出变量
三、变量的数据类型
1.整型
2.浮点型
3.字符型
4.ASCII编码表
5.布尔类型(boolean)
四、基本数据类型转换
1.自动类型转换
2.强制类型转换
第三章 指针入门
一、指针的定义
二、指针的基本用法
注意事项
第四章 值传递和地址传递
第五章 常量
一、常量的常见类型
1.整型常量
2.浮点常量
3.字符常量
4.字符串常量
二、常量的定义
1.#define预处理器定义常量
2.const关键词声明指定类型的常量
3.const和#define的区别
第六章 运算符
一、算数运算符
二、关系运算符
三、逻辑运算符
四、赋值运算符
五、位运算符
六、三元运算符
七、运算符的优先级
第七章 标识符
一、标识符的命名规则
二、标识符的命名规范
关于命名规范
三、关键字
第八章 键盘输入语句
vs的c语言输入语句
第九章 进制
一、进制的转换规则
1.其他进制转十进制
2.十进制转其他进制
3.其他进制转二进制
4.二进制转其他进制
二、二进制
三、位运算
⭐程序是让计算机执行某些操作或解决某个问题而编写的一系列有序指令的集合
⭐计算机能懂的语言是二进制,程序员能看懂的是编程语言
⭐计算机做的所有事情都是计算,计算的步骤就是算法
⭐解释:借助一个程序,由这个程序读懂程序员的代码,并按照要求执行
⭐编译:借助一个程序,将程序员所写的编程语言,翻译成机器语言,以供计算机直接执行
任何语言都可以解释或编译,解释和编译只是他们的执行方式
--- 解释型语言有特殊的计算能力
--- 编译型语言有确定的运算性能
⭐语言的能力和使用领域主要由库和传统所决定
⭐现代编程语言语法上的差异很小,几乎都是C-like
⭐C语言是编译型语言
⭐C程序通常运行在linux/unix操作系统下
ANSI C【标准C】、C89、C99
所有当代编译器几乎都支持C99
ANSI:美国国家标准局
ISO:国际化标准组织
丹尼斯.里奇:C语言之父、UNIX之父【第四版Unix完全由c语言重新写的】
代码级别的跨平台【可用于多种操作系统,适用于多种机型】
允许直接访问物理地址,对硬件进行操作,可用于编写系统软件
有结构化程序设计、有变量作用域以及递归功能的过程式语言
可以值传递,也可以指针传递
面向过程,没有对象,不同的变量类型可以用结构体(struct)组合在一起
预编译处理,代码质量高,执行效率高
⭐集成开发环境,用于开发软件的程序
一组C内置函数、常量和头文件,可以作为C程序员的参考手册
math.h 各种数学函数和一个宏
stdio.h 定义了三个变量类型、一些宏和各种函数来执行输入和输出
stdlib.h……
编写 --- 编写.c源代码【放在项目文件夹里】
编译 --- .c源文件通过编译器,编译成.obj目标文件 【由cl.exe程序完成,放在项目文件夹的debug文件夹里】
链接 --- 在C程序中,会使用到部分C程序库的内容【头文件】,通过链接程序,将.obj目标文件和库文件【在程序中使用到的库文件,由系统提供】链接成.exe可执行文件【由link.exe程序完成,放在解决方案文件夹的debug文件夹里】
运行 --- 执行.exe可执行文件【二进制文件】,得出执行结果只编译链接不运行:
修改后的源文件,需要重新编译链接,才能生效,可以用“生成 -> 重新生成解决方案”
cl.exe和link.exe均在vs的bin目录下
1.引入头文件
2.main函数,程序的执行入口,程序从main函数开始执行,大括号中的内容为main函数的函数体
#include
void main() //void表示main函数没有返回值
{
printf("北\t上\t广\n");
printf("Hello\\ \"World!\'");
getchar();//使窗口停留
}
⭐c语言严格区分大小写
⭐每条语句以分号结尾
⭐大括号“{}”成对出现,缺一不可
\t --- 表示一个制表位,tab
\n --- 表示换行输出
\\ --- 表示一个‘\’
\' --- 表示一个‘'’
\" --- 表示一个‘"’
\r --- 表示回车,光标回到开头,会覆盖之前输出的内容
对程序进行说明解释的文字,注释的内容不会执行
//单行注释
/*
多行注释
*/
⭐块注释【多行注释】里不能嵌套块注释
注释快捷键 --- ctrl+k,ctrl+c;取消注释 --- ctrl+k,ctrl+u
1.注释风格:
--- 函数用块注释,语句用单行注释
2.正确的缩进和空白
--- tab向右移,shift + tab向左移
--- 运算符两边习惯各加一个空格
--- 代码格式化快捷键ctrl + k,ctrl + f
3.函数块的风格 --- 行尾风格 和 次行风格【同一个程序最好使用统一风格】
函数注释范例:
/*
函数名:xxx
参数:int n1,int n2
返回类型:xxx
功能:该函数用于xxx
作者:xxx
日期:xx年xx月xx日
*/
#include
void main()
{
int num = 1;
double score = 2.3;
char gender = 'A';
char name[] = "阿白";
/*
变量:程序的基本组成单位
--- 相当于内存中一个数据存储空间的表示,通过变量名可以访问到变量值
*/
printf("num = %d\t\tgender = %c\tscore = %.2f\tname = %s",num,gender,score,name);
/*
输入/输出整型 --- %d
输入/输出长整型 --- %ld
输入/输出小数 --- %.小数位数f
输入/输出字符 --- %c
输入/输出字符串 --- %s
*/
}
⭐程序的基本组成单位
⭐是内存中一个数据存储空间的表示,通过变量名可以访问到变量值
⭐不同的数据类型,占用的空间大小不同
⭐变量必须先声明,后使用
⭐变量表示内存中一个存储区域,该区域有自己的名称【变量名】和类型【数据类型】,该数据可以在同一类型范围内不断变换【更改变量值】
⭐变量在同一个作用域内不能重名
⭐变量三要素:变量名 + 数据类型 + 值
输入/输出整型 --- %d
输入/输出长整型 --- %ld
输入/输出小数 --- %.小数位数f
输入/输出字符 --- %c
输入/输出字符串 --- %s
每一种数据都定义了明确的数据类型,在内存中分配了不同大小的内存空间【使用字节数】
⭐C数据类型分为:基本类型、构造类型、指针类型、空类型void
--- 基本类型包括:数值类型【整型[短整型short/整型int/长整型long/long long]、浮点型[单精度float/双精度double]】 和 字符类型[char]
--- 构造类型包括:数组、结构体struct、共用体union、枚举类型enum
--- 指针类型【存放地址】
--- void空类型
⭐在c中没有字符串类型,它使用字符数组来表示字符串
⭐各数据类型的存储大小与操作系统、系统位数和编译器有关,可以用sizeof()查看所占用字节数
用于存放整数值
c语言的整型分为 有符号 和 无符号 两种,默认是signed【有符号】
int/signed int --- 带符号+/-的整数,字节数为2/4字节,范围(-2^(2*8-1)~2^(2*8-1)-1)【1byte = 8bits,带符号减1位,所示范围为两字节的】
unsigned int --- 不带符号-的整数,字节数为2/4字节,范围(0~2^(2*8)-1)
bit(位)计算机中最小存储单位;byte(字节)计算机中基本存储单位【1 byte = 8 bit】
用于存放小数
float单精度 --- 4字节 --- 1.2E-38 ~ 3.4E+38 --- 6位小数
double双精度 --- 8字节 --- 2.3E-308 ~ 1.7E+308 --- 15位小数
⭐浮点数在机器中的存放形式:浮点数 = 符号位 + 指数位 + 尾数位
⭐浮点数是近似值,尾数可能由于丢失,而造成精度损失
⭐浮点型默认为double型,默认保留小数点后六位输出,声明float常量时,须在数值后加‘f’或‘F’
⭐通常情况下,应该使用double类型,更精确
浮点型常量有两种表示形式
十进制数形式【5.12、5.12f、.512 --- 必须有小数点】
科学计数法【5.12e-2】
字符常量是使用单引号括起来的单个字符
⭐多个字符称为字符串,在c语言中,用char数组表示
char --- 1字节 --- 可以存放字母或数字
⭐在c中,允许使用转义字符作为字符型
在c中,char的本质是一个整数,是ASCII编码表【特殊字符和数字的对应关系】中对应的字符
⭐可以直接给char类型赋值整数,会按照对应的ASCII字符输出
⭐char类型是可以运算的,相当与一个整数
字符型存储到计算机中,需要根据编码表找到对应的码值(整数),并转换为二进制进行存储
字符和码值的对应关系是通过字符编码表对应好的
⭐计算机内部的所有数据用二进制(0/1)存储,一个字节(8位)可以组合出256种状态,每一各状态对应一个符号
⭐ASCII编码表由美国制定,英文字符与二进制位之间的关系
⭐ASCII编码表不能表示所有的字符,在ASCII的基础上,最常用的编码表Unicode万国码
0为假,非0为真,本质上是整型
//可以借助C语言宏定义,更直观的展现布尔类型——
#define BOOL int
#define TRUE 1
#define FALSE 0
……
void main()
{
……
BOOL isOk = TRUE;//<==>int isOK = 1;
……
}
⭐C99提供了_Bool型,它仍是整数类型,只能赋值为0或1,非0的值会被存储为1
⭐C99提供了
⭐bool类型常用于条件控制语句或循环控制语句
自动类型转换 & 强制类型转换
c程序在进行赋值或运算时,精度小的数据类型【表示范围较小的】自动转换为精度大的【表示范围较大的】
精度从低到高:
short/char -> int -> unsigned int -> long -> unsigned long -> double -> long double
【float -> double】
多种数据类型混合运算时,系统自动将所有数据转换成精度最大的数据类型
两种数据类型字节数不同,自动转换成字节数大的类型;若两种类型字节数相同,一种有符号,一种无符号,转换成无符号类型
在赋值运算中,赋值号两边数据类型不同,赋值号右边的数据类型将转换成左边的数据类型,若右边的数据类型比左边长时,可能丢失一部分数据,导致精度降低
将[精度高的数据类型]转换为[精度低的数据类型],可以使用强制转换符"()",可能造成精度降低或溢出
(数据类型) 表达式 //这种强制类型转换操作并不改变操作数本身
⭐浮点型强转int,不是四舍五入,而是直接截断小数点后面的部分
强制转换符只对最近的数值有效,需要针对更多表达式,可以将表达式用括号括起来
指针表示一个地址
#include
void main()
{
/*
指针案例:
1.写一个程序,获取一个int变量num的地址,并显示到终端
2.将num的地址赋给指针ptr,并通过ptr去修改num的值
*/
int num = 0;
int* ptr = #
printf("修改前 -- num的地址是:%p;num的值是:%d\n", ptr, *ptr);
*ptr = 10;
printf("修改后 -- num的地址是:%p;num的值是:%d\n", ptr, *ptr);
}
数据类型* 指针名 = &变量名;
⭐即:定义一个指针,该指针的内存中存放了变量的地址
⭐可以通过解引用 *指针名 来获取指针指向的变量的值
输入/输出地址 %p
取地址符 &变量名
获取指针的地址 &指针名获取变量的地址 指针名
获取变量的值 *指针名
⭐指针的数据类型与该指针指向的变量的数据类型必须相对应(如,int的对应指针是int*)
⭐除基本数据类型外,还有指向数组、结构体、共用体的指针,二级指针,多级指针等
⭐C语言传递参数(或赋值)可以是值传递(pass by value),也可以传递指针/地址传递(a pointer passed by value)
⭐默认传递值的类型:基本数据类型(整型、浮点型、字符型)、结构体、共用体
⭐默认传递地址的类型:指针、数组
⭐值传递:将变量指向存储的内容,在传递/赋值时,拷贝一份给接收变量
⭐地址传递/指针传递:指针 --- 将指针变量存储的地址,拷贝一份传递给接收变量;数组 --- 将数组的首地址传递给接收变量
又称字面量,是固定的值,在程序执行期间不可改变
⭐常量可以是任何基本数据类型(如,整型、浮点型、字符型、字符串、枚举)
⭐常量的值在定义后不能修改
#include
#define YEAR 2022
#undef YEAR //取消YEAR的定义
#define YEAR 2023 //重定义
#define DEBUG
int main(void)
{
//若字符串常量过长,可以在某行字符串末尾加上“\”,另起一行,继续编写代码
char str[20] = "hello \
world\n";
const int month = 12;
printf("%d年有%d个月\n", YEAR, month);
#ifdef DEBUG //如果定义了常量DEBUG
printf("调试信息");
#endif // DEBUG
#ifndef DEBUG
printf("没有定义DEBUG");
#endif // !DEBUG
return 0;
}
可以是十进制、8进制、16进制
⭐前缀为0是八进制、前缀为0x或0X是16进制【零X】,不带前缀默认是十进制
⭐整型常量的后缀U/L --- 不区分大小写,U代表无符号整数(unsigned),L代表长整数(long),U和L的顺序任意
由整数部分、小数点、小数部分和指数组成,可以使用小数形式或指数形式来表示(3.14,314E-2,3.14f)
括在' '中的单个字符,可以是一个普通字符,也可以是一个转义序列
括在""中的内容,一个字符串常量可以包含普通字符、转义序列和通用字符
在编写C语言程序时,若字符串常量过长,可以在某行字符串末尾加上“\”,另起一行,继续编写代码
包括:使用#define预处理器;使用const关键词
#define 常量名 常量值
前面带#号,一般都是预处理器
const 数据类型 常量名 = 常量值;
⭐const定义常量时,需要指定数据类型,define不带类型
⭐const在编译、运行时起作用,define是在编译的预处理阶段起作用
⭐define只是简单的替换,没有类型检查,简单的字符串替换可能会导致边界效应(你把它当一个整体,但事实并非如此)
//define只是简单的替换
#define A 1
#define B A+3 //B的值是“1 + 3”
#define C A/B*3 //C的值是“1 / 1+3 * 3”
⭐const常量可以进行调试,define不能进行调试
因为define在预编译阶段就替换掉了,调试的时候没有define
⭐同一个const常量不能重定义,而define可以通过undef取消某个符号的定义,再重新定义
⭐define还可以配合#ifdef、#ifndef、#endif来使用,让代码更加灵活(如,可以通过define来启动或关闭调试信息)
一种特殊的符号,用以表示数据的运算、赋值和比较等
算数运算符(+、-、*、/、%) 赋值运算符(=、+=、-=……)
关系运算符(比较运算符)(>、<、==……) 逻辑运算符(&&、||、!)
位运算符(&、|、^、~) 三元运算符(表达式 ? 表达式1:表达式2)
对数值类型的变量进行运算
⭐+(正/加)、-(负/减)、*、/、%、++(先用后加、先加后用)、--(先用后减、先减后用)
⭐运算符的运算流程,第一步获取右侧表达式中各数值;第二步按表达式中精度最高的数据类型,先转换后运算;将右侧表达式的结果赋值给左侧,并转换为对应的精度
⭐做除号运算时,如果结果要double型,每一步运算中需要确保有一个double型算子
⭐计算机中的取模公式:a % b = a - a / b * b当a和b中有一个是负数,你可以通过公式,知道计算机会给你一个什么结果
⭐自增与自减:符号在前,先算(自增/自减)后用;符号在后,先用后算
⭐关系表达式常用在 if结构 的条件中或 循环结构 的条件中
⭐关系运算符的结果要么是真(非0,默认是1),要么是假(0)
⭐关系运算符组成的表达式,称为关系表达式
==、!=、>、<、>=、<=
用于连接多个条件(一般是关系表达式),运算结果要么是真(非0,默认是1),要么是假(0)
&&(逻辑与,全真为真)、||(逻辑或,有真即真)、!(逻辑非,假的是真)
⭐在进行逻辑与操作时,a & b,若表达式a的值为假,则不再计算并判断表达式b,该现象称为短路现象
⭐在进行逻辑非操作时,a || b,若表达式a的值为真,则不再计算并判断表达式b
将某个运算后的值赋给指定的变量
⭐赋值运算的顺序是从右向左
⭐赋值运算符的左侧只能是变量,右侧可以是变量、表达式、常量值
=、+=、-=、*=、/=、%=、<<=、>>=、&=、^=、|=(和位运算符相关)
位运算符作用于位(bit),并逐位执行操作 [要彻底搞懂位运算符,要先学习二进制]
&(按位与)、|(按位或)、^(异或)、~(取反)、<<(左移)、>>(右移)
条件表达式 ? 表达式1: 表达式2;
⭐若条件表达式为真(非0),运算结果为表达式1;若条件表达式为假(0),运算结果为表达式2
⭐表达式1和表达式2要是可以赋给接收变量的类型(或可以自动转换),否则会有精度损失
⭐三元运算符可以转换为if--elss语句
运算符优先级:
第一类:[](数组下标)、()(圆括号,用于(表达式)、函数名(形参表))、.(对象的成员选择)、->(指针的成员选择)
第二类【单目运算符】:-、+(正负号)、(类型)(强制类型转换)、++、--、*(取值运算符)、&(取地址符)、!、~(按位取反)、sizeof()(长度运算符)
第三类:/、*、%
第四类:+、-
第五类:<<(左移)、>>(右移)
第六类:>、>=、<、<=
第七类:==、!=
第八类:&(按位与)
第九类:^(按位异或)
第十类:|(按位或)
第十一类:&&
第十二类:||
第十三类【三目运算符】: ? : (条件运算符)
第十四类【赋值运算符】:=、+=、-=、*=、/=、%=、<<=、>>=、&=、^=、|=
第十五类:,(逗号运算符)
总结:
1.运算符结合的方向大都是从左向右,只有三个是从右向左结合:第十三类 --- 三目运算符、第十四类 --- 赋值运算符、第二类 --- 单目运算符
2.所有的双目运算符中,只有赋值运算符的结合方向是从右向左的
3.逗号的运算符优先级最低
4.运算符的大致优先级:括号、指针运算符 > 单目运算符 > 算数运算符 > 左移右移 > 关系运算符 > 位运算符 > 逻辑运算符 > 三目运算符 > 赋值运算符 > 逗号运算符
5.同级别的优先级问题:
.的优先级高于*(->操作符用于消除这个问题)
[]高于*(如,int *ap[])
函数()高于*(如,int *fp())
综上,同为第一类运算符,小星星是垫底的存在
对各种变量、函数等命名时使用的字符序列,凡是自己可以起名的地方都叫标识符
神奇的知识,main也是标识符
1.标识符由字母大小写、数字、下划线或$组成,严格区分大小写
2.数字不能作为开头,不可以含有空格
3.不可以使用关键字,但可以包含关键字
1.不能出现仅靠大小写区分的相似标识符
2.所有宏定义、枚举常数、常量(只读变量),都用大写字母命名,用下划线分隔单词
3.定义变量不要忘记初始化:定义变量时,编译器不一定清空变量指向的内存,它的值可能是无效数据,可能导致程序异常退出
4.变量名、函数名的命名规范:小驼峰,多单词组成时,第一个单词首字母小写,后续单词首字母大写
在网上浏览到的一种命名规范
⭐局部变量/函数 --- 小驼峰命名法;
⭐其他变量(模块变量、全局变量、指针变量) --- 匈牙利 + 下划线 + 小驼峰;
⭐宏定义、枚举常数、常量 --- 大写的下划线命名法
匈牙利命名:前缀字母用变量类型的缩写,其余部分用英文单词或其缩写,单词首字母大写
小驼峰和大驼峰:区别在于首字母小写或大写
下划线:把各单词用下划线分隔开来
在C语言中赋予了特殊的含义,关键字中所有字母都为小写
scanf()函数,包含在
注意的是,输入数据后,回车按钮会被当作字符读取,这时可以用getchar()来接收这个回车
在文件末尾,暂停程序可以使用两个getchar()
vs的神奇输入语句,见代码
#define _CRT_SECURE_NO_WARNINGS //可以把这行copy到网上,有一劳永逸的解决办法
#include
void main()
{
char name[10] = "";
double score = 0.0;
char sex = ' '; //要求字符一定要包含一个值
printf("请输入你的姓名:");
scanf("%s", name);
//scanf_s("%s", name, 10); vs接受的另一种方式
/*
关于scanf返回值被忽略(scanf()函数不安全):
This function or variable may be unsafe. Consider using scanf_s instead.
To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
vs编译器认为scanf不安全,可以改为使用scanf_s,
或使用#define _CRT_SECURE_NO_WARNINGS来解决这个问题,但是!
scanf_s的使用和scanf还有所不同,在输入字符串时,如果你使用scanf()函数的输入方式:
它会疯狂报错,提示写入位置时发生访问冲突&堆栈Cookie检测代码检测到基于堆栈的缓冲区溢出
正确的写法是[scanf_s("%s", name, 10);]
--- 10这个数字是用来指定缓冲区大小的参数,表示最多读取9(n-1)个字符,
不加的话,编译器会报错,无法进行正常的字符串输入...
另外一个#define _CRT_SECURE_NO_WARNINGS的神奇知识:
如果你写在inclde之后,是不会起作用的...
因为宏定义的作用域范围为:从宏定义命令开始到源文件结束
scanf及scanf_s函数的定义是在之中的,消除报错,要把他包含在宏定义的作用域内
*/
printf("请输入你的成绩:");
scanf("%lf", &score);
getchar(); //这里的getchar()接收了一个enter键,以继续性别的输入
printf("请输入你的性别(m男/w女):");
scanf("%c", &sex);
printf("你的姓名是%s,性别%c,年龄%.1f", name, sex, score);
}
整数的四种表示方式:
⭐二进制,0、1,满2进1,C语言没有二进制常数的表示方法
⭐十进制,0-9,满10进1
⭐十六进制,0-9及A-F,满16进1,以0x或0X开头,此处英文不区分大小写,a-f等价于A-F
一串n进制数字转十进制:
从个位开始转换:个位 * n ^ 0 + 第二位 * n ^ 2 + 第三位 * n ^ 3 + ……
将十进制数转换为n进制:
不断除以n,直到商为0,将每步得到的余数倒过来,就是对应的数值
n进制数中的每一位,转成对应的一个3位[八进制]/4位[十六进制]的二进制数即可
从低位开始,将二进制数每3位[八进制]/4位[十六进制]一组,转成对应的八进制/十六进制数
计算机底层都采用二进制,易于实现
1.有符号的二进制,最高位是符号位:0表示正数,1表示负数
2.正数的原码、反码、补码都一样(三码合一)
3.负数的反码 = 原码符号位不变,其他位取反
4.负数的补码 = 反码 + 1
5.0的反码、补码都是0
6.计算机运算时,都以补码的方式计算[可以把正数、负数统一起来]
&(按位与)、|(按位或)、^(按位异或)、~(按位取反)、<<(左移)、>>(右移)
1.按位与:二进制,同1为1
2.按位或:二进制,有1为1
3.按位异或:二进制,同则为0,异则为1
4.按位取反:二进制,取反
5.左移:二进制,将一个算子的二进制位全部左移若干位(左边的二进制位丢弃,右边补0)
6.右移:二进制,将一个算子的二进制位全部右移若干位(右边的二进制位丢弃,左边正数补0,负数补1)
位运算的范例
(举例~2)
1.2的补码与原码相同:00000000 00000000 00000000 00000010(四个字节)
2.取反:11111111 11111111 11111111 11111101(补码,左边第一位是1,负数)
3.补码转反码:11111111 11111111 11111111 11111100
4.反码转原码:10000000 00000000 00000000 00000011
5.得到结果:-3(举例2&-3)
1.2的补码:00000000 00000000 00000000 00000010
2.-3的反码:11111111 11111111 11111111 11111100
3.-3的补码:11111111 11111111 11111111 11111101
4.2&-3:00000000 00000000 00000000 00000000(左边第一位是0,正数,原反补相同)
5.得到结果:0(右移和左移)
1.正数n的右移,左移x(比如3)位,相当于n除以x次2: n / 2 / 2 / 2 ,取整数
2.其他的左移右移,还是按照二进制运算方式计算