null第八章第八章 主要
内容
财务内部控制制度的内容财务内部控制制度的内容人员招聘与配置的内容项目成本控制的内容消防安全演练内容
主要内容 8.1 地址和指针的概念
8.2 变量的指针和指向变量的指针变量
8.3 通过指针引用数组
8.4 通过指针引用字符串
8.5 指向函数的指针
8.6 返回指针值的函数
8.7 指针数组和多重指针
8.8 动态内存分配与指向它的指针变量 8.1 地址和指针的概念 8.1 地址和指针的概念 数据在内存中是如何存储的,又是如何读取的?
如:int i,j,k;
i=3;j=6;k=9; 8.1 地址和指针的概念 8.1 地址和指针的概念 内存区的每一个字节有一个编号,这就是“地址” 。如果在程序中定义了一个变量,在对程序进行编译时,系统就会给这个变量分配内存单元。 1、按变量名或变量地址存取变量值的方式称为
“直接访问”方式。
如:
printf(″%d″,i);
scanf(″%d″,&i);
k=i+j; null2. 另一种存取变量值的方式称为“间接访问”的方式。即,将变量i的地址存放在另一个变量中。要存取变量i的值,首先找到存放“i的地址”的变量,从中取出i的地址,然后再根据相应的地址存取数据。在C语言中,指针是一种特殊的变量,它是存放地址的。null所谓指向是通过地址来体现的。指针和指针变量的定义:20003i_pointeri2000称为i_pointer指向变量i。变量i的指针(地址)指针变量8.2 变量的指针和指向变量的指针变量8.2 变量的指针和指向变量的指针变量 变量的指针就是变量的地址,存放地址的变量称为指针变量,它用来指向一个变量。为了
表
关于同志近三年现实表现材料材料类招标技术评分表图表与交易pdf视力表打印pdf用图表说话 pdf
示指针变量与它所指向的变量之间的联系,使用*加上指针变量名,表示它所指向的变量。8.2 变量的指针和指向变量的指针变量8.2 变量的指针和指向变量的指针变量8.2.1 怎样定义指针变量定义指针变量的一般形式为
基类型 *指针变量名;
如:
int *pointer_1,*pointer_2;基类型指针变量名null下面都是合法的定义:
float *pointer_3;
char *pointer_4;
可以用赋值语句使一个指针变量得到另一个变
量的地址,从而使它指向该变量。
例如:
pointer_1=&i;
pointer_2=&j;也可以在定义时,同时进行初始化:
float *p3=&i;
char *p4=&j;null注意:定义指针变量时,指针变量前面的“*”,表示该变量的类型为指针型变量。
例: int *pointer_1;
指针变量名是pointer_1 ,而不是* pointer_1 。
而在其它位置,*pointer_1表示指针变量pointer_1所指向的值。
如:int *p1;
int i=5;
p1=&i;
printf(“%d”,*p1) null注意:(2) 在定义指针变量时必须指定基类型。
下面的赋值是错误的∶
float a;
int * pointer_1;
pointer_1=&a; null在对指针变量赋值时需要注意两点:⑴ 指针变量中只能存放地址(指针),不要将一个
整数赋给一个指针变量。
例: pointer_1=100; /* pointer_1是指针变量,100是整数,不合法 */
(2) 赋给指针变量的变量地址不能是任意的类型,而只能是与指针变量的基类型具有相同类型的变量的地址。
null两个相关的运算符:
(1)&:取地址运算符。
(2)*:指针运算符。
如:
&a 表示变量a的地址。
*p为指针变量p所指向的存储单元。8.2.2 怎样引用指针变量null例8.1 通过指针变量访问整型变量#include
void main ( )
{ int a,b;
int*pointer_1, *pointer_2;
a=100;b=10;
pointer_1=&a; /*把变量a的地址赋给
pointer_1 */
pointer_2=&b; /*把变量b的地址赋给
pointer_2 */
printf(″%d,%d\n″,a,b);
printf(″%d,%d\n″,*pointer_1, *pointer_2);
}
nullnull例8 . 2 输入a和b两个整数,按先大后小的顺序输出
a和b。#include
void main()
{ int *p1,*p2,*p,a,b;
scanf(″%d,%d″,&a,&b);
p1=&a;p2=&b;
if(a<b)
{p=p1;p1=p2;p2=p;}
printf(″a=%d,b=%d\n\n″,a,b);
printf(″max=%d,min=%d\n″,*p1,*p2);
} null运行情况如下:
5,9↙
a=5,b=9
max=9,min=5
当输入a=5,b=9时,由于a<b,将p1和p2交换。交换前的情况见图(a),交换后见图(b)。nullnull有以下程序 void main ( )
{ int a=7,b=8,*p,*q,*r;
p=&a;q=&b;
r=p;p=q;q=r;
printf(“%d,%d,%d,%d\n”,*p,*q,a,b);
}
程序运行后的结果是:运行结果:
8,7,7,8null8.2.3 指针变量作为函数参数单向值传递方式传递参数,改变形参的值,不能改变实参的值。
指针变量作为函数的参数是将一个变量的
地址传送到另一个函数中。null8.2.3 指针变量作为函数参数单向值传递方式:
void f(int a)
{a=3;}
void main()
{int b=0;
f(b);
printf(“%d”,b);
}指针作为函数参数:
void f(int *ptr)
{*ptr=3;}
void main()
{int b=0;
f(&b);
printf(“%d”,b);
}输出结果:0输出结果:3null8.2.3 指针变量作为函数参数例8 . 3 对输入的两个整数按大小顺序输出 #include
void main()
{void swap(int *p1,int *p2);
int a,b;
int *pointer_1,*pointer_2;
scanf(″%d,%d″,&a,&b);
pointer_1 =&a; pointer_2 =&b;
if(a<b) swap( pointer_1 , pointer_2 );
printf(″\n%d,%d\n″,a,b);
} nullvoid swap(int *p1,int *p2)
{ int temp;
temp=*p1;
*p1=*p2;
*p2=temp;
}nullnull上例中不能将swap函数改为:
void swap(int *p1,int *p2)
{ int * temp;
*temp=*p1;
*p1=*p2;
*p2=*temp;
}null不能通过单向值传递方式改变实参a,b的值。
void swap(int x,int y)
{ int temp;
temp=x;
x=y;
y=temp;
}
在main函数中调用swap(a,b);null不能通过改变指针形参的值而使指针实参的值改变。
void swap(int *p1,int *p2)
{ int *p;
p=p1;
p1=p2;
p2=p;
}
null例8.4输入3个整数a,b,c,
要求
对教师党员的评价套管和固井爆破片与爆破装置仓库管理基本要求三甲医院都需要复审吗
按大小顺序将它们输出。
用函数实现改变这3个变量的值。 #include
void main()
{ void exchange(int *q1, int *q2, int *q3);
int a,b,c,*p1,*p2,*p3;
scanf(″%d,%d,%d″,&a, &b, &c);
p1=&a;p2=&b;p3=&c;
exchange (p1,p2,p3);
printf(″\n%d,%d,%d\n″,a,b,c);
}nullvoid exchange(int *q1, int *q2, int *q3)
{ void swap(int *pt1, int *pt2);
if(*q1<*q2) swap(q1,q2);
if(*q1<*q3) swap(q1,q3);
if(*q2<*q3) swap(q2,q3);
}
void swap(int *pt1, int *pt2)
{int temp;
temp=*pt1;
*pt1=*pt2;
*pt2=temp;
} null有如下程序:
void f(int y,int *x)
{y=y+*x;*x=*x+y;}
void main()
{int x=2,y=4;
f(y,&x);
printf(“%d %d”,x,y);
} 8.3 通过指针引用数组 8.3 通过指针引用数组所谓数组元素的指针就是数组元素的地址。可以用一个指针变量指向一个数组元素。
例如:int a[10];
int *p;
p=&a[0];
(把a[0]元素的地址赋给指针变量p)
也就是使p指向a数组的第0号元素 。
数组名a表示数组的首地址。
p=&a[0];等价于 p=a;8.3.1 数组元素的指针nullnullC语言规定在指针指向数组元素时,可以对指针进行以下运算:
加一个整数(用+或+=),如p+1
减一个整数(用-或-=),如p-1
自加运算,如p++,++p
自减运算,如p--,--p
两个指针相减,如p1-p2 (只有p1和p2都指向同一数组中的元素时才有意义)。8.3.2 指针的运算null说明:
如果指针变量p已指向数组中的一个元素,则p+1
指向同一数组中的下一个元素,p-1指向同一数组中
的上一个元素。
(2)数组名表示数组的首地址,即&a[0], 如果p的初值为&a[0],则p+i和a+i就是数组元素a[i]的地址,或者说,它们指向a数组的第i个元素 。
(3)*(p+i)或*(a+i)是p+i或a+i所指向的数组元素,即a[i]。 null8.3.3 通过指针引用数组元素 引用一个数组元素,可以用:
(1) 下标法,如a[i]形式;
(2) 指针法,如*(a+i)或*(p+i)。其中a是数组名,p是指向数组元素的指针变量,其初值p=a。例8.5 输出数组中的全部元素 假设有一个a数组,整型,有10个元素。要输出各元素的值有三种方法: null(1)下标法
#include
void main()
{ int a[10];
int i;
for(i=0;i<10;i++)
scanf(″%d″,&a[i]);
printf(″\n″);
for(i=0;i<10;i++)
printf(″%d″,a[i]);
}null(2) 通过数组名计算数组元素地址,找出元素的值。
#include
void main()
{ int a[10];
int i;
for(i=0;i<10;i++ )
scanf(″%d″,&a[i]);
printf(″\n″);
for(i=0;i<10;i++)
printf(″%d″,*(a+i));
}null(3) 用指针变量指向数组元素。
#include
void main()
{ int a[10];
int *p,i;
for(i=0;i<10;i++)
scanf(″%d″,&a[i]);
printf(″\n″);
for(p=a;p<(a+10);p++)
printf(″%d ″,*p);
}null关于指针变量的计算若p=a(p指向数组a)
(1)p++;使p指向下一元素即a[1],若再执行*p,表示引用a[1]的值。
(2)*p++;++与*同优先级,结合方向自右向左,等价于*(p++),即先得到p所指向的变量的值,*p,再使p+1(指向下一个元素)
for(i=0;i<10;i++,p++)
printf(“%d”,*p);
等价于:
for(i=0;i<10;i++)
printf(“%d”,*p++);
null关于指针变量的计算(3)*(p++)与*(++p)的区别
*(p++)=a[0];
*(++p)=a[1];
(4)(*p)++表示所指向元素的值加1。
例:
有如下说明:
int a[10]={1,2,3,4,5,6,7,8,9,10},*p=a;
则*(p+8)的值是( )null例8.6#include
void main()
{ int *p,i,a[10];
p=a;
for(i=0;i<10;i++)
scanf("%d",p++);
for(i=0;i<10;i++,p++)
printf("%d ",*p);
printf("\n");
}null8.3.4 用数组名作函数参数用数组名作函数的参数时,数组中各元素的值发生
变化,实参数组元素的值会随之变化。
如: void main()
{f(int arr[],int n);
int array[10];
┇
f(array,10);
┇
}
void f(int arr[ ],int n) {...}
等价于void f(int *arr,int n){...}
null例8.7 将数组a中n个整数按相反顺序存放null#include
void main()
{ void inv(int x[ ],int n);
int i,a[10]={3,7,9,11,0,
6,7,5,4,2};
printf(″The original array:\n″);
for(i=0;i<10;i++)
printf (″%d,″,a[i]);
printf(″\n″);
inv (a,10);
printf(″The array has been in verted:\n″);
for(i=0;i<10;i++)
printf (″%d,″,a[i]);
printf (″\n″);
}nullvoid inv(int x[ ],int n) /*形参x是数组名*/
{ int temp,i,j,m=(n-1)/2;
for(i=0;i<=m;i++)
{
j=n-1-i;
temp=x[i];
x[i]=x[j];
x[j]=temp;
}
return;
}运行情况如下:
The original array:
3,7,9,11,0,6,7,5,4,2
The array has been inverted:
2,4,5,7,6,0,11,9,7,3nullnull#include
void main()
{void inv(int *x,int n);
int i,a[10]={3,7,9,11,0,
6,7,5,4,2};
printf( ″The original array:\n″ );
for(i=0;i<10;i++)
printf (″%d,″,a[i]);
printf (″\n″);
inv(a,10);
printf ( ″The array has been in verted:\n″ );
for(i=0;i<10;i++)
printf (″%d,″,a[i]);
printf (″\n″);}对刚才的程序可以作一些改动。将函数inv中的形参x改成指针变量。 nullvoid inv(int *x,int n) /*形参x为指针变量*/
{intp,temp,*i,*j,m=(n-1)/2;
i=x;j=x+n-1;p=x+m;
for(;i<=p;i++,j--)
{temp=*i;*i=*j;*j=temp;}
return;
}null如果有一个实参数组,想在函数中改变此数组中的元素的值,实参与形参的对应关系有以下4种情况: (1) 形参和实参都用数组名,如:
void main() void f(int x[ ],int n)
{ int a[10]; {
… …
f(a,10); }
} null(2) 实参用数组名,形参用指针变量。如:
void main() void f(int *x,int n)
{int a[10]; {
… …
f(a,10); }
}(3)实参形参都用指针变量。例如:
void main() void f(int *x,int n)
{int a[10], *p=a; {
┇ ┇
f(p,10); }
} null(4) 实参为指针变量,形参为数组名。如:
void main() void f(int x[ ],int n)
{int a[10],*p=a; {
┇ ┇
f(p,10); }
} null例8.9 用选择法对10个整数按由大到小顺序排序 #include
void main()
{ void sort(int x[ ],int n);
int*p,i,a[10];
p=a;
for(i=0;i<10;i++)
scanf(″%d″,p++);
p=a;
sort(p,10);
for(p=a,i=0;i<10;i++)
{printf(″%d″,*p);p++;}
}nullvoid sort(int x[ ],int n)
{ int i,j,k,t;
for(i=0;i<n-1;i++)
{k=i;
for(j=i+1;j<n;j++)
if(x[j]>x[k])
k=j;
if(k!=i)
{t=x[i];
x[i]=x[k];
x[k]=t;}
}
} 8.4 通过指针引用字符串 8.4 通过指针引用字符串8.4.1字符串的表示形式 例 8.14 定义一个字符数组,对它初始化,
然后输出该字符串 #include
void main()
{char string[]=″I love China!″;
printf(″%s\n″,string);
} (1) 用字符数组存放一个字符串,然后输出该字符串。null(2) 用字符指针指向一个字符串
可以不定义字符数组,而定义一个字符指针。用字符指针指向字符串中的字符。 例8.15 定义字符指针,使它指向一个字符串。
#include
void main()
{char *string=″ I love China!″;
printf(″%s\n″,string);
}null8.4.3 对使用字符指针变量和字符数组的讨论字符数组和字符指针变量二者之间的区别主要有以下几点:
(1) 字符数组由若干个元素组成,每个元素中放一个字符,而字符指针变量中存放的是地址(字符串第1个字符的地址),决不是将字符串放到字符指针变量中。
null(2)赋值方式。对字符数组只能对各个元素赋值,不
能用以下办法对字符数组赋值。
char str[14];
str=″I love China!″;
而对字符指针变量,可以采用下面方法赋值:
char*a;
a=″I love China!″; null(3)对字符指针变量赋初值:
char *a=″I love China!″;等价于
char*a;
a=″I love China!″;
而对数组的初始化:
char str[14]={″I love China!″};
不能等价于
char str[14];
str[ ]=″I love China!″;null(4) 指针变量的值是可以改变的,例如:例8.19 改变指针变量的值#include
void main()
{char*a=″I love China!″;
a=a+7;
printf(″%s″,a);
}而数组名虽表示数组地址,但它是不能改变的。null8.5 指向函数的指针8.5.1 什么是函数指针 如果在程序中定义了一个函数,在编译时,编译系统为函数代码分配一段存储空间,这段存储空间的起始地址(又称入口地址)称为这个函数的指针。
可以定义一个指向函数的指针变量,用来存放某一函数的起始地址,这就意味着此指针变量指向该函数。null8.5.2 用函数指针变量调用函数 如果想调用一个函数,除了可以通过函数名调用以外,还可以通过指向函数的指针变量来调用该函数。
定义指向函数的指针变量的形式为:
返回类型 (*指针变量名)(形参表列);
如:int (*p)(int,int);
null8.6 返回指针值的函数一个函数可以带回一个整型值、字符值、实型值等,也可以带回指针型的数据,即地址。
这种带回指针值的函数,一般定义形式为
类型名 *函数名(参数表列);
例如:
int *a(int x,int y);null8.7 指针数组和多重指针8.7.1 指针数组的概念一个数组,若其元素均为指针类型数据,称为指针数组,也就是说,指针数组中的每一个元素都相当于一个指针变量。
一维指针数组的定义形式为:
类型名数组名[数组长度];
例如:
int*p[4];null例8.24 将若干字符串按字母顺序(由小到大)输出。#include
#include
void main()
{void sort(char *name[ ],int n);
void print(char *name[ ],int n);
char *name[ ]={"Follow me","BASIC","Great Wall″,"FORTRAN","Computer design"};
int n=5;
sort(name,n);
print(name,n);
}nullvoid sort(char *name[ ],int n)
{char *temp;
int i,j,k;
for(i=0;i<n-1;i++)
{k=i;
for(j=i+1;j<n;j++)
if(strcmp(name[k],name[j])>0)k=j;
if(k!=i)
temp=name[i];
name[i]=name[k];
name[k]=temp;}
}
} nullvoid print(char *name[ ],int n)
{int i;
for(i=0;i<n;i++)
printf(″%s\n″,name[i]);
}运行结果为:
BASIC
Computer design
FORTRAN
Follow me
Great Wallnull8.7.2 指向指针数据的指针定义一个指向指针数据的指针变量:
char**p;
p的前面有两个*号。*运算符的结合性是从右到左,因此**p相当于*(*p),显然*p是指针变量的定义形式。如果没有最前面的*,那就是定义了一个指向字符数据的指针变量。现在它前面又有一个*号,表示指针变量p是指向一个字符指针变量的。*p就是p所指向的另一个指针变量。