算法:是指解决某一个特定问题而采取的确定且有限的步骤。具备五个特点:有穷性,确定性,可行性,有零个或多个输入,有一个或多个输出。最常用的是伪代码和流程图。
N-S流程图
结构化的语言:顺序结构,选择结构,循环结构
指针
一、定义
为什么会出现指针?
a是房间,1001是房客,2001是房间a的地址
p是吧台(指针),3001是p的地址
去3001询问吧台p就知道a房间的地址是2001了。
int*p,a=1001; p=&a; 所以 *p=a=1001
1、计算机的内存是以字节为单位的一片连续的存储空间,每一个字节都有一个编号,这个编号就是内存地址。
2、若在程序中定义了一个变量,C编译系统就会根据定义中变量的类型,为其分配一定字节数的内存空间,这个变量的内存地址就确定了(一个人就一个单人间,多个人就分个多人间,房客可以变,但房间不会变),每个变量的地址是指给变量所占存储单元的第一个字节的地址。(int 2,float 4,double 8)
3、对变量进行存取操作,本质上就是对某个地址的存储单元进行操作。直接按变量的地址存取变量值的方式叫做“直接存取”方式。(int a ;a=12就是把12放到a所在存储单元,放到2001这个地址中,实际上就是对内存地址进行的操作)
4、定义一种特殊的变量,这种变量是用来存放内存地址的,通过变量P间接得到变量a的地址,然后再存取变量a的值,叫做“间接存取”方式。(房客12要去问吧台P,p告诉12,她住在2001这个地址。)
5、用来存放指针地址的变量就叫做“指针变量”。(类型与存放变量的类型相同)
6、“变量p指向变量a”的含义就是指针变量p中存放了变量a的地址。
7、在某些场合,指针是使运算得以进行的唯一途径()。
二、指针的定义赋值
int *pi,*pj; (定义了两个指针变量)
pi,pj是指向整形的指针,pi,pj中只能存放整形变量的地址。
int **p,*s,k=20;(p中存放的是吧台的地址)
s=&k;p=&s;(&表示求地址运算符,代表地址,p中存放的是s的地址,s里存放的是k的地址,给指针变量赋值)
*p(代表引用p中存放的内容)代表存储单元s,*s代表存储单元k,因此**p也代表存储单元k,
//*出现在定义语句中时,代表定义一个指针变量,当*出现在执行语句时,代表引用当前指针的变量中的内容。
为什么指针变量要有“基类型”?
int2,float4,double8,char 1
a,b,c,d,e,f,都是整形,占两个字节,要让p从a指向b时,就也必须移动两个字节,才能指向b,所以p也就是int,如果p是double,那p每次都移动8个字节,就不能指向b了。
一个指针变量中存放的是一(int型是2个字节,float型是4个字节)个存储单元的地址值。
给指针变量赋值
1、通过求地址运算(&)获得地址值
1)单目运算符&用来求出运算对象地址,得用求地址运算可以吧一个变量的地址赋给指针变量。p=&k(求出了变量k的地址值,赋给指针型变量p)
2)把变量k的地址赋给了q=q指向了变量k
3)1,&只能应用于变量和数组元素,不可用于表达式、常量或被说明为register(寄存器)的变量。
2,&必须放在运算对象左边,且运算对象类型比寻与指针变量的基类型相同。
4)调用scanf时,若q=&k,则scanf(“%d”,&k)和scanf(“%d”,q)是等价的。
2、通过指针变量获得地址值
1)可以通过&,把指针变量的地址值赋给另一个指针变量,从而使得两个指针变量指向同一个地址。p=q
2)当进行赋值运算时,赋值号两边的指针变量的基类型必须相同。
3、通过标准函数获得地址值
调用库函数malloc和calloc在内存中开辟动态存储单元,并把所开辟的动态存储单元的地址赋给指针变量。
4、给指针变量赋”空“值(int *p=NULL)
1)p=NULL,等价于p=’ \0’ ;或p=0;
2)使用NULL时,应该在程序的前面出现预定义行
#include “stdio.h”。NULL的值为0,当执行以上赋值语句后,称p为空指针。
三、对指针变量的操作
1、通过指针来引用一个存储单元
间接访问运算符(间址运算符)“*”单目运算符。
1)int*p,i=10,j;
p=&i;(*p=i,所以&和*就好比乘除号一样,可以相互抵消)
表示取&i中的内容赋予j。
j=*p+1,表示取变量p所指向存储单元(i)中的内容加1后赋予变量j。
2)int*p,k=0;
p=&k;
所以,利用*p=100可以100赋给k。
3)*p=*p+1;
现在使得变量k中的值变为了101.
也可以写成:*p+=1,或++*p;或(*p)++;(括号不能少)
4)*p++;
值为p所指存储单元中的内容(100),然后使指针变量p本身增1;并不使所指存储单元中的值增1。
m=*p++; m=*p; p++; p=P+1;(指针变量加1就是把指针往前移动一个存储单元)
所以*p++就=200,先把p往前移动一个存储单元,然后再代表其存储的变量内容=200,并不再是101了。
5)例题:
当指针指向变量时,完全可以通过指针来对所存储单元进行存取。
2、移动指针
*q-*p=22; q-p=2;(地址相差2个存储单元)
1)移动指针:对指针变量加上或减去一个整数。或通过赋值运算,使指针变量指向相邻的存储单元。只有当指针指向一串连续的存储单元时,指针的以移动才有意义。
2)当指针指向一串连续的存储单元时,可以对指针变量进行加上或减去一个整数的运算,也可以对指向同一串连续存储单元的两个指针进行相减运算。
3)例题:
4)当移动指针时,基类型为int的指针只能用来指向int变量,不能用以指向其他类型变量。指针移动时,指针必须指向基类型相同的变量。如果用基类型为int的指针来指向一串double类型的变量,当指针移动时,对整数1系统将按照其类型来确定移动2个字节而不是移动8个字节。
3、指针的比较
其本质是比较在内存中指针所指向的地址,但必须是一串连续的存储单元。
四、指针在函数中的应用及举例
1、函数之间地址的传递
1、形参为指针变量时,实参和形参之间的数据传递
1)若函数的形参为指针类型,则调用该函数时,对应的实参必须是基类型相同的地址值或者是已经指向某个存储单元的指针变量。(只有指针变量才能存放地址)
2)例子:
myadd(int *a,int *b)
{int sum;
sum=*a+*b;
return sum;
}
main(){
int x,y,z;
printf(“enter x,y”);
scanf(“%d%d”,&x,&y);
z=myadd(&x,&y);
printf(“%d+%d=%d\n”,x,y,z);
}//*a和*b引用的是地址为x和地址为y中的内容,当实参为地址的时候,形参一定是对应的指针,实参为指针的话,也代表形参对应的是指针。
2、通过传送地址值,在被调用函数中直接改变调用函数中的变量的值。
1)把数据从被调用函数返回到调用函数的唯一途径是通过return语句返回数值,这就限定了只能返回一个数据。
2)例子:调用swap函数,交换主函数中变量x和y中的数据。
main(){
int x=30,y=20;
printf(“(1) x=%d,y=%d\n”,x,y);
swap(&x,&y);
printf(“(4) x=%d,y=%\n”,x,y);
}
swap(int *a,int *b){
int t;
printf(“(2)a=%d,b=%d\n”,*a,*b);
t=*a;*a=*b;*b=t;
printf(“(3)a=%d,b=%d\n”,*a,*b);
}
原来说,形参改变,实参是不变的,这里形参改变了,实参也变了。(通过地址值让形参改变了实参)
2)例子:编写函数order(int*a,int*b),使调用函数中得第一个实参总是存放两个数中的最小数,第二个参数存放两个数中较大的数。