1.0表示正常,-1表示异常 换行\n 排版代码键位“alt
F8”
2.变量的本质就是内存中一段存储空间。变量的初始化就是变量的赋值。
3.释放不是清空,而是把使用权限分配给其他程序。用填充数字来提醒没有初始化。
4.定义变量:数据类型 变量名=要赋的值(数据类型 变量名 变量名=要赋的值)程序=算法+语言
5.八进制前加0,十六进制前加0X。字母A-F表示十六进制。在汇编中:在数字后加B表示二进制,加O表示八进制,加D表示十进制,加H表示十六进制。4
%X或%x或%#X表示以十六进制输出;%O表示以八进制输出。
6.单个字符用单引号表示,字符串用双引号表示。浮点数可以用传统写法和科学计数法。“A”正确,表示了‘A’和‘\0’的组合。
7.整数是以补码的形式转化为二进制代码存储;实数是以IEEE754标准转化为二进制代码存储;字符的本质实际也是与整数存储方式相同。
8.字节就是存储数据的单位,并且是硬件所能访问的最小单位。一个字节=8位(比特);1K=1024字节
9.%c输出字母,%f输出小数。ASCII不是一个值,而是一种规定,规定了不同的字符是用哪个整数值去表示。
10.scanf()输入函数,printf()输出函数
printf()输出函数的四种用法:
①printf("字符串");
②printf(“输出控制符”,输出参数);
③printf(“输出控制符1 输出控制符2。。。”,输出参数1,输出参数2。。。);输出控制符与输出参数的个数必须一一对应。
④printf("输出控制符 非输出控制符",输出参数);
输出控制符包括:%d,%ld,%f,%lf,%c,%x,%X,%#x,%#X(推荐使用),%O,%S
scanf()输入函数的两种用法:
①scanf(“输入控制符”,&输入参数);
②scanf(“非输入控制符 输入控制符”,&输入参数);非输入控制符必须原样输入。
while((ch=getchar())!='\n')
continue;
11.%取余数(算数运算符)!=不等于(关系运算符)==等于 逻辑运算符:!(非)&&(并且)||(或)算数>关系>逻辑> 赋值
除法的运算结果和运算对象的数据类型有关,两个数都是int,则商就是int,没有小数部分;被除数和除数中只要有一个或两个都是浮点型数据,商也是浮点型,有小数部分。取余的运算对象必须是整数,结果是余数,取余数的符号与被除数相同。
真&&假:假 假&&真:假 真||假:真 假||真:真
&&左边的表达式是假,右边的表达式肯定不会执行。
||左边的表达式是真,右边的表达式肯定不会执行。
+=2(i=i+2)
自增:前自增++i
后自增i++
异同:都使i的值加1;前自增整体表达式的值是i+1之后的值,后自增整体表达式的值是i+1之前的值。
为什么会出现自增:代码更精炼;自增的速度更快
自减
三目运算符 A?B:C等价于if(A) B;else C;
逗号表达式 (A,B,C,D)从左到右执行,最终表达式的值是最后一项的值。i(j++,++j,j+2,j-3)最后两项没有把值赋给j。
位运算符:
&按位于(二者二进制代码每一位都与) &&逻辑与(值只能1或0,真或假) 二者含义完全不同
| 按位或 ||逻辑或
~ 按位取反
^ 按位异或 相同为0,不同为1
<< 按位左移 i<<1表示把i所有二进制位左移一位(二进制相当于乘二除二)比*速度快
>> 按位右移
通过位运算符,我们可以对数据的操作精确到每一位。
12.流程控制是程序代码执行的顺序。分为:顺序执行,选择执行,循环执行。
选择执行(if,switch)定义:有选择的执行某些代码。
if:1.if最简单的用法
if(表达式)
语句
功能:如果表达式为真,执行语句;不成立,不执行。
2.if的范围问题:if默认只能控制一个语句的执行或不执行。如执行多个语句,需用{}括起来。
3.if...else...的用法
4.if...else if...else...的用法
5.C语言对真假的处理:非零是真,零是假;真是1表示,假是0表示
6.if举例——求分数的等级
#include<stdio.h>
int main()
{float score;
printf("请输入您的成绩\n");
scanf("%f",&score);
if(score>=0&&score<60)
printf("不及格\n");
else if(score>=60&&score<80)
printf("良好\n");
else printf("优秀\n");
return 0;
}
两个数字互换
#include<stdio.h>
int main()
{int i=3;
int j=5;
int t; //定义临时变量
t=i;
i=j;
j=t;
printf("%d,%d\n",i,j);
return 0;
}
三个数中取最大值
#include<stdio.h>
int main()
{int a,b,c;
int t;
printf("请输入三个数字,以空格作为间隔\n");
scanf("%d %d %d",&a,&b,&c);
if(a<b)
{t=a;
a=b;
b=t;
}
if(a<c){
t=a;
a=c;
c=t;
}
if(b<c){
t=b;
b=c;
c=t;
}
printf("%d\n",a);
printf("最大值如上所示\n");
return 0;
}
7.if的常见问题解析
①空语句的问题
13.循环
定义:某些代码会被重复执行
分类:
for:for和if的嵌套使用(所有能被3整除的相加)
#include<stdio.h>
int main()
{int i;
int sum=0;
for(i=3;i<=12;++i)
{
if(i%3==0)
sum=sum+i;
}
printf("sum=%d i=%d\n",sum,i);
return 0;
}
强制类型转化
例子:1+1/2=1/3+...+1/100的和
#include<stdio.h>
int main()
{int i;
float sum=0;
for(i=1;i<=100;++i)
{
sum=sum+1.0/i;
}
printf("sun=%f",sum);
return 0;
}
格式:(数据类型)(表达式)
功能:
sum=sun+(float)(1/i);//这样是不对的
更简单的写法:sum=sum+1.0/i;
浮点数存储所带来的问题
float和double都不能保证可以精确的存储一个小数
举例:如何判断一个数浮点型变量X是否为0
if(|x-0.000001|<=0.000001)
是0;
else
不是0;
循环中更新的变量不能定义成浮点型。
求1到100的问题。
#include<stdio.h>
int main()
{int i;
int cnt=0;
int cnt1=0;
int cnt2=0;
int sum1=0;
int sum2=0;
int sum=0;
float avg=0;
for(i=1;i<101;++i)
{
if(i%2==1)
{
sum1=sum1+i;
++cnt1;
}
else
{
sum2=sum2+i;
++cnt2;
}
}
sum=sum1+sum2;
cnt=cnt1+cnt2;
avg=1.0*sum/cnt;
printf("奇数个数=%d\n",cnt1);
printf("奇数和=%d\n",sum1);
printf("偶数个数=%d\n",cnt2);
printf("偶数和=%d\n",sum2);
printf("avg=%f\n",avg);
return 0;
}
多层for循环的嵌套使用
while:
①执行顺序:while(表达式) 语句;
②与for的相互比较:可以相互转换,但for的逻辑性更强,更不容易出错,推荐使用for。
③举例:
for(1,2,3)
A;
等价于:
1;
while(2)
A;
3;
输入一个数字,并且判断该数字是否为回文数。
#include<stdio.h>
int main()
{int val;
int m;
int sum=0;
printf("请输入需要判断的数字\n");
scanf("%d",&val);
m=val;
while(m)
{
sum=sum*10+m%10;
m/=10;
}
if(sum==val)
printf("yes\n");
else
printf("no\n");
return 0;
}
斐波拉契数列第n项的值
#include<stdio.h>
int main()
{int f1,f2,f3;
int n;
int i;
f1=1;
f2=2;
printf("请输入数字\n");
scanf("%d",&n);
if(1==n)
f3=1;
else if(2==n)
f3=2;
else for(i=3;i<=n;++i)
{
f3=f1+f2;
f1=f2;
f2=f3;
}
printf("%d",f3);
return 0;
}
④什么时候使用while,什么时候使用for
do。。。while
格式:
do
{语句
}while(表达式)
do....while并不等价于for,也不等价于while。
主要用于人机交互
举例:一元二次方程
#include<stdio.h>
#include<math.h>
int main()
{
float a,b,c;
char ch;
float delta;
do{
printf("请输入一元二次方程的三个系数\n");
printf("a=");
scanf("%f",&a);
printf("b=");
scanf("%f",&b);
printf("c=");
scanf("%f",&c);
delta=b*b-4*a*c;
if(delta>0)
{
printf("此方程有两个不同解\n");}
else if(delta==0)
printf("此方程有两个相同解\n");
else{
printf("此方程没有实数解\n");}
printf("是否继续Y/N");
scanf(" %c",&ch);
}while('Y'==ch || 'y'==ch);
return 0;
}
%c前面必须加一个空格
switch:电梯程序
#include<stdio.h>
int main()
{int i;
printf("请输入楼层\n");
scanf("%d",&i);
switch(i)
{
case 1:
printf("1");
break;
case 2:
printf("2");
break;
case 3:
printf("3");
break;
default:
printf("NO");
}
return 0;
}
break与 continue
break:
break如果用于循环是用来终止循环;break如果用于switch,则是用于终止switch的;break不能直接用于if,除非if是循环内部的一个子句。
for(i=1;i<=3;++i)
if(3>2)
break; //break是用来终止for循环,break只能终止理她最近的for循环。在多层switch的嵌套中,break只能终止最近的switch。
continue:
用于跳过本次循环余下的语句,转去判断是否需要执行下次循环。
for(1;2;3)
{A;
B;
continue;//如果执行该语句,则执行完该语句后,会执行语句3,跳过C,继续循环。
C
}
while(表达式)
{A;
B;
continue;//如果for和while相互转化,则for语句中的3应在continue语句之上。
C;
}
while((ch=getchar())!='\n')
continue;//防止用户非法输入
14.数组
简单使用:
#include<stdio.h>
int main()
{
int i;
int a[5]={1,2,3,4,5}; //a表示数组的名字,5代表数组元素的个数,数组的元素表示为a[0],a[1]...a[4]
for(i=0;i<5;++i)
printf("%d\n",a[i]);
return 0;
}
为什么需要数组:为了解决大量同类型数据的存储;为了模拟现实世界
数组的分类
一维数组:为n个变量连续分配存储空间;所有的变量数据必须相同;所有变量所占的字节大小必须相等。
有关一维数组的操作:
初始化:完全初始化 int a[5]={1,2,3,4,5} 不完全初始化 int a[5]={1,2,3}未被初始化的元素自动为零 不初始化int a[5];所有元素都是垃圾值
清零 int a[5]={0}.
注意:只有在定义数组的同时才可以整体赋值。其他情况下整体赋值都是错误的。数组名代表数组第一个元素的地址。
int a[5]={1,2.3.4.5};
int b[5];
把a数组的元素复制给b数组的正确做法:
for(i=0;i<5;++i)
a[i]=b[i];
赋值:scanf("%d",&a[0]);
排序 求最大/最小值
倒置
#include<stdio.h>
int main()
{
int i,t,j;
i=0;
j=5; // j的值需要特别注意
int a[6]={1,2,3,4,5,6};
while(i<j)
{
t=a[i];
a[i]=a[j];
a[j]=t;
++i;
--j;
}
for(i=0;i<6;++i)
printf("%d\n",a[i]);
return 0;
}
查找 插入 删除
二维数组:int a[3][4]总共是12个元素,可当做3行4列看待,这些元素可用似坐标法表示。
int a[m][nj;该二维数组的最大元素只能是a[m-1][n-1]
初始化:int a[3][4]={
{1,2,3,4},
{5,6,7,8},
{ 9,10,11,12},
}
输出二维数组内容:用两个循环互相嵌套输出
#include<stdio.h>
int main()
{
int i,j;
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");
}
return 0;
}
对二维数组的排序
求每一行的最大值
判断矩阵是否对称
矩阵的相乘
多维数组
是否存在多维数组:不存在,内存是线性一维的,n维数组可以当做每个元素是n-1维数组的一维数组。
int a[3][4];该数组是含有3个元素的一维数组,只不过每个元素都可以再分成4个小元素。
int a[3][4][5];
15.函数
void表示函数没有返回值,故不能有return;在括号内表示该函数不能接受数据
#include<stdio.h>
void max(int i,int j)//max是函数的名字,i与j表示函数的形式参数。定义函数可以避免长语句重复使用。注意不要使用分号。
{
if(i>j)
printf("%d\n",i);
else
printf("%d\n",j);
}
int main()
{
int a,b,c,d;
a=1,b=2,c=3,d=4;//逗号表达式的使用
max(a,b);
max(c,d);
return 0;
}
为什么需要函数:避免了重复性操作;有利于程序的模块化。
什么是函数:
逻辑:能够完成特定功能的独立的代码块
物理:能够接收数据(当然也可以不接收数据),能够对接收的数据进行处理(也可以不处理),能够将数据处理的结构返回(也可以不返回任何值)。
函数是个工具,它是为了解决大量类似问题而设计的;函数可以当做一个黑匣子。
如何定义函数:函数的返回值 函数的名字(函数的形参列表)
{
函数的执行体
}
①函数定义的本质是详细描述函数之所以能够实现某个特定功能的具体方法。②return表达式的含义:终止被调函数,向主调函数返回表达式的值;如果表达式为空,则终止函数,不向被调函数返回任何值。;break是用来终止循环和switch的,return是用来终止函数的。
③函数返回值的类型也称为函数的类型,因为如果函数名前的返回值类型和函数执行体中的return表达式中的类型不同的话,最终函数返回值的类型以函数名前的返回值类型为准。
#include<stdio.h>
int a()
{
return 10;
}
int main()
{
/*int i=1;
i=a();
printf("%d",i);*/
float b=6.6;
b=a();
printf("%f",b);
return 0;
}
#include<stdio.h>
void a()
{
int i;
for(i=0;i<5;++i)
{
printf("你好!\n");
return; //return是用来终止被调函数,而break是用来终止循环。
}
printf("hello!\n");
}
int main()
{
a();
return 0;
}
函数的分类:
有参函数 和 无参函数
有返回值函数 和 无返回值函数
库函数 和自定义函数
值传递函数 和 地址传递函数(理论上不正确)
普通函数 和主函数(又称main函数):一个程序必须有且只能有一个主函数。主函数可以调用普通函数,普通函数不能调用主函数。普通函数可以相互调用。主函数是程序的入口,也是程序的出口。
判断一个数字是否为素数
主函数方法:
#include<stdio.h>
int main()
{
int val,i;
printf("请输入数字\n");
scanf("%d",&val);
for(i=2;i<val;++i) //判断是否为素数不考虑0,1,2
{
if(val%i==0)
break;
}
if(i==val)
printf("为素数\n");
else
printf("非素数\n");
return 0;
}
第二种方法
#include<stdio.h>
bool IsPrime(int i)
{
int j;
for(j=2;j<i;++j)
{
if(i%j==0)
break;
}
if(j==i)
return true;
else
return false;
}
int main()
{
int b;
printf("请输入数字\n");
scanf("%d",&b);
if(IsPrime(b))
printf("yes\n");
else
printf("no\n");
return 0;
}
第三种方法
#include<stdio.h>
int IsPrime(int i)
{
int j;
for(j=2;j<i;++j)
{
if(i%j==0)
break;
}
if(j==i)
return 0;
else
return 1;
}
int main()
{
int b;
printf("请输入数字\n");
scanf("%d",&b);
if(IsPrime(b)==0)
printf("yes\n");
else
printf("no\n");
return 0;
}
函数复习
#include<stdio.h>
int a(int i)
{
return 10;
}
int main()
{
int i;
i=99;
printf("%d\n",i);
i=a(9);
printf("%d\n",i);
return 0;
}
函数的声明
#include<stdio.h>
int a(int i); //此为函数的声明
int main()
{
int i;
i=99;
printf("%d\n",i);
i=a(9);
printf("%d\n",i);
return 0;
}
int a(int i)
{
return 10.8;
}
注意的问题:
函数定义的顺序,如果没有前置声明,则定义函数放在了调用函数的后面是错误的。
前置声明作用:①告诉编译器即将可能出现的若干个字母代表的是一个函数。
②告诉编译器即将可能出现的若干个字母所代表的函数的形参和返回值的具体情况。
③函数声明是一个语句,末尾必须加分号。
④对库函数的声明是通过#include<库函数所在的文件的名字.h>来实现的。
形参和实参:个数相同,位置一一对应,数据类型相互兼容
如何在软件开发中合理的设计函数来解决实际问题
求到某数之间的各个素数
普通方法:
#include<stdio.h>
int main()
{
int i,j,k;
printf("请输入数字\n");
scanf("%d",&i);
for(k=2;k<=i;++k)
{
for(j=2;j<k;++j)
{
if(k%j==0)
break;
}
if(j==k)
printf("%d\n",k);
}
return 0;
}
定义函数方法
#include<stdio.h>
int a(int i);
int main()
{
int i,k;
printf("请输入数字\n");
scanf("%d",&i);
for(k=2;k<=i;++k)
{
if(a(k)==1)
printf("%d\n",k);
}
return 0;
}
int a(int i)
{
int j;
for(j=2;j<i;++j)
{
if(i%j==0)
break;
}
if(j==i)
return 1;
else
return 0;
}
函数是C语言的基本单位,类是Java,C#,C++的基本单位
常用的系统函数
double sqrt(double x);求x的平方根 int abs(int x);求x的绝对值/double
fabs(double x);
递归:栈:先进后出 自己调用自己就是递归的本质。
容易搞错的调用例子 :
#include<stdio.h>
void a(int i)
{
printf("%d",i);
}
void b(void)
{
a(10);
}
int main()
{
int i=99;
b();
return 0;
}
变量的作用域和存储方式:
按作用域分:
全局变量:在所有函数外部定义的变量。全局变量的适用范围是从定义位置到整个程序结束。
局部变量:在一个函数内部定义的变量或者是函数的形参都统称为局部变量。局部变量的使用范围是只能在本函数内部使用。
注意:全局变量和局部变量命名冲突的问题,在一个函数内部如果定义的局部变量的名字和全局变量的一样,局部变量会屏蔽全局变量的值。
按变量的存储方式:
静态变量
动态变量
寄存器变量
16.指针
#include<stdio.h>
int main()
{
int * p;//p是变量的名字,int * 表示的是p变量存放的是int类型变量的地址
int i=1;
p=&i;
//p=i 或 p=55 错误,因为类型不一致,p只能存放int类型变量的地址 ,不能存放int类型变量的值
return 0;
}
/* p保存了i的地址,因此p指向i。因为二者为不同概念的变量,所以互不影响。指针变量就是地址变量。如果一个指针变量指向了某个普通变量,则*指针变量就完全等同于普通变量。
如果p=/i,因此*p=i。*/
*p就是以p的内容为地址的变量;指针就是地址,地址就是指针;地址就是内存单元的编号;指针变量是存放地址的变量;叙述时有时把指针变量和指针等同,其实二者不同。
指针的重要性:表示一些复杂的数据结构;快速的传递数据,减少了内存的耗用;使函数返回一个以上的值,能直接访问硬件,能够方便的处理字符串,理解面向对象语言中引用的基础。
指针的定义
地址:内存单元的编号,从0开始的非负整数。范围:2^30K=1G,32根地址总线是4G
指针:指针就是地址,指针变量就是存放内存单元编号的变量,也是存放地址的变量。指针的本质就是一个操作受限的非负整数
指针的分类
①基本类型指针
#include<stdio.h>
int main()
{
int *p;
int i=5;
p=&i; //*p=i;是错误的。*p=q;也是错误的,*p是int类型,q是int*类型
printf("%d",*p);
return 0;
}
int *p;
int*q;
p=q;
printf("%d",*q);//q的空间是属于本程序的,所以本程序可以读写q的内容,但是如果q内部是垃圾值,则本程序不能读写*q的内容。因为此时*q所代表的内存单元的控制权限并没有分配给本程序。
互换两个数字:
错误:
#include<stdio.h>
void a(int i,int j )
{
int k;
k=i;
i=j;
j=k;
}
int main()
{
int i,j;
printf("请输入两个数字\n");
scanf("%d,%d",&i,&j);
a(i,j);
printf("%d,%d",i,j);
return 0;
}
正确:
#include<stdio.h>
void a(int *i,int *j)
{
int k;
k=*i;
*i=*j;
*j=k;
}
int main()
{
int i,j;
printf("请输入两个数字\n");
scanf("%d,%d",&i,&j);
a(&i,&j);
printf("%d,%d",i,j);
return 0;
}
*的三种含义:①乘法 ②定义指针变量 ③指针运算符,该运算符放在已经定义好的指针变量前面,若p是已经定义好的指针变量,则*p表示以p的内容为地址的变量。
int* p; char ch='A'; p=&ch 错误,因为类型不一致
使函数返回一个以上的值 举例:不使用指针,可以用return(返回值)。
如何通过被调函数修改主调函数普通变量的值:实参必须为主调函数普通变量的地址;形参必须为指针变量;在被调函数中,通过*形参名的方式就可以修改主调函数相关变量的值。
②指针和数组
指针和一维数组
数组名:一维数组名是个指针常量,它存放的是一维数组第一个元素的地址
下标和指针的关系:如果P是个指针变量,则p[i]永远等价于*(p+1)
如果一个函数要处理一个一维数组,则需要接收该数组的哪些信息(确定一个一维数组需要几个参数)
需要两个参数:数组第一个元素的地址,数组的长度
#include<stdio.h>
int b(int* parr,int l)
{
int i;
for(i=0;i<l;++i)
printf(" %d",*(parr+i));//等价于* parr[i]
printf("\n");
parr[2]=66;
printf("%d",*(parr+2));
}
int main()
{
int a[3]={1,2,3};
b(a,3);
return 0;
}
例二
#include<stdio.h>
void b(int* parr,int l)
{
int i;
for(i=0;i<l;++i)
printf(" %d",*(parr+i));
printf("\n");
return;
}
int main()
{
int a[3]={1,2,3};
int c[4]={1,2,3,4};
b(a,3);
b(c,4);
return 0;
}
指针变量运算
指针变量不能相加,相乘,相除,只能相减。如果两个指针变量指向的是同一块连续空间中的不同存储单元,则可以相减。
#include<stdio.h>
int main()
{
int a[5];
int* i;
int* j;
i=&a[2];
j=&a[4];
printf("%d",j-i);
return 0;
}
一个指针变量到底占几个字节
假设p指向char类型变量:1k
假设q指向int类型变量:4k
假设r指向double类型变量:8k
sizeof(数据类型)功能:返回值就是该数据类型所占的字节数
sizeof(int)=4 sizeof(char); sizeof(double)=8 sizeof(char)
#include<stdio.h>
int main()
{
int a=1;
double b=9.9;
char ch='A';
int* p1=&a;
double* p2=&b;
char* p3=&ch;
printf("%d,%d,%d\n",sizeof(p1),sizeof(p2),sizeof(p3));
return 0;
}
一个指针变量,无论它指向的变量占几个字节,该指针变量本身只占8个字节;一个变量的地址是用该变量首字节的地址来表示,但该地址是由变量类型所占的字节数来表示的。
动态内存分配
传统数组的缺点:
①数组长度必须事先指定,且只能是常整数,不能是变量。
②传统形式定义的数组,该数组的内存程序员无法手动释放。数组一旦定义,系统就会为该数组分配的存储空间就会一直存在,除非数组所在的函数运行结束。(在一个函数运行期间,系统为该函数中数组所分配的空间会一直存在,直到该函数运行完毕时,数组的空间才会被系统释放)
③数组的长度不能在函数运行的过程中动态的扩充或缩小
④A函数定义的数组在A函数运行期间可以被其他函数使用,但A函数运行完毕之后,A函数中的数组将无法再被其他函数使用。传统方式定义的数组不能跨函数使用。
为什么需要动态分配内存:动态数组很好地解决了传统数组的这四个缺陷。传统数组也叫静态数组
动态内存分配距离——动态数组的构造
#include<malloc.h>//要使用malloc函数,必须添加malloc.h头文件。malloc函数只有一个形参,并且形参是整型。
int* p=(int*)malloc(4);//4表示请求系统为本程序分配个字节。malloc函数只能返回第一个字节的地址。一共分配了8个字节,p指向的内存也占4个字节。p本身所占的内存是静态分配的,P所指向的内存是动态分配的。
#include<stdio.h>
#include<malloc.h>
int main()
{
int i=5;
int* p=(int*)malloc(4);
*p=5;//与5行内存分配方式不同
free(p);//将P所指向的内存给释放掉,但是P只能在函数结束后由系统释放
printf("123\n");
return 0;
}
例二
#include<stdio.h>
#include<malloc.h>
void a(int* i)
{
*i=200;
//如若加入free(i);,则输出的*j值出现错误。
return;
}
int main()
{
int* j=(int*)malloc(4);
*j=10;
printf("%d\n",*j);
a(j);
printf("%d\n",*j);
return 0;
}
动态数组构造:
#include<stdio.h>
#include<malloc.h>
int main()
{
int a[5];//每4个字节是一个int类型变量,共20字节
int i,k;
int* j;
printf("请输入所构造数组的元素个数\n");
scanf("%d",&i);
j=(int*)malloc(4*i);//类似于int j[i];
printf("请输入数字\n");
for(k=0;k<i;++k)
scanf("%d",&j[k]);
for(k=0;k<i;++k)
printf(" %d",j[k]);
free(j); //手动释放掉后的内存为垃圾值
for(k=0;k<i;++k)
printf(" %d",j[k]);
return 0;
}
realloc:动态的扩充和缩小
realloc(数组名,字节数):当字节数比原数组字节大则扩充,小则缩小。
静态内存和动态内存的比较:静态内存是由系统自动分配,由系统自动释放。静态内存是在栈分配的;动态内存是由程序员手动分配,手动释放,动态内存是在堆分配的。
多级指针
#include<stdio.h>
void e(int* i)
{
*i=3;
return;
}
int main()
{
int a=1;
int* b=&a;
int** c=&b;
int*** d=&c;
printf("%d\n",a);
printf("%d\n",b);
printf("%d\n",c);
printf("%d\n",***d);
e(&a);
printf("%d",a);
return 0;
}
多级指针的赋值
#include<stdio.h>
void e(int** i)
{
**i=3;
return;
}
int main()
{
int a=1;
int* b=&a;
int** c=&b;
int*** d=&c;
printf("%d\n",a);
printf("%d\n",b);
printf("%d\n",c);
printf("%d\n",***d);
e(&b);
printf("%d",*b);
return 0;
}
跨函数使用内存的问题
静态内存不能跨函数,下例为错。
#include<stdio.h>
void a(int** i)
{
int j=5;
*i=&j;
return;
}
int main()
{
int* p;
a(&p);
printf("%d",*p);
return 0;
}
动态内存跨函数使用——修改值
#include<stdio.h>
#include<malloc.h>
void a(int** i)
{
*i=(int*)malloc(4);
**i=5;
return;
}
int main()
{
int* p;
a(&p);
printf("%d",*p);
return 0;
}
指针和二维数组
③指针和函数
④指针和结构体
结构体
为什么需要结构体:为了表示一些复杂的事物而普通的基本类型无法满足实际要求。
什么叫结构体:把一些基本类型数据组合在一起形成的一个新的复合数据类型。
如何定义结构体:
struct Student
{
int score;
int age;
char sex;
} ;
...
struct Stduent st1;//此方式只定义了一个新的数据类型,没有定义变量。
怎样使用结构体变量:
赋值和初始化
①初始化:定义的同时赋值
如果定义完之后只能单个赋值。
#include<stdio.h>
int main()
{
struct Student
{
int age;
char sex;
float score;
};
struct Student st1={18,'F',98.3};
struct Student st2;
st2.age=17;
st2.sex='F';
st2.score=97.5;
printf("%d %c %f\n",st1.age,st1.sex,st1.score);
printf("%d %c %f\n",st2.age,st2.sex,st2.score);
return 0;
}
如何取出结构体变量中的每一个成员:
①结构体变量名.成员名 ②指针变量名->成员名 在计算机内部会被转化成(*指针变量名).成员名 的方式来执行。
这两种方式是等价的。
struct Student* pst=&st2;
pst->age=17;//pst所指向的那个结构体变量中的age这个成员。
通过函数完成对结构体变量的输入和输出
#include<string.h>
strcpy(pst->name,"jerry");//对字符串的输入
输入与输出举例:
#include<stdio.h>
#include<string.h>
struct Student
{
int age;
float score;
char sex;
char name[100];
};
void InputStudent(struct Student* st)
{
st->age=16;
st->score=59.9;
st->sex='F';
strcpy(st->name,"jerry");
return;
}
void OutputStudent(struct Student*st)//可以发送地址,也可以发送内存
{
printf("%d %f %c %s\n",st->age,st->score,st->sex,st->name);
return;
}
int main()
{
struct Student st1;
InputStudent(&st1);
printf("%d %f %c %s\n",st1.age,st1.score,st1.sex,st1.name);
OutputStudent(&st1);
printf("%d",sizeof(st1));
return 0;
}
结构体变量的运算:可以相互赋值st1=st2或st2=st1
结构体变量和结构体变量指针作为函数参数传递的问题
动态构造放学生信息的结构体数组:动态构造一个数组,存放学生的信息,然后按照分数排序输出。
#include<stdio.h>
#include<malloc.h>
struct Student
{
char name[100];
char sex[100];
int age;
float score;
};
void sp(struct Student* i,int j)
{
int a,b;
struct Student c;
for(a=0;a<j-1;++a)
{
for(b=0;b<j-1-a;++b)
{
if((i[b].score)>(i[b+1].score))
{
c=i[b];
i[b]=i[b+1];
i[b+1]=c;
}
}
}
for(a=0;a<j;++a)
{
printf("%s %s %d %f\n",(i[a].name),(i[a].sex),(i[a].age),(i[a].score));
}
return;
}
int main()
{
struct Student* pst;
int len,i;
pst=(struct Student*)malloc(len*sizeof(struct Student));
printf("请输入共有几名学生\n");
scanf("%d",&len);
for(i=0;i<len;++i)
{
printf("第%d名学生的名字\n",(i+1));
scanf("%s",pst[i].name);
printf("第%d名学生的性别\n",(i+1));
scanf("%s",pst[i].sex);
printf("第%d名学生的年龄\n",(i+1));
scanf("%d",&pst[i].age);
printf("第%d名学生的分数\n",(i+1));
scanf("%f",&pst[i].score);
}
sp(pst,len);
return 0;
}
枚举
什么是枚举:把一个事物所有可能的取值一一列举出来
怎么使用枚举
#include<stdio.h>
enum weekday
{monday=1,tuesday,wednesday,thurday,friday,saturday,sunday//这里可以自定义值,默认第一个为0
};
void a(enum weekday i)
{
switch(i)
{
case 1://注意switch语句的case需要用:
printf("星期一\n");
break;
case 2:
printf("星期二\n");
break;
case 3:
printf("星期三\n");
break;
case 4:
printf("星期四\n");
break;
case 5:
printf("星期五\n");
break;
case 6:
printf("星期六\n");
break;
case 7:
printf("星期日\n");
break;
}
}
int main()
{
a(thurday);
return 0;
}
枚举的优缺点:代码更安全,但书写麻烦
位运算符:
补码:
原码:也叫符号绝对值码,最高位0表示正,1表示负,其余二进制是该数字的绝对值得二进制位
简单易懂,加减运算复杂,存在加减乘除四种运算,增加了CPU的复杂度,0的表示不唯一
反码:反码运算不便,也没有在计算机中应用
移码:表示数值平移N位,N称为移码量。移码主要用于浮点数阶码的存储
补码:
十进制转二进制
正整数转二进制:除二取余,直至商为0,余数倒叙排序
负整数转二进制:先求与该负数相对应的正整数的补码,然后将所有位取反,末尾加1,不够位数时,左边补1 1111=F
零转二进制:全是0
二进制转十进制:
如果首位是0,则表明是正整数,按普通方法来求
如果首位是1,则表明是负整数,将所有位取反,末尾加一,所得数字就是该负数的绝对值
如果全是零,则对应的十进制数字就是零
学习目标:在vc++6.0中一个int类型的变量所能存储的数字的范围是多少:80000000——7FFFFFFF均用十六进制表示
最小负数的二进制代码是多少
最大正数的二进制代码是多少
已知一个整数的二进制代码求出原始的数字
数字超过最大正数会怎样
不同类型数据的相互转化
字符串的处理
链表:
算法
通俗定义:解题的方法和步骤
狭义定义:对存储数据的操作,对不同的存储结构,要完成某一个功能所执行的操作是不一样的。说明算法是依附于存储结构的,不同的存储结构,所执行的操作是不一样的
广义定义:也叫泛型,无论数据是如何存储的,对数据的操作都是一样的
我们至少可以通过两种结构来存储数据:
数组 优点:存取速度快 缺点:需要一个连续的很大内存,插入和删除元素的效率很低
链表 优点:插入删除元素效率高,不需要一个连续的很大的内存 缺点:要查找某个位置的元素效率低
专业术语:
头节点:头结点的数据类型和首节点的类型是一样的,头结点是首节点前面的那个节点,并不存放有效数据。设置头结点的目的是为了方便对链表的操作。
头指针 :存放头节点地址的指针变量
首节点:存放第一个有效数据的节点
尾节点:存放最后一个有效数据的节点。
尾指针
⑤多级指针
冒泡排序法
#include<stdio.h>
void sort(int* p,int a)
{
int b,c,d;
for(b=0;b<a-1;++b)
{
for(c=0;c<a-1-b;++c)//这里需要深刻理解
{
if(p[c]>p[c+1])
{
d=p[c];
p[c]=p[c+1];
p[c+1]=d;
}
}
}
return;
}
int main()
{
int a[10]={-65,-97,-8,0,-23,78,1568,5,10,67};
int i;
sort(a,10);
for(i=0;i<10;++i)
{
printf("%d\n",a[i]);}
return 0;
}
18.二进制全部为0的含义。
①数值0
②字符串结束标记符‘\0’
③空指针NULL NULL本质也是0,表示的是内存单元的编号0 计算机规定,以0为编号的存储单元的内容不可读,不可写