1)程序设计语言的发展:
第一代语言:机器语言(0,1)
第二代语言:汇编语言(add 1,2)
第三代语言:高级语言(结构化C-Fortran-Basic-Pascal、面向对象C+±Java-C#)a+b
2)C的特点
优点:代码量小、速度快、功能强大
缺点:危险性高、开发周期长、可移植性弱
3)应用领域
CPU 内存条 硬盘 显卡 主板显示器 之间的关系
内容顺序:硬盘==>内容==>CPU==>结果(显卡、声卡)
主板提供一个整体框架
helloworld
程序如何运行起来的
编译-链接==>.exe文件==>操作系统运行
什么是数据类型
基本类型数据:
复合类型数据
什么是变量
在定义变量时,通过与内容条中的空闲地址进行链接,将赋值的内容放入地址中
变量的本质就是内存中的一段存储空间
cpu内存条 vc++6.0 操作系统 之间的关系
定义变量与内存条的存储空间产生关联,执行生成.exe后,利用操作系统进行运行
变量为什么必须要初始化
所谓初始化就是赋值的意思
注:
内存的基本概念
内存是用来存储数据的设备。它的存储速度介于寄存器和硬盘之间。
内存条时CPU唯一可以访问的大容量的存储设备!所有硬盘中的程序和数据必须调入内存后方可被CPU执行!切记:CPU不能直接处理硬盘中的数据!
内存的问题时软件开发中最核心的问题之一!如:内存的分配,内存的释放,内存什么时候分配,内存什么时候释放,由谁来分配,由谁来释放,分配在是什么地方,访问权限如何!
内存是多字节组成的线性一维存储空间。
内存的基本划分单位是字节。
每个字节含有8位。每一位存放1个0或1个1.
字节和编号是一一对应的。每个字节都有一个唯一确定的编号,一个编号对应一个字节!这个编号也叫地址。
一个系统所能管理的内存空间的大小取决于参与编号的二进制位数。
如:DOS系统20位寻址方案可控制 2 20 2^{20} 220B 即1MB的内存
386/486系统采用三字节编制,可寻址 2 24 2^{24} 224M 即16M的内存
奔腾寻址空间32位,其有效寻址空间为 2 3 2 2^32 232M 即4GB
软件运行与内存关系(垃圾数据)
综上所述,一个软件所分配到的空间中极有可能存在着以前其他软件使用过后的残留数据,这些数据被称之为垃圾数据。所以通常情况下我们为一个变量,为一个数组,分配好存储空间之后,都要对该内存空间初始化!
如何定义变量
数据类型 变量名 = 要赋的值
等价于
数据类型 变量名;
变量名 = 要赋的值
举例子
int i = 3; 等价于 int i; i = 3;
int i, j; 等价于 int i; int j;
int i, j=3; 等价于 int i; int j; j=3
int i = 3; j = 5 等价于 int i ; int j; i=3; j=5
int i, j; i=j=5; 等价于 int i, j; i =5; j=5;
什么是进制
十进制就是逢十进一 D %d表示以十进制输出
二进制逢二进一 B
八进制 O %o表示以八进制输出
十六进制 H %x或%X表示以十六进制输出
注释:// /**/
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cCjzjjnI-1627043706049)(C:\Users\98614\AppData\Roaming\Typora\typora-user-images\image-20210628161500212.png)]
常量在C语言中是如何表示的
整数
浮点数
传统的写法 float x = 3.2;
科学计数法 float x = 3.2e3; //x的值时3200
注:double赋给float可能会丢失数据,可在数据后加F,表示赋予float。
字符
单个字符用单引号括起来 ‘A’
字符串用双引号括起来 “AB”
注:“A”正确,因为“A”代表了‘A’‘\0’的组合
常量以什么样的二进制
编码
int i = 86;
整数以补码的形式转换为二进制代码存储在计算机中的实数是以IEEE754标准转化为二进制代码存储在计算机中的字符的本质实际也是与整数的存储方式相同。
代码规范化
缩进,一对括号, 函数后空格,运算符左右加空格,运算级别最低的地方敲空格
换行,功能相对独立,进行换行。
什么是字节
字节就是存储数据的单位,并且是硬件所能访问的最小单位。
1 字 节 = 8 位 1字 节=8位 1字节=8位; 1 k = 1024 字 节 1k=1024字节 1k=1024字节; 1 M = 1024 k 1M=1024k 1M=1024k; 1 G = 1024 M 1G=1024M 1G=1024M
不同类型数据之间相互赋值的问题
int i = 45;
long j = 102345;
i = j;
printf("%ld %d\n", i, j);
float x = 6.6;
double y = 8.8;
printf("%f %lf\n, x, y")
什么是ASCII
ASCII不是一个值,而是一种规定。
ASCII规定了不同的字符是使用哪个整数值去表示
它规定了
‘A’–65; ‘B’–66; ‘a’–97; ‘b’–98; ‘0’–48 ………
字符的存储[字符本质上与整数的存储方式相同]
基本的输入和输出函数的用法
printf()
:将变量的内容输出到显示器上
printf("字符串\n")
;printf("输出控制符", 输出参数);
// d是十进制,o是八进制,x十六进制printf("输出控制符1 输出控制符2...", 输出参数1,输出参数2...);
// 输出控制符和输出参数的个数必须一一对应printf("输出控制符 非输出控制符,", 输出参数);
// 输出控制符包含:%d %ld %c %f %lf %o %s %x(或者%X或者%#X)
#表示显示字符关系scanf()
:通过键盘将数据输入到变量中
用法一:scanf("输入控制符", 输入参数);
功能:将从键盘输入的字符转化为输入控制符所规定格式的数据,然后存入以输入参数的值为地址的变量中。//&i 表示i的地址 &是一个取地址运算符scanf("%d", &i);
用法二:scanf("非输入控制符 输入控制符", 输入参数);
功能:将从键盘输入的字符转化为输入控制符所规定格式的数据,然后存入以输入参数的值为地址的变量中(非输入控制符必须原样输入)
如何使用scanf
编写出高质量代码
使用scanf
之前最好先使用printf
提示用户以什么样的方式来输入
scanf
中尽量不要使用非输入控制符,尤其是不要用\n
(非常不好的格式,不要加\n
)
应该编写代码对用户的非法输入做适当的处理。
while ((ch=getchar()) != '\n')
continue;
scanf
中输入会逐个字节解析,如果存在问题,则停止解析后面的,直接赋值,再次解析时,从停止位置开始,完成解析过程。
代码注释
时间,功能,目的,输出结果,总结
int
,则商就是int
,若商有小数,则截取小数部分;被除数和除数中只要有一个或两个都是浮点型数据,则商也是浮点型,不截取小数部分。什么是流程控制
成都代码执行的顺序
流程控制的分类
顺序执行
选择执行
定义:有些代码可能执行,也可能不执行,有选择的执行某些代码
分类:
if
if 最简单的用法
格式:
if (表达式)
语句
功能:
如果表达式为真,执行语句;不成立,语句不执行
if的范围问题
if (表达式)
语句A;
语句B;
解释:if默认只能控制语句A的执行或不执行
if无法控制语句B的执行或不执行(语句B是一定执行的)
if (表达式)
{
语句A;
语句B;
}
此时if可以控制语句A和语句B
由此可见:if默认只能控制一个语句的执行或者不执行,如果想控制多个语句的执行或者不执行就必须把这些语句用{}括起来
if…else…的用法
if…else if…else…的用法
格式:
if (1)
A;
else if (2)
B;
else if (3)
C;
else
D;
C语言对真假的处理
非零是真
零就是假
真用1表示
假用零表示
if举例–求分数的等级
if的常见问题解析
空语句的问题
if (3>2);
等价于
if (3>2)
;
;问题
if (表达式1)
A;
else
B;
正确
if (表达式1);
A;
else
B;
错误
执行顺序
if (表达式1)
A;
else if (表达式2)
B;
else if (表达式3)
C;
else
D;
即使表达式1和2都成立,也只执行A
缺少else
if (表达式1)
A;
else if (表达式2)
B;
else if (表达式3)
C;
这样写语法不会有错误,但逻辑有漏洞
else没有表达式
if (表达式1)
A;
else if (表达式2)
B;
else if (表达式3)
C;
else (表达式)
D;
else没有表达式错误
switch
switch (语句)
{
case 判断1: 语句1; break; // 如果只有一条语句,可以不加{},默认break属于上一条case
case 判断2: 语句2; break;
default: 语句; break; // 可省略
}
循环执行
定义:某些代码会被重复执行
分类:
for
for (1;2;3)
语句A;
执行的流程【重点】:1->2->A->3->2->A->3->2
范围问题
强制类型转换 (float)(i)
格式:(数据类型)(表达式)
功能:把表达式的值强制转化为前面所执行的数据类型
浮点数的存储所带来的问题
float和double都不能保证可以精确的存储一个小数
循环中更新的变量不能定义成浮点型:浮点型非准确存储
例如:
float i=99.9
printf(“%f\n”, i);
输出结果:99.900002
因为浮点数无法准确存储,所以就衍生出来两个编程问题
有一个浮点型变量x,如何判断x的值是否是零
if(|x-0.000001|<=0.000001)
是零
else
不是零
while
执行顺序
格式
while(表达式)
语句;
与for的相互比较
for和while可以相互转换
for (1;2;3)
A;
等价于
1;
while(2)
{
A;
3;
}
举例
回文数 121 323 正着写和倒着写一样
什么时候使用while,什么时候使用for
do while
格式:
do
{
。。。。
} while(表达式);
至少执行一次,但是while不一定一定执行一次
主要用于人机交互
自增[自减]
分类:
相同:最终都使i的值加1
不同
优点:代码更精炼,自增的速度更快
编程时注意:
三目运算符
A ?B:C
等价于
if (A)
B;
else
C;
逗号表达式
格式:(A, B, C, D)
功能:从左到右执行
printf(“格式运算符,格式运算符,格式运算符,格式运算符”, A, B, C, D);
从右向左入栈,输出从左向右出栈
break
break 如果用于循环是用来终止循环
break 如果用于switch,则是用来终止switch
break 不能直接用于if,除非if属于循环内部的一个子句
在多层循环中,break只能终止距离它最近的那个循环
在多层switch嵌套中,break只能终止距离它最近的switch
continue
continue用于跳过本次循环余下的语句,转去判断是否需要执行下次循环
为什么需要函数
什么叫函数
如何定义函数
函数的返回值 函数的名字(函数的形参列表)
{
函数的执行体
}
函数的分类
有参函数和无参函数
有返回值和无返回值
库函数和用户自定义函数
值传递函数和地址传递函数
普通函数和主函数(main函数)
一个程序必须有且只有一个主函数
主函数可以调用普通函数,普通函数不能调用主函数
普通函数可以相互调用
主函数是程序的入口,也是程序的出口
注意的问题
常用的系统函数
专题:递归
为什么需要数组
为了解决大量同类型数据的存储和使用问题
为了模拟现实世界
数组的分类
一维数组
怎样定义一维数组
有关一维数组的操作
初始化
完全初始化
int a[5]={1,2,3,4,5};
不完全初始化,为被初始化的元素自动为零
int a[5]={1,2,3};
不初始化,所有元素是垃圾值
int a[5];
清零
int a[5]={0};
错误写法
int a[5];
a[5] = {1,2,3,4,5};// 错误
只有在定义数组的同时才可以整体赋值,其他情况下整体赋值都是错误的
a[5] = 100; // 错误,没有a[5]
int a[5]={1,2,3,4,5}
int b[5];
如果要把a数组中的值全部复制给b数组
b = a; // 错误
正确写法
for(int i=0; i<5;i++)
b[i] = a[i]
赋值
排序
求最大值、最小值
倒置
查找
插入
删除
二维数组
int a[3][4]总共12个元素,可以当成3行4列看待,这12个元素的名字依次是
a[0][0] a[0][1] a[0][2] a[0][3]
a[1][0] a[1][1] a[1][2] a[1][3]
a[2][0] a[2][1] a[2][2] a[2][3]
a[i][j]表示第i+1行,第j+1列的元素
int a[m][n]; 该二维数组右下角的元素位置只能是a[m-1][n-1]
初始化
int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
int a[3][4]={
{1,2,3,4},
{5,6,7,8},
{9,10,11,12}
};
输出二维数组内容:
for (i=0; i<3; i++)
{
for (j=0; j<4; j++)
printf("%-5d ", a\[i][j]);
printf("\n");
}
多维数组
是否存在多维数组:
不存在,因为内存是线性一维的,n维数组可以当做每个元素是n-1维数组的一维数组
比如:int a[3][4]; 该数组是含有3个元素的一维数组,只不过每个元素都可以再分成4个小元素
int a[3][4][5]; 该数组是含有3个元素的一维数组,只不过每个元素都是4行5列的二维数组
指针的重要性
表示一些复杂的数据结构
快速的传递数据,减少了内存的消耗
使函数返回一个以上的值
能直接访问硬件
能够方便的处理字符串
是理解面向对象语言中引用的基础
总结:指针是C语言的灵魂
指针的定义
指针的分类
基本类型指针
int * p; // 定义p为指针变量
int i=3;
p = &i; //把i的地址赋给p
*p // 表示i,以p的内容为地址的变量
*的含义:
如何通过被调函数修改主调函数普通变量的值
*形参名 = 。。。
的方式就可以修改主调函数相关变量的值指针和数组
指针和一维数组
数组名
一维数组名a
下标和指针的关系
如果p是个指针变量,则p[i]永远等价于 *(p+i)
确定一个一维数组需要几个参数【如果一个函数要处理一个一维数组,则需要接受该数组的哪些信息】
需要两个参数:
指针变量的运算
指针变量不能相加,不能相乘,也不能相除
如果两个指针变量指向的是同一块连续空间中的不同存储单元,则这两个指针变量才可以相减
一个指针变量到底占几个字节
sizeof(数据类型/变量名)
假设p指向char类型变量(1个字节)
假设q指向int类型变量(4个节字)
假设r指向double类型变量(8个字节)
p、q、r本身所占的字节数一样,都占4个字节。—4字节=32位,32根线控制地址,2的32次方组合结果,使用4个字节可以完全保存地址总线
总结:
指针和二维数组
指针和函数
指针和结构体
多级指针
int i = 10;
int *p = &i;
int **q = &p;
int ***r = &q;
分类:
注意的问题:
全局变量和局部变量命名冲突的问题
在一个函数内部如果定义的局部变量的名字和全局变量名字一样时,局部变量会屏蔽掉全局变量
动态内存分配
传统数组的缺点:
数组长度必须事先制定,且只能是常整数,不能是变量
例子:int a[5];正确
int len = 5; int a[len]; //error
传统形式定义的数组,该数组的内存程序员无法手动释放
在一个函数运行期间,系统为该函数中数组所分配的空间会一直存在,直到该函数运行完毕时,数组的空间才会释放
数组的长度一旦定义,其长度就不能在更改
数组的长度不能在函数运行的过程中动态的扩充或缩小
A函数定义的数组,在A函数运行期间可以被其它函数使用,但A函数运行完毕之后,A函数中的数组将无法在被其他函数使用
为什么需要动态分配内存
动态数组很好的解决了传统数组的这4个缺陷
传统数组也叫静态数组
malloc 是 memory(内存) allocate(分配)
动态内存分配举例——动态数组的构造
要使用malloc函数,必须添加malloc.h这个头文件
malloc函数只有一个形参,并且形参是整型
整数表示请求系统为本程序分配字节数
malloc函数只能返回第一个字节的地址
int *p = (int *)malloc(4);
分配了8个字节,p变量占4个字节,p所指的内存也占4个字节
p本身所占的内存是静态分配的,p所指向的内存是动态分配的
free(p)表示把p所指向的内存给释放掉,p本身的内存是静态的,不能由程序员手动释放,p本身的内存只能在p变量所在的函数运行终止时由系统自动释放
静态内存和动态内存的比较
跨函数使用内存的问题
结构体
为什么需要结构体
声明叫结构体
如何定义一个结构体
3种方式(推荐使用第一种)
// 第一种方式
struct Student
{
int age;
float score;
char sex;
};
// 第二种方式
struct Student
{
int age;
float score;
char sex;
} st2; // 只能定义一次
// 第三种方式
struct
{
int age;
float score;
char sex;
} st3;
怎样使用结构体变量
赋值和初始化
定义的同时可以整体赋初值
如果定义完之后,则只能单个的赋初值
struct Student st = {80, 66.6, 'f'}; //初始化,定义的同时赋初值
struct Student st2;
st2.age = 10;
st2.score = 88;
st2.sex = 'f';
如何取出结构体变量中的每一个成员
结构体变量名.成员名
st.age;
st.score;
st.sex;
指针变量名->成员名
指针变量名->成员名 在计算机内部会被转化成(*指针变量名).成员名的方式来执行
所以说这两种方式是等价的
struct Student *pst = &st;
pst->age = 88;
pst->score = 66.6;
pst->sex = 'f';
pst->age在计算机内部会被转化为(*pst).age
结构体变量的运算
结构体变量不能相加,不能相减,也不能相互乘除,但结构体变量可以相互赋值
结构体变量和结构体变量指针作为函数参数传递的问题
推荐使用结构体指针变量作为函数参数来传递
举例:动态构造存放学生信息的结构体数组
动态构造一个数组,存放学生的信息,然后按分数排序输出
枚举:
什么是枚举
把一个事物所有可能的取值一一列举出来
怎样使用枚举
枚举的优缺点
代码更安全
书写麻烦
进制:
补码:
原码:
反码
移码
补码
十进制转二进制
正整数转二进制
除2取余,直至商为零,余数倒序排序
负整数转二进制
先求与该负数相对应的正整数的二进制代码,然后将所有位取反,末尾加1,不够位数时,左边补一
零转二进制
全是零
已知二进制求十进制
二进制全部为零的含义:0000000000000000000的含义
数值0
字符串结束标记符‘\0’
空指针NULL
NULL本质也是零,而这个零不代表数字零,而表示的是内存单元的编号零
我们计算机规定了,以零为编号的存储单元的内容不可读,不可写
int类型的变量所能存储的数字的范围是:
链表:
算法:
通俗定义
解题的方法和步骤
狭义定义
对存储数据的操作
对不同的存储结构,要完成某一个功能所执行的操作是不一样的
比如:
要输出数组中所有的元素的操作和要输出链表中所有元素的操作肯定是不一样的
这说明:算法是依附于存储结构的,不同的存储结构,所执行的算法是不一样的
广义定义
广义的算法也叫泛型
无论数据是如何存储的,对该数据的操作都是一样的
我们至少可以通过两种结构来存储数据
数组
优点
存储速度很快
缺点
需要一个连续的很大的内存
插入和删除元素的效率很低
链表
专业术语
首节点
尾节点
头结点:
头指针
确定一个链表需要一个参数
优点
插入删除元素效率高
不需要一个连续的很大的内存
缺点
查找某个位置的元素效率低
位运算符:
&:按位与;&&逻辑与,也叫并且,&&与&的含义完全不同
|:按位或,||逻辑或
~:按位取反
^:按位异或,相同为零,不同为1
<<:按位左移,右边补零:左移n位相当于乘以2的n次方(前提是数据不能溢出)
面试题:
i = i*8;
i = i<<3; ------------快
请问上述两个语句,哪个语句执行的速度快
>>:按位右移,左边一般补零(也可以补1);右移n位相当于除以2的n次方(前提是数据不能溢出)
通过位运算符可以对数据的操作精确到每一位
3. 空指针NULL
NULL本质也是零,而这个零不代表数字零,而表示的是内存单元的编号零
我们计算机规定了,以零为编号的存储单元的内容不可读,不可写
int类型的变量所能存储的数字的范围是:
链表:
算法:
通俗定义
解题的方法和步骤
狭义定义
对存储数据的操作
对不同的存储结构,要完成某一个功能所执行的操作是不一样的
比如:
要输出数组中所有的元素的操作和要输出链表中所有元素的操作肯定是不一样的
这说明:算法是依附于存储结构的,不同的存储结构,所执行的算法是不一样的
广义定义
广义的算法也叫泛型
无论数据是如何存储的,对该数据的操作都是一样的
我们至少可以通过两种结构来存储数据
数组
优点
存储速度很快
缺点
需要一个连续的很大的内存
插入和删除元素的效率很低
链表
专业术语
首节点
尾节点
头结点:
头指针
确定一个链表需要一个参数
优点
插入删除元素效率高
不需要一个连续的很大的内存
缺点
查找某个位置的元素效率低
位运算符:
&:按位与;&&逻辑与,也叫并且,&&与&的含义完全不同
|:按位或,||逻辑或
~:按位取反
^:按位异或,相同为零,不同为1
<<:按位左移,右边补零:左移n位相当于乘以2的n次方(前提是数据不能溢出)
面试题:
i = i*8;
i = i<<3; ------------快
请问上述两个语句,哪个语句执行的速度快
>>:按位右移,左边一般补零(也可以补1);右移n位相当于除以2的n次方(前提是数据不能溢出)
通过位运算符可以对数据的操作精确到每一位