目录
数组(方便起大量同类型数据储存使用,模拟现实世界)... 20
基础
C语言的基本单位是函数
文件后缀必须是.c or .cpp才能运行
规范写代码:
让别人看懂,不容易出错,
开头格式
/*
写程序时间:
功能:
目的:
*/
结尾格式:
/*输出结果是:
——————————————
(输出结果)
——————————————
总结(时间:)
*/
看程序
一步一步去写
看流程
试数
int整型
float单精度类型
double(可以存的小数更多)
#include<文件名>(stdio.h/math.h/…)sqrt开方在后面那个文件里面,
printf输出
if/else if
=赋值
==等于
Delta
程序假死按shift.ctrl,alt关闭程序
单行注释//
多行注释/*
*/
关闭程序点close workspace
.close不是完全关闭
Ctrl+S保存(*表示没保存)
CPU中央处理器
视频储存在硬盘上,点击调入内存条,CPU进行处理,图像通过显卡输出
主板是一个载体矩形电路板
HelloWorld运行开头# include < stdio.h >
编译,链接形成可执行exe.程序,
操作系统(CPU)执行
编译链接产生的中间文件可删,只需要留源文件(C++Source file)
基本类型数据
一字节是8位
常数(不会变的数)
浮点数(实数)//不能准确存储
单精度浮点数—float(4个字节)
双精度浮点数—double(8个字节)
传统写法
float x = 3.2
科学计数法
float x = 3.2e3;//x的值是 3200
float x = 123.45e-2; // x 的值是1.2345
E是移动小数点,e后面的数是正数向右移,负数左移小数点
整数
整形—int 4个字节(int x =10,表示x变量为整形变量,指x只能存放整数)
短整型—short 2个字节。
long4个字节,在64位中8个字节.
长整形—long long 8个字节
字符
单精度字符
单个字符用单引号’A’
字符串用双引号“AB”
初始化就是赋值,防止有残留数据
定义变量
数据类型 变量名 =要赋的值;
等价于
数据类型 变量名;
变量名 = 要赋的值
举例子:
int i = 2;等价于int i ;i = 2;
int I = 4,j = 5;等价于 int i,j ;I = 4 , j = 5
进制
进制即逢几进一
C语言八进制前加0,十六进制前加0x
汇编中:二进制数字后B(1011B),八进制O(1367O) ,十进制D,十六进制H
二进制;0,1,10,11,100,101,110,1000
十六进制0,1,2,3,4,5,6,7,8,9,a,b.c,d,e,f
Int I = 10(表示的只是一个二进制代码而不是10,必须以以下方式输出才能表示一个数)
%d表示以十进制输出
%x表示以十六进制输出
%o表示以八进制输出
进制转换
例子十六转十
32C = 3*16的平方+2*16+12
10进制转n进制
用n除取余,先余为低后余为高。
字节
字节是存储数据的单位,,并且是硬件所能访问的最小单位
CPU只能控制字节
1字节B = 8位b(一个0,或1就是一位)
1K B= 1024字节
1M = 1024k
1G = 1024M
1024 = 2 的10次方
(厂商计算1k = 1000字节)
ASCII(阿斯克码)
不能把字符串(“AB”)付给单个字符
不能把一个字符定义多次(char ch = A;
char ch = B)
但可以把一个字符多次赋值(char ch = A;
ch = B)
ASCLL不是一个值,而是一种规定,它规定了不同的字符是使用哪个整数值去表示
它规定了
‘A’ – 65
‘B’ – 66
‘a’ – 97
‘b’ – 98
‘0’ -- 48
……
基本的输入输出函数的用法
输入输出
printf()将变量的内容输出到显示器上
四种用法
1.printf(“字符串\n”)\n表示换行
2.printf “(输出控制符”,输出参数);
3.printf (“输出控制符1 输出控制符2”, 输出参数1 ,输出参数2,输出控制符 鹤输出参数的个数必须一一对应)
4.%开头的是输出控制符,%d,int输出(10进制)
, %ld,long long输出
%c char 输出
%f float输出
%lf double输出
%x{或者%X,(输出符号大小写不一样)%#x(输出数字前有0x表示十六进制输出。)}
非输出控制符:如\n
int j = 3;
int k = 4;
printf(“%d %d\n” , j ,k )%d让3的二进制代码以十进制输出
输出控制符
01组成的代码可以表示数据也可以表示指令
如果01组成的代码表示数据的话,那么同样的01代码组合以不同的输出格式输出就会有不同的输出结果。
scanf ()[通过键盘将数据输入到变量中]
scanf(“输入控制符”,输入参数);
功能:将从键盘输入符字符转换为输入控制符所规定格式的数据,然后存入以输入参数的值为地址(&a//表示i的地址,&是一个取地址符)的变量中。
scanf(“%d\n”,&i);(如果%前面加东西,用户输入就必须先打%前的规定东西再打用户自己想输入的东西,否则printf运行不出来)
printf(“i = %d\n”,i);
一次给多个变量赋值与printf一样。每个变量之前都要加&号
运行输入时要输多个(数字不能连着写,之间的非输入控制符要原样的输入[如逗号]
写scanf之前,最好在前面加一个提示信息(printf(“请输入。。。”);提示用户以什么样的形式来输入。
scanf中间不要加非输入控制符如\n
while是循环的意思
应该编写代码对用户的非法输入作适当的处理
char ch ;
while((ch = getchar()) ! = ‘ \n ’);
continuo;
运算符
算数>关系>逻辑>赋值
算数运算符
+ - * / %(取余数)
关系运算符
> >= < <= !=(不等于) ==(等于)
逻辑运算符
!(非) &&(并且) ||(或者)
!真 假
!假 真
真&&真 真
真&&假 假
假&&真 假
假&&假 假
(只要一个假就是假)
真||假 真
(与&&相反,只要一个真就是真)
C语言对真假的处理
非零都是真(int m = 10;
(m =9)是真)
零都是假
1表示真
0表示假
若&&前的表达式是假,那么后面的表达式就不执行了
若||前面的表达式是真,后面的表达式不执行。
If(score > 100)
printf(“这是做梦”);
If (score >= 90 && score <= 100)//不能写90 <= score <= 100, 前半部分是真结果为1,前半部分是假结果为0,但后半部分都成立
printf(“优秀”);
else
printf(“其他”);
不含有分号的是表达式,含有分号的是语句
赋值运算符
= += *= /= -=(a+=3是a=a+3)
除法的运算结果与运算对象的数据类型有关,两个数都是int,则商就是int,若商有小数部分,则截去小数部分;被除数和除数只要有一个是浮点数据类型,则商也是浮点型,不截去小数部分。
取余%的运算对象必须是整数,结果是整除后的余数,其余数符号与被除数相同。
若忘了运算符的级别顺序,可以用()括起来
位运算符
按位与&、或|、异或^、取反~
流程控制(程序代码执行的顺序)
1.流程控制的分类
顺序执行
从上到下
选择执行
有选择的执行某些代码(可能执行也可能不执行)
If
If最简单的用法
格式:
If( 表达式 ) //不用加分号
语句//真输出,假不输出
表达式不带分号,语句是带分号的。
If范围的问题
1. If(表达式)
语句A
语句B
If只控制语句A
2. if(表达式)
{
语句A
语句B
}
If控制AB
If默认控制一个语句,如果想输出两个语句就用大括号括起来
if(如果) …else(否则)的用法
Else与if的控制范围相同
if()
printf(“”);
else //else 后面不加东西。
printf(“”);
整体是一个语句(因为只执行一个语句)
If … else if…else…(从上往下执行)
switch
循环执行
空语句:直接打;
互换两个数字:
定义一个容器用来互换
int I = 2;
int j = 3;
int t;
t = I;
I = j;
j = t;//I, j,互换变量。
可以用这个输入多个整数,把这几个整数按照从大到小(从小到大)输出;
(用if判断,把最大的值换给a)
自增自减
前自增++i
后自增i++
比较
相同:最终都使i的值加一
不同:++i先加再运算 ,i++先运算再加。
最好不要作为一个完整复合句的一部分用,应单独成一个语句。
不要用他们之间的差异
在for内无区别。
三目运算符
A?B:C
if(A)
B;
Else
C;
逗号表达式
格式
A, B, C, D
功能
从左到右执行
最终表达式的值是最后一项的值
Int j = 2;
I = (j++,++j,j+2,j - 3)= 1
For循环
一个for控制一个句子
Int i;
Int sum = 0;
For(i = 原始值(a);I <10(b); i++(c))//for循环里的i++和++i是一个意思
{
Sum+= i;(d)
}
Printf(“%d”,sum);
//一个循环的顺序是a,b,d,c。for()内语句用分号;分割。
强制类型转化
格式:
(数据类型)(一个值)强制转化
功能:
把表达式的值强制转化为前面所执行的数据类型
例子:
(int)(4.5+2.2 最终值是6
(float)(5) 最终值是5.000000
程序
1/1+1/2+1/3+…+1/100
#include<stdio.h>
int main(void)
{
double sum = 0;
int i;
for(i = 1; i <= 100; ++i)
{
sum += 1/(float)(i);/*不能写1/i,因为i是整数1/2,1/3结果都是0,
除法int型结果也是int型,有一个是浮点型结果就是浮点型
此时i前面加(float)强制类型转换,
不能写(float)(1/i),否则结果把0,转换成0.00000,
所以要写1/(float)(i)
或者写成
(1.0)/(i)*/
}
printf("%lf", sum);
return 0;
}
For循环的嵌套使用(自己尝试,主要是找到循环的顺序)
输出%的方法是%%
While循环
执行的顺序
格式:
While(表达式)
语句;
与for的相互比较
for(I = 1,i<101;++i)
sum = sum + i
i = 0
while(i<101)
{
sum = sum + 1;
++i
}
While与for之间可以相互转换
do …while格式(多用于人机交互)
do
{
……
}while(表达式)
do…while并不等价于for或while。
例:
一元二次方程
#include<stdio.h>
#include<math.h>
Int main()
{
double a, b, c;
double delta;
double x1, x2;
do
printf(“b = ”);
scanf(“%lf”,&b);
printf(“c = ”);
scanf(“%lf”,&c);
delta = b*b – 4*a*c;
if(delta > 0)
{
x1 = ( (- b) + sqrt(delta))/(2*a);
x2 = ( (- b) - sqrt(delta))/(2*a);
printf("该一元二次方程有两个解\nx1 = %.2lf\nx2 = %.2lf\n",x1,x2);
}
else if(delta == 0)
{
x1 = x2 = ( (- b) + sqrt(delta))/(2*a);
printf("该一元二次方程有两个相同的解x1 = x2 = %.2lf\n",x1);
}
else if(delta < 0)
{
printf("无解");
} while(1)
return 0;
}//一次只能求一个值
Switch
Int i;
printf(“请输入你想到达的楼层”);
scanf(“%d”,&i);
switch(i)
{
case 1://i等于1时
printf("一层”);
break; //跳出,没有break就会一直往下执行
case 2:
printf(“二层”);
break;
default: //默认相当于else
printf(“没有此层”);
}
数组(方便起大量同类型数据储存使用,模拟现实世界)
Int a[5] = {1, 2, 3, 4, 5}
//a[0]=1, a[1]=2…… a[4]=5
a,是名字,有5个数
一维数组
数组内的元素连续分配储存空间
所有变量数据类型必须相同
所有变量所占字节大小必须相等
关于一维数组的操作
初始化
完全初始化
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};//错误,只有在定义数组的同时才可以整体赋值,其他情况下整体赋值都是错误的。这5是下标,且没有a[5]这个元素,最大只有a[4]
把a数组中的值全部复制给b数组
Int a[5] = {1,2,3,4,5}
B[5]
For(int i=0;i<5;i++)
B[i] = a[i];
//不能写成b = a,a,b,代表的是数组首元素的地址;
赋值
Scanf(“%d”, &a[0]);
倒置
Int a[5] = {1,2,3,4,5}
Int I,j;
Int t;
I=0;
j=4;
While(i<j)
{
t = a[i];
A[i] = a[j];
A[j] = t;
I++;
--j;
}
For(i=0;i<5;i++)
Printf(“%d”,a[i]);
二维数组的使用
二维数组Int a[8][6]//48个数(8行六列),三维同理
A[3][4];
A[0][0], a[0][1], a[0][2], a[0][3], a[0][4]
A[1][0], a[1][1], a[1][2]……
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}
Or
Int a[3][4] = {
{1, 2, 3, 4},
{5 ,6, 7, 8},
{9, 10, 11, 12}
};
输出二维数组内容
For(int i=0;i<3;++i)
{
For(int j=0;j<4;j++)
Printf(“%d”,A[i][j]);
Printf(“\n”);
}
对二维数组排序;
求每一行的最大值;
判断矩阵是否对称;
矩阵相乘;
不存在多维数组
因为内存是线性一维的;
N维数组可以当作每个元素是n-1维数组的一维数组
//int a【2】【3】
该数组是含有2个元素的一维数组
只不过每个元素都可以再分成3个小元素
函数(能够完成特定功能的独立的代码块)
简单介绍
能够接收数据(也可以不接收int fun(void))
能够对接收的数据进行处理
能将处理的数据返回(也可以不返回void fun(int j))
为相似大量同类型的问题使用,避免重复性操作,有利于程序的模块化。
所有的语言都先执行main函数,从main函数进入、退出
函数可以当一个黑箱(工具)
函数名自己定
例:
Void max(int I, int j)//函数前的void表示函数内部不能有返回值,主函数不能有int t=max(a,b)的语句,max是函数的名字,i,j是形式参数;
{
If(i>j)
Printf(“%d\n”, i);
Else
Printf(“%d\n”,j);
}
Int main()
{
int a, b;
A = 1;
B = 3;
Max(a,b);//使用上方的max函数a给i,b给j,max使用完毕再跳回main函数时,i,j所占的内存空间就释放掉了,下次再使用i,j所占的空间就不一定与上次相同了。
Return 0;
}
例
#include<stdio.h>
Int f(void)//void表示该函数不能接收数据,int表示函数返回值是int类的
{
return 10;//向主调函数返回10
}
int main()
{
Int j = 88;
J = f();//f()内部不能加值,
Printf(“%d”,j);//输出j=10
}
如何定义函数
函数的返回值 函数的名字(函数的形参)
{
函数的执行体
}
- 函数定义的本质是详细描述函数之所以能够实现某个特定功能的具体方法
- return表达式的含义:
- 终止被调函数,向主调函数返回表达式的值
- 如果表达式为空, 则只终止函数,不向主掉函数返回任何值
3.函数返回值的类型,也成为函数的类型,因为如果 函数返回值类型与函数定义类型冲突时,以函数定义类型为准
int f()
{
return 10.5//f()的结果是10
}
函数的分类
1.函数分为有参函数和无参函数
无参:调用该函数时无需传入数据,格式:类型名 函数名(void)
有参:调用该函数时需要传入数据,格式:类型名 函数名(形参)
2.有返回值和无返回值
- 库函数和自定义
- 普通函数 和 主函数(main函数)
一个程序必须有且仅有一个主函数
主函数可以调用普通函数 普通函数不能调用主函数
普通函数可以相互调用
主函数是程序的入口也是程序的出口
函数举例
int max(int i,int j)
{
if(i>j)
return i;
else
return j;
}//这样写将i,j返回给主函数,在主函数里自己处理
判断一个数是否为素数
用它自己除2~它自己的数,如果都不能被整除,那么它就是素数
常用的系统函数:
double sqrt(double x) 求x的平方根
int abs(int x)求x的绝对值
double fabs(double x)求x的绝对值
Pow(a,b)a 的b次方
Ceil()向上取整,1.2取2.
%03d,表示:打印一个整数,整数的长度不足3位前面会用0补足3位。
比如
printf("%03d",30),显示030。
printf("%03d",3000),显示3000。
递归
栈:储存先进后出
函数自己调用自己
变量的作用域和存储方式:
按作用域分:
全局变量:在所有函数之外的地方定义的变量,从定义它的下面的所有函数都可以使用。
局部变量:在函数内部定义的变量或函数的形参 都是局部变量,只能在定义的函数内部使用;
局部变量不初始化,则会有垃圾值。
一个变量不能在它的作用域内被定义多次。
指针
介绍
用来存放地址, 指针也有自己的地址。
Int * p//指针变量p是变量的名字,int * 表示p变量存放的是int类型变量的地址(&i)。
Int i = 3;
p = &i;/*
- p保存了i的地址,因此p指向i。
- 修改p的值不影响i的值,修改i的值也不影响p的值。
- 如果一个指针变量指向了某个普通变量,则*指针变量 完全等于 普通变量。(*p = i)(*p不是p)
- *指针运算符,*是&取地址的逆运算(取所在地址的数值)。
*/
p = i;//错误,因为p只能存放int类型变量的地址,不能存放int类型变量的值。
指针的重要性:
表示一些复杂的数据结构
快速的传递数据
使函数返回一个以上的值
能直接访问硬件
能够方便的处理字符串
是理解面向对象语言中引用的基础
指针的定义
地址
内存单元的编号
从0开始的非负整数
指针:
指针就是地址,地址就是指针。
指针变量是存放地址的变量
指针和指针变量是两个不同的概念
但是我们叙述是会把指针变量简称为指针,实际他们的含义不一样
指针的本质就是一个操作受限的非负整数。(指针不能相加乘除,但是可以相减!)
Int*p;
Int**pp = &p;//二级指针存放指针的地址;
常见错误:
int * q;
Int * p;
*q = p//int = int *语法编译报错,*是间接运算符(解引用)
*q = *p//*p没赋值
P = q//q内是垃圾值,q付给p,p也变成垃圾值
Printf(“%d”,*q)/*
q内是垃圾值,*q不能被本程序读写。
因为此时*q代表的内存单元的控制权限没有分配给本程序。
*/
野指针:(悬挂指针)没有访问权限的指针(地址),这个地址可能不存在
NULL:空指针,明确表示当前是无效指针
父函数调用子函数,想通过子函数修改父函数变量的值(实参),(即形参的改变能影响实参),传指针,解引用。
指针大小(与指针类型无关):
一个字节8位:
X86:32位平台,指针占4字节;
X64/arm64:64位平台,指针占8个字节
Inter(英特尔)(电脑用):复杂指令集,功能强、价格贵、功耗大(发热)
Arm(手机、嵌入式用):精简指令集,便宜,功耗低;
指针的分类
基本类型的指针
指针和数组
指针和函数
指针和结构体
经典指针程序,互换两个数字
void swap(int * a, int * b)
{
int t;
t = *a;
*a = *b;
*b = t;
return;
}
int main()
{
Int a=3, b=5;
Printf(“%d %d”,swap(&a, &b))
}
字符串不用传长度:有\0;
星号的三种含义
- 乘法
- 定义指针变量int * p;
- 间接运算符,放在已经定义好的指针变量前面,&的逆运算符。
*p表示以p的内容为地址的变量。
如何通过被调函数修改主调函数普通变量的值
- 形参必须是指针变量
- 实参必须是普通变量的地址
- 在被调函数中通过
*形参名 = ……
的方式就可以修改主调函数相关变量的值。
数组和指针
指针和一维数组
一维数组名
一位数组名是个指针常量;
它存放的是第一个元素的地址;
输出地址用%p或者%#x;
下标和指针的关系
如果p是个指针变量,则p[i]永远等价于*(p+i)
确定一个一维数组需要哪些参数【如果一个函数要处理一个一维数组,则需要接收该数组的哪些信息】
Void F(int * pa,int lenth)//数组名,数组长度
{
Int i;
For(I = 0;i<lenth;i++)
{
printf(“%d”, *(pa));
}
Int main();
{
Int a[3] = {2,3,4};
F(a, 3)//a是 int *;
}
指针变量的运算
指针变量不能相加、乘、除
如果两个指针变量指向的是同一块连续空间中的不同存储单元,这两个指针变量才能相减。
问:一个指针变量占几个字节:
sizeof(数据类型or变量名)
功能:返回值就是该数据类型/变量名所占的字节数
例子:sizeof(int) = 4;
一个字节一个编号,八位一个字节。
假设p指向char类型变量(1个字节)
Q指向int类型变量(4个字节)
R指向double类型变量(8个字节)
Pqr本身所占的字节是否相同:相同
专题:
动态内存分配
传统数组的缺点:
1.数组长度必须事先指定,且只能是常整数,不能是变量:
例子:
Int a [5];//ok
Int len = 5,int a[len];//error
2.传统形式定义的数组,该数组的内存程序员无法手动释放。
在一个函数运行期间,系统为该函数中数组所分配的空间会
一直存在,直到该函数运行完毕时,数组的空间才会被释放
3.数组的长度一旦定义,其长度不能再改变
数组的长度不能在函数运行的过程中动态的扩充或缩小。
4.传统方式定义的数组不能跨函数使用,A函数定义的数组,在A函数运行期间可以被其他函数,但是A函数运行完毕后,A函数中的数组将无法再被其他函数使用。
为什么需要动态分配内存
动态数组很好符解决了传统数组的4个缺陷
传统数组也叫静态数组
动态内存分配举例——动态数组的构造
#include<malloc.h>
int *p;
int len;
scanf(“%d”,&len);
P = (int *)malloc(4*len);//相当于int p[len];
Free(p);//释放掉动态分配的数组;
静态内存和动态内存的比较
跨函数使用内存的问题
结构体
结构体:
把一些基本类型组合到一起形成新的复合数据类型叫~
定义结构体
3种方式:(最好用第一种)
第一种:
第二种:
因为定义了变量名,所以只能定义一次,不能再次使用
第三种:
使用结构体变量
赋值与初始化
1.边定义边赋值
2.先定义再赋值,内容只能一个一个赋值
如何取出结构体变量中的每一个成员
p->age的含义:p所指向的那个结构体变量中age这个成员。
结构体变量和结构体指针变量作为函数参数传递的问题
举例
动态结构存放学生信息的结构体数组
结构体变量的运算
结构体变量不能加减乘除但能相互赋值。
链表
算法:
通俗定义:
解题的方法和步骤
狭义定义:
对存储数据的操作
广义定义:
泛型。
无论数据如何存储的,对该数组的操作都是一样的
我们至少可以通过两种结构来存储数据
数组
优点:存取速度快
缺点:需要一个连续的很大的内存;插入和删除元素的效率很低
链表(确定一个链表只需要一个参数)
专业术语:
头结点:
头结点的数据类型和首节点的类型是一模一样的
头结点是首节点前面的那个节点
头结点并不存放有效数据
设置头结点的目的是为了方便对链表的操作
头指针:
存放头结点地址的指针变量
首节点
存放第一个有效数据的节点
尾节点:
存放最后一个有效数据的节点
一个元素分为两个部分,前面是数据,后面是指针,指向下一个数据;
优点:用指针指向下一个元素,不用连续的内存,插入和删除元素容易
缺点:取出某一个元素的效率低,不知道那个地址在哪(不连续,只能通过上一个元素的指针一个一个找)
清屏:system(“cls”),头文件stdlib.h
息屏:Sleep(),头文件windows.h
cout.width() 设置输出占宽度
A.size()A数组的宽度(输入多少就多宽)
_getch()输入不用回车自动运行;(如char input = getch())头文件:conio.h