![第09章 指针-清华大学C语言_第1页](http://file4.renrendoc.com/view/abd53b2dc893b0fa6a386885132c97b4/abd53b2dc893b0fa6a386885132c97b41.gif)
![第09章 指针-清华大学C语言_第2页](http://file4.renrendoc.com/view/abd53b2dc893b0fa6a386885132c97b4/abd53b2dc893b0fa6a386885132c97b42.gif)
![第09章 指针-清华大学C语言_第3页](http://file4.renrendoc.com/view/abd53b2dc893b0fa6a386885132c97b4/abd53b2dc893b0fa6a386885132c97b43.gif)
![第09章 指针-清华大学C语言_第4页](http://file4.renrendoc.com/view/abd53b2dc893b0fa6a386885132c97b4/abd53b2dc893b0fa6a386885132c97b44.gif)
![第09章 指针-清华大学C语言_第5页](http://file4.renrendoc.com/view/abd53b2dc893b0fa6a386885132c97b4/abd53b2dc893b0fa6a386885132c97b45.gif)
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第9章指针制作人:王敬华第9章:指针
学习的意义
语言程序设计教程第二版
第九章指针C
指针是C语言中广泛使用的一种数据类型。
运用指针编程是C语言最主要的风格之一。C程序设计中使用指针可以:
①使程序简洁、紧凑、高效
②有效地表示复杂的数据结构
③动态分配内存
④得到多于一个的函数返回值
⑤能象汇编语言一样处理内存地址,从而编出精练而高效的程序
学习指针是学习C语言中最重要的一环,
能否正确理解和使用指针是我们是否掌握C语言的一个标志,可以说不懂C语言中的指针就不懂什么是C语言。学习目标
理解指针的概念掌握指针变量的定义与引用方法;掌握指针与数组、字符串之间的联系;掌握动态内存分配和释放的方法;掌握带指针型参数和返回指针的函数的定义方法;掌握函数指针的用法;
语言程序设计教程第二版
第九章指针C学习内容
指针与指针变量的概念指针变量的定义和引用指针和地址运算指针与数组数组的指针和指向数组的指针变量指向多维数组的指针____数组指针元素为指针的数组____指针数组指针与字符串指针与动态内存分配多级指针指针与数组作为函数的参数指针作为函数的返回值____指针函数指向函数的指针____函数指针带参数的main函数本章小结
语言程序设计教程第二版
第九章指针C…...内存2000200120022005020032004…...…...…...9.1指针与指针变量的概念1、内存地址──内存中存储单元的编号101102201202301302401402501502601602教学楼教室号码存储地址教室存储单元教室有容量存储单元有大小(字节单元、字单元)50存储数据注意:内存单元的地址与内存单元中的数据是两个完全不同的概念。语言程序设计教程第二版
第九章指针C内存…...…...0200020012002200520032004…...…...2、变量地址──系统分配给变量的内存单元的起始地址程序中:inti;
floatk;
内存中每个字节有一个编号-----地址ik
编译或函数调用时为其分配内存单元变量是对程序中数据存储空间的抽象i的地址k的地址注意:在TC或BC下,系统将给变量i分配2字节的单元,而VC下将是4字节的单元!语言程序设计教程第二版
第九章指针C整型变量i变量i_pointer…...…...1020002004200620052001200220033、指针与指针变量指针:一个变量的地址指针变量:专门存放变量地址的变量2000指针变量整型变量i的内容指针变量i_pointer的内容(是地址)变量的地址指针指针变量变量变量地址(指针)变量值指向地址存入指针变量语言程序设计教程第二版
第九章指针C4、&与*运算符含义含义:取变量的地址单目运算符结合性:自右向左含义:
取指针所指向变量的内容单目运算符结合性:自右向左两者关系:互为逆运算理解200010i_pointer*i_pointer&i_pointerii_pointer&i&(*i_pointer)i*i_pointer*(&i)i_pointer
=
&i
=
&(*i_pointer)i
=
*i_pointer
=
*(&i)…...…...2000200420062005整型变量i10变量i_pointer2001200220032000指针变量i_pointer-----指针变量,它的内容是地址量*i_pointer----指针的目标变量,它的内容是数据&i_pointer---指针变量占用内存的地址语言程序设计教程第二版
第九章指针C直接访问:按变量名来存取变量值间接访问:通过存放变量地址的变量去访问变量例
i=3;-----直接访问指针变量…...…...2000200420062005整型变量i10变量i_pointer20012002200320003例
*i_pointer=20;-----间接访问209.2指针变量的定义和引用
1、变量值的存取方法语言程序设计教程第二版
第九章指针C指针变量…...…...2000200420062005整型变量i10变量i_pointer2001200220032000整型变量k10例
k=i;k=*i_pointer;--直接访问--间接访问语言程序设计教程第二版
第九章指针C2、指针变量与其所指向的变量之间的关系3变量i2000i_pointer*i_pointeri*i_pointer&ii_pointeri=3;*i_pointer=3;3、指针变量的定义一般形式:[存储类型]数据类型符*变量名;合法标识符表示定义指针变量不是‘*’运算符指针的目标变量的数据类型指针变量本身的存储类型注意:
int*p1,*p2;与int*p1,p2;
指针变量名是p1,p2,不是*p1,*p2
指针变量只能指向定义时所规定类型的变量
指针变量定义后,变量值不确定,应用前必须先赋值例
int
*p1,*p2;float*q;staticchar*name;语言程序设计教程第二版
第九章指针C例
inti;int*p=&i;例int*p=&i;
inti;例
voidmain(){inti;staticint*p=&i;..............}()标准C下不能用auto变量的地址去初始化static型指针(但在C++程序中可以)
4、指针变量的赋值初始化赋值[存储类型]
数据类型*指针名=初始地址值;赋给指针变量,不是赋给目标变量变量必须已说明过类型应一致例
inti;int*p=&i;int*q=p;用已初始化指针变量作初值语言程序设计教程第二版
第九章指针C例
inta;int*p;p=&a;赋值语句赋值例
inta=20;int*p,*q;p=&a;
q=p;整型变量a指针变量p指针变量q……...2000…...…...2020002000语言程序设计教程第二版
第九章指针C例
int*p=&a;inta;指针变量赋值的几种错误方法:
变量a的定义在后,对a的引用超出了a的作用域例
inta;int*pi=&a;char*pc=&a;pc不能指向非字符型变量例
inta;int*p;*p=&a;赋值语句中,被赋值的指针变量p的前面不能再加“*”说明符例
int*p;p=2000;不允许直接把一个数赋值给指针变量例
inta;staticint*p=&a;不能用auto变量的地址去初始化static型指针注意:一个指针变量只能指向同类型的变量如果给指针赋值时,=号右边的指针类型与左边的指针类型不同,则需要进行类型强制转换。
inta;
int*pi;char*pc;pi=&a;//pi指向apc=(char*)pi;//pc也指向了a,即pi和pc的值都是a的地址语言程序设计教程第二版
第九章指针C5、零指针与空类型指针零指针:(空指针)
定义:指针变量值为零表示:
int*p=0;
p指向地址为0的单元,系统保证该单元不作它用表示指针变量值没有意义#defineNULL0int*p=NULL:
p=NULL与未对p赋值不同
用途:
避免指针变量的非法引用在程序中常作为状态比较
例int*p;......while(p!=NULL){...…}void*类型指针表示:void*p;
使用时要进行强制类型转换表示不指定p是指向哪一种类型数据的指针变量例
char*p1;void*p2;p1=(char*)p2;p2=(void*)p1;语言程序设计教程第二版
第九章指针C6、引用指针变量inta;int*p=&a;//p指向a*p=10;//相当于a=10;格式:
*指针变量inta,*p;p=&a;*p=10;a++;printf("a=%d,*p=%d",a,*p);输出结果:a=11,*p=11可写成(*p)++,而不是*p++
注意:程序在利用指针间接引用内存单元时,将按照指针变量定义时所指向的数据类型来解释引用的内存单元。语言程序设计教程第二版
第九章指针C【例1】不同类型的指针操作同一内存变量
#include<stdio.h>voidmain(){unsignedshorta;unsignedshort*pi=&a;char*pc=(char*)&a;*pi=0XF0F0;*pc=0;
printf("a=%X",a);}……...2000…...…...整型变量a指针变量pi2000pi可操作单元指针变量pc2000pc可操作单元F0F000输出结果:a=F000语言程序设计教程第二版
第九章指针C【例2】输入两个数,并使其从大到小输出#include<stdio.h>voidmain(){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",a,b);
printf("max=%d,min=%d\n",*p1,*p2);}运行结果:a=5,b=9max=9,min=5…...…...指针变量p1指针变量p20002008200220042006指针变量p2整型变量b整型变量a5200692008200620082006重点强调:指针变量必须先定义,后赋值,最后才能使用!没有赋值的指针变量是没有任何意义的,也绝对是不允许使用的。指针变量只能指向定义时所规定类型的变量。指针变量也是变量,在内存中也要占用一定的内存单元,但所有类型的指针变量都占用同样大小的内存单元,其具体大小取决于所使用的编译环境,如在BC3.1和VC6.0下为4个字节,在TC2.0下为2个字节。语言程序设计教程第二版
第九章指针C1、指针变量的加、减运算9.3指针和地址运算
指针可以参与加法和减法运算,但其加、减的含义绝对不同于一般数值的加减运算。如果指针p是这样定义的:ptype*p;,并且p当前的值是ADDR,那么:p±n的值=ADDR±n*sizeof(ptype)int*pi;char*pc;long*pl;pi=(int*)1000;pc=(char*)1000;pl=(long*)1000;pi++;//pi的值将是1002(假设int型占2byte)pi-=2;//pi的值将是998pc++;//pc的值将是1001pc-=2;//pc的值将是999pl++;//pl的值将是1004pl-=2;//pi的值将是996注意:两个指针相加没有任何意义,但两个指针相减则有一定的意义,可表示两指针之间所相差的内存单元数或元素的个数,在后面的学习中就会体会到。
语言程序设计教程第二版
第九章指针C2、指针变量的关系运算若p1和p2指向同一数组,则
p1<p2表示p1指的元素在前
p1>p2表示p1指的元素在后
p1==p2表示p1与p2指向同一元素若p1与p2不指向同一数组,比较无意义p==NULL或p!=NULL语言程序设计教程第二版
第九章指针C1、数组的指针9.4指针与数组
数组的指针其实就是数组在内存中的起始地址。而数组在内存中的起始地址就是数组变量名,也就是数组第一个元素在内存中的地址。a2000200220042018…...…...a[0]a[1]a[2]a[9]aa+1a+2a+9……例:shortinta[10];inta[10];intk;for(k=0;k<10;k++)
a[k]=k;
//利用数组下标inta[10];intk;for(k=0;k<10;k++)*(a+k)=k;//利用数组的指针注意:a+k
&a[k]*(a+k)a[k]语言程序设计教程第二版
第九章指针C2、指向数组的指针变量9.4指针与数组
如果将数组的起始地址赋给某个指针变量,那么该指针变量就是指向数组的指针变量。例:shortinta[10],p=a;p2000200220042018…...aa+1a+2a+9………...a[0]a[1]a[2]a[9]2000pp+1p+2p+9……*a*(a+1)*(a+2)*(a+9)……*p*(p+1)*(p+2)*(p+9)……p[0]p[1]p[2]p[9]……地址元素
注意:p+1指向数组的下一个元素,而不是简单地使指针变量p的值+1。其实际变化为p+1*size(size为一个元素占用的字节数)。例如,假设指针变量p的当前值为2000,则p+1为2000+1*2=2002,而不是2001。语言程序设计教程第二版
第九章指针Ccharstr[10];intk;for(k=0;k<10;k++)
str[k]='A'+k;
//也可写成*(str+k)='A'+kcharstr[10];intk;char*p;p=str;for(k=0;k<10;k++)
p[k]='A'+k;
//也可写成*(p+k)='A'+k
charstr[10];intk;char*p;p=str;for(k=0;k<10;k++)
*p++='A'+k;
//相当于*p='A'+k;p++;
下面是对数组元素赋值的几种方法,它们从功能上是等价的
执行完后,p仍然指向数组str的首地址执行完后,p指向数组元素str[9]的下一内存单元
注意:数组名是地址常量,切不可对其赋值,也不可做++或--运算。例如:inta[10];如果在程序中出现a++或a--则是错误的。语言程序设计教程第二版
第九章指针Ca[0]a[1]a[2]a[3]a[4]
【例】数组元素的引用方法voidmain(){
inta[5],*pa,i;for(i=0;i<5;i++)
a[i]=i+1;pa=a;for(i=0;i<5;i++)
printf("*(pa+%d):%d\n",i,*(pa+i));for(i=0;i<5;i++)
printf("*(a+%d):%d\n",i,*(a+i));for(i=0;i<5;i++)
printf("pa[%d]:%d\n",i,pa[i]);for(i=0;i<5;i++)
printf("a[%d]:%d\n",i,a[i]);}12345pa语言程序设计教程第二版
第九章指针C例:
inta[]={1,2,3,4,5,6,7,8,9,10},*p=a,i;
数组元素地址的正确表示:
(A)&(a+1)(B)a++(C)&p(D)&p[i]数组名是地址常量p++,p--()a++,a--()a+1,*(a+2)()例:注意指针变量的运算voidmain(){
inta[]={5,8,7,6,2,7,3};
inty,*p=&a[1];
y=(*--p)++;
printf(“%d”,y);
printf(“%d”,a[0]);}58762730123456app6输出结果:56语言程序设计教程第二版
第九章指针Cvoidmain(){
inti,*p,a[7];p=a;for(i=0;i<7;i++)
scanf("%d",p++);
printf("\n");for(i=0;i<7;i++,p++)
printf("%d",*p);}例
注意指针的当前值p=a;pp58762730123456apppppp指针变量可以指到数组后的内存单元语言程序设计教程第二版
第九章指针C#include<stdio.h>voidmain(){shortinta[2][3]={{1,2,3},{4,5,6}};shortinti,j,*p;
p=&a[0][0];
for(i=0;i<2;i++){for(j=0;j<3;j++)
printf("a[%d][%d]=%d",i,j,*(p+i*3+j));
printf("\n");}}3、指向多维数组的指针____数组指针利用指针变量不仅可以引用一维数组,而且也可以引用多维数组。【例】利用一般指针变量对二维数组的引用。200020022004200620082010a[0]a[1]2000a[0][0]1a[0][1]2a[0][2]3a[1][0]4a[1][1]5a[1][2]6pp+1p+2p+3p+4p+5a[0]a[0]+1a[0]+2a[0]+3a[0]+4a[0]+5a[1]a[1]+1a[1]+2地址指针P所占内存单a[0]a[1]
当指针p指向这个二维数组时,其实p就相当于一个一维数组,因此访问二维数组中的元素可分别用p[0]…p[5]或*(p+0)…*(p+5)来表示
注意:假设有一个m行n列的二维数组a:
a[i](i在0到m-1之间)为第i+1行的首地址,是一个地址常量。如上例中的a[0]表示第一行的首地址,当然也是整个二维数组元素所占内存单元的首地址,a[1]表示第二行的首地址。当二维数组的首地址赋给指针变量p以后,则访问某个元素a[i][j]可用以下几种方式来代替:*(p+i*n+j)、p[i*n+j]、*(a[0]+i*n+j)。二维数组名a不可赋值给一般指针变量p,只能赋值给指向二维数组的指针变量。p=a;是非法的。语言程序设计教程第二版
第九章指针C3、指向多维数组的指针____数组指针语言程序设计教程第二版
第九章指针C(1)二维数组的行地址与列地址a[0]a[1]a[2]a+0&a[0]a+1&a[1]a+2&a[2]a[0]+0a[0]+1a[0]+2a[0]+3一维数组a[0]a[0][0]a[0][1]a[0][2]a[0][3]a[1]+0a[1]+1a[1]+2a[1]+3一维数组a[1]a[1][0]a[1][1]a[1][2]a[1][3]a[2]+0a[2]+1a[2]+2a[2]+3一维数组a[2]a[2][0]a[2][1]a[2][2]a[2][3]列地址列地址列地址行地址一维数组ainta[3][4];3、指向多维数组的指针____数组指针语言程序设计教程第二版
第九章指针C
如果将二维数组名a看成一个行地址(第0行的地址),则a+i代表二维数组a的第i行的地址,a[i]可看成一个列地址,即第i行第0列的地址。行地址a每次加1,表示指向下一行,而列地址a[i]每次加1,表示指向下一列。*(*(a+i)+j)a:第0行的地址a+i:第i行的地址*(a+i):即a[i],第i行第0列的地址*(a+i)+j:即&a[i][j],第i行第j列的地址*(*(a+i)+j):即a[i][j],第i行第j列的元素对于二维数组:(1)a是数组名,包含三个元素
a[0],a[1],a[2](2)每个元素a[i]
又是一个一维数组,包含4个元素aa+1a+2*(*(a+0)+1)*(a[0]+1)inta[3][4];a[0]a[1]a[2]200020082016200020022008201020162018a[0][0]a[0][1]a[1][0]a[1][1]a[2][0]a[2][1]a[0][2]a[0][3]a[1][2]a[1][3]a[2][2]a[2][3]基类型行指针与列指针a[0]+1a[1]+1a[2]+1*(a+0)+1*(a+1)+1*(a+2)+13、指向多维数组的指针____数组指针二维数组的理解:语言程序设计教程第二版
第九章指针Ca+i=&a[i]=a[i]=*(a+i)=&a[i][0],
值相等,含义不同a+i
&a[i],表示第i行首地址,指向行a[i]*(a+i)&a[i][0],表示第i行第0列元素地址,指向列inta[3][4];200020022008201020162018a[0][0]a[0][1]a[1][0]a[1][1]a[2][0]a[2][1]a[0][2]a[0][3]a[1][2]a[1][3]a[2][2]a[2][3]a[0]a[1]a[2]200020162008aa+1a+2二维数组的理解:对二维数组inta[3][4],有:a-----二维数组的首地址,即第0行的首地址a+i-----第i行的首地址a[i]*(a+i)------第i行第0列的元素地址a[i]+j
*(a+i)+j-----第i行第j列的元素地址*(a[i]+j)*(*(a+i)+j)a[i][j]语言程序设计教程第二版
第九章指针Cinta[3][4];a[0][0]a[0][1]a[1][0]a[1][1]a[2][0]a[2][1]a[0][2]a[0][3]a[1][2]a[1][3]a[2][2]a[2][3]二维数组元素表示形式:(1)a[1][2](2)*(a[1]+2)(3)*(*(a+1)+2)(4)*(&a[0][0]+1*4+2)地址表示:(1)a+1
(2)&a[1][0](3)a[1](4)*(a+1)(5)(int*)(a+1)行指针列指针地址表示:(1)&a[1][2](2)a[1]+2(3)*(a+1)+2(4)&a[0][0]+1*4+2二维数组的理解:语言程序设计教程第二版
第九章指针C表示形式含义地址a二维数组名,数组首地址a[0],*(a+0),*a第0行第0列元素地址a+1第1行首地址a[1],*(a+1)第1行第0列元素地址a[1]+2,*(a+1)+2,&a[1][2]第1行第2列元素地址*(a[1]+2),*(*(a+1)+2),a[1][2]第1行第2列元素值2000200020082008201213二维数组的理解:语言程序设计教程第二版
第九章指针C3、指向多维数组的指针____数组指针指向二维数组的行指针变量的定义格式:
数据类型符(*指针变量名)[常量表达式];二维数组第二维的大小
括号不能省例:inta[2][3];
int(*p)[3];()
int*p[3];()
int(*p)[2];()语言程序设计教程第二版
第九章指针C(2)通过二维数组的行指针来访问二维数组【例】利用指向二维数组的行指针变量对二维数组的引用。#include<stdio.h>voidmain(){shortinta[2][3]={{1,2,3},{4,5,6}};
shortint(*p)[3];shortinti,j;p=a;for(i=0;i<2;i++){for(j=0;j<3;j++)
printf("a[%d][%d]=%d",i,j,p[i][j]);
printf("\n");}p++;
for(j=0;j<3;j++)
printf("%d",p[0][j]);}200020022004200620082010a[0]a[1]p2000a[0][0]1a[0][1]2a[0][2]3a[1][0]4a[1][1]5a[1][2]6a[0](2000)a[1](2006)看成一维数组p++后p的指向p=a运行结果:a[0][0]=1a[0][1]=2a[0][2]=3a[1][0]=4a[1][1]=5a[1][2]=6456*(*p+i*3+j)或(*p+i*3)[j]注意:对指向二维数组的行指针变量进行赋值一般形式为:
(1)二维数组名+整型常数n,如:p=a+1;或
(2)&二维数组名[整型常量n],如:p=&a[1]。不可用数组单元地址对其赋值。如:p=a[0];或p=&a[0][0]都是错误的。语言程序设计教程第二版
第九章指针C4、元素为指针的数组____指针数组
当某个数组单元都是指针型数据时,这个数组被称为指针数组。其定义的一般格式为:数据类型符*变量名[常量表达式];例:
charc[3]={'a','b','c'};
char*p[3];p[0]=&c[0];p[1]=&c[1];p[2]=&c[2];指针数组p200020012002数组cc[0]
'a'c[1]
'b'c[2]
'c'p[0]2000p[1]2001p[2]2002语言程序设计教程第二版
第九章指针C4、指针数组与数组指针的比较int*p[3];①表明p是数组变量②表明p中的单元都是指针③表明p中的单元都是int型的指针指针数组int(*p)[3];①表明p是指针变量②表明p指向大小为3的数组③表明p指向的数组是int型数组数组指针指针数组二维数组指针变量定义int*p[20];int(*p)[20];变量性质p是数组名,不是指针变量,不可对p赋值P是指针变量,不是数组名,可对p赋值语言程序设计教程第二版
第九章指针C【例】利用指针数组对键盘输入的5个整数进行从小到大排序。#include<stdio.h>voidmain(){
inti,j,t;
inta,b,c,d,e;
//将a,b,c,d,e的内存地址分别赋给p[0]...p[4]
int*p[5]={&a,&b,&c,&d,&e};//对a,b,c,d,e赋值
scanf("%d,%d,%d,%d,%d",p[0],p[1],p[2],p[3],p[4]);for(i=0;i<4;i++)//利用冒泡法排序
for(j=i+1;j<5;j++)if(*p[i]>*p[j])//交换p[i]、p[j]所指向的变量值
{t=*p[i];*p[i]=*p[j];*p[j]=t;}for(i=0;i<5;i++)//显示排序后的结果
printf("%d",*p[i]);}运行结果(假设输入:38764):34678语言程序设计教程第二版
第九章指针C20002010202020302040变量所占内存单元(不一定连续)abcdep[0]2000p[1]2010p[2]2020p[3]2030p[4]2040指针数组p(占用连续的存储单元)注意:该方法是将a,b,c,d,e所对应的内存单元的值进行交换,而指针数组并无变化。问:如果a,b,c,d,e的值不变,能否进行排序?语言程序设计教程第二版
第九章指针C9.5指针与字符串1、字符串表示形式用字符数组实现例:voidmain(){charstring[]=“IloveChina!”;
printf(“%s\n”,string);
printf(“%s\n”,string+7);}IloveChistring[0]string[1]string[2]string[3]string[4]string[5]string[6]string[7]string[8]string[9]stringstring[10]string[11]string[12]string[13]n!a\0运行结果:IloveChina!China!语言程序设计教程第二版
第九章指针C用字符指针实现例:
voidmain(){
char*string=“IloveChina!”;
printf(“%s\n”,string);
string+=7;while(*string){
putchar(string[0]);string++;}}IloveChistringn!a\0字符指针初始化:把字符串首地址赋给stringchar*string;string=“IloveChina!”;string*string!=0运行结果:IloveChina!China!整体引用逐个字符引用语言程序设计教程第二版
第九章指针C2、字符指针变量与字符数组char*cp;与
charstr[20];
str由若干元素组成,每个元素放一个字符;而cp中存放字符串首地址
charstr[20];str=“IloveChina!”;()char*cp;cp=“IloveChina!”;()
str是地址常量;cp是地址变量
cp接受键入字符串时,必须先开辟存储空间例
charstr[10];
scanf(“%s”,str);()而
char*cp;
scanf(“%s”,cp);()改为:char*cp,str[10];cp=str;
scanf(“%s”,cp);()语言程序设计教程第二版
第九章指针C3、字符串与数组关系字符串用一维字符数组存放字符数组具有一维数组的所有特点数组名是指向数组首地址的地址常量数组元素的引用方法可用指针法和下标法数组名作函数参数是地址传递等区别存储格式:字符串结束标志赋值方式与初始化输入输出方式:%s%ccharstr[]={“Hello!”};()charstr[]=“Hello!”;()charstr[]={‘H’,‘e’,‘l’,‘l’,‘o’,‘!’};()char*cp=“Hello”;()inta[]={1,2,3,4,5};()int*p={1,2,3,4,5};()charstr[10],*cp;inta[10],*p;str=“Hello”;()cp=“Hello!”;()a={1,2,3,4,5};()p={1,2,3,4,5};()scanf(“%s”,str);printf(“%s”,str);gets(str);puts(str);语言程序设计教程第二版
第九章指针C4、字符指针变量使用注意事项当字符指针指向字符串时,除了可以被赋值之外,与包含字符串的字符数组没有什么区别。charstr[10],*pstr;pstr="12345";//pstr指向"12345"strcpy(str,pstr);//将pstr所指向的字符串复制到数组str中pstr=str;printf("TheLengthofstris:%d\n",strlen(pstr));//输出字符串的长度5注意“野指针”操作:如果一个指针没有指向一个有效内存就被引用,则被称为“野指针”操作或空指针赋值。野指针操作尽管编译时不会出错,但很容易引起程序运行时表现异常,甚至导致系统崩溃。char*pstr;charstr[8];scanf("%s",pstr);//野指针操作,pstr没有指向有效内存strcpy(pstr,"hello");//野指针操作pstr=str;//pstr指向数组str所对应内存单元的首地址strcpy(pstr,"0123456789");//不是野指针,但会造成数组越界
为什么“野指针”操作会给程序运行带来极大的不确定性,甚至造成系统崩溃呢?语言程序设计教程第二版
第九章指针C系统程序区0001pstr0001指针pstr所占内存char*pstr;pstr=‘a’;随机值,有可能指向系统程序区假设首地址为0001此时对pstr指向的内存单元赋值极其危险!为什么“野指针”赋值会给程序运行带来极大的危险?再次提醒:指针变量只有与内存建立联系以后才可使用,否则将造成程序运行异常,甚至导致系统死机!语言程序设计教程第二版
第九章指针C【例】利用字符指针实现字符串的倒序排列
#include<stdio.h>#include<string.h>voidmain(){charstr[200],ch;char*p,*q;gets(str);//读取一个字符串
p=str;//p指向字符串的首地址
q=p+strlen(p)-1;//q指向字符串的末地址
while(p<q){//交换p和q各自指向的字符
ch=*p;//将p所指向的字符保存在ch中*p++=*q;//先将q指向的字符赋给p指向的字符单元,p再增1*q--=ch;//先将ch的值赋给q指向的字符单元,q再减1}
printf("%s\n",str);}运行结果:IloveChina!↙!anihC
evolI语言程序设计教程第二版
第九章指针C'I''''L''o''v''e''''C''h''i''n''a''!'0strpq
p=str;q=p+strlen(p)-1交换'!''I'pq交换'a'pq交换'n''L'pq交换'i''o'pq交换'h''v'''pq'C''e'交换pq''End程序执行过程演示:语言程序设计教程第二版
第九章指针C字符串指针数组与字符串二维数组之间的区别
charstr[3][10]={"Wuhan","Beijing","Shanghai"};char*pstr[3];pstr[0]=str[0];pstr[1]=str[1];pstr[2]=str[2];pstr[0]pstr[1]pstr[2]'W''u''h''a''n'00000'B''e''i''j''i''n''g'000'S''h''a''n''g''h''a''i'00pstrstr字符串结束标志多余空位补0语言程序设计教程第二版
第九章指针C定义字符指针数组时直接用字符串对其赋初始值
char*pstr[3]={"Wuhan","Beijing","Shanghai"};pstr[0]pstr[1]pstr[2]'W''u''h''a''n'0'B''e''i''j''i''n''g'0'S''h''a''n''g''h''a''i'0pstrstr字符串结束标志语言程序设计教程第二版
第九章指针C#include<stdio.h>#include<string.h>voidmain(){
inti,j,k;
char*pcity[]={"Wuhan",Beijing","Shanghai","Tianjin","Guangzhou",""};
char*ptemp;for(i=0;strcmp(pcity[i],"")!=0;i++){k=i;for(j=i+1;strcmp(pcity[j],"")!=0;j++)if(strcmp(pcity[k],pcity[j])>0)k=j;if(k!=i){ptemp=pcity[i];pcity[i]=pcity[k];pcity[k]=ptemp;}}【例】利用字符指针数组对一组城市名进行升序排列。运行结果:BeijingGuangzhouShanghaiTianjin
Wuhan
for(i=0;strcmp(pcity[i],"")!=0;i++)printf("%s",pcity[i]);
printf("\n");}选择排序语言程序设计教程第二版
第九章指针C9.6指针与动态内存分配1、静态内存分配
当程序中定义变量或数组以后,系统就会给变量或数组按照其数据类型及大小来分配相应的内存单元,这种内存分配方式称为静态内存分配。intk;//系统将给变量k分配2个字节(VC下分配4个字节)的内存单元charch[10];//系统将给这个数组ch分配10个字节的内存块,首地址就是ch的值静态内存分配一般是在已知道数据量大小的情况下使用
例如,要对10个学生的成绩按降序输出,则可定义一个数组:intscore[10];
用于存放10个学生的成绩,然后再进行排序。
如果事先并不知道学生的具体人数,编写程序时,人数由用户输入,然后再输入学生的成绩。那有如何如何处理呢?intn;int
score[n];scanf("%d",&n);如何解决?动态内存分配语言程序设计教程第二版
第九章指针C2、动态内存分配
所谓动态内存分配是指在程序运行过程中,根据程序的实际需要来分配一块大小合适的连续的内存单元。程序可以动态分配一个数组,也可以动态分配其它类型的数据单元。动态分配的内存需要有一个指针变量记录内存的起始地址。
(1)malloc
函数malloc()用于分配若干个字节的内存空间,返回一个指向该存储区地址的指针。其函数的原型为:void*malloc(unsignedintsize);说明:size这个参数的含义是分配的内存的大小(以字节为单位)。返回值:失败,则返回值是NULL(空指针)。成功,则返回值是一个指向空类型(void)的指针(即所分配内存块的首地址)。语言程序设计教程第二版
第九章指针C2、动态内存分配
intn,*pscore;scanf("%d",&n);//分配n个连续的整型单元,首地址赋给pscorepscore=(int*)malloc(n*sizeof(int));//分配内存失败,则给出错误信息后退出if(pscore==NULL){
printf("Insufficientmemoryavailable!");exit(0);}……//可对pscore所指向的单元进行其它处理例如:根据学生人数来建立数组的问题可以用动态内存分配来解决,其方法如下:动态分配的内存块0100pscore0100
共n*sizeof(int)个字节内存单元语言程序设计教程第二版
第九章指针C关于malloc的使用有几点需强调一下:malloc前面必须要加上一个指针类型转换符,如前面的(int*)。因为malloc的返回值是空类型的指针,一般应与右边的指针变量类型一致。malloc所带的一个参数是指需分配的内存单元字节数,尽管可以直接用数字来表示,但一般写成如下形式:分配数量*sizeof(内存单元类型符)malloc可能返回NULL,表示分配内存失败,因此一定要检查分配的内存指针是否为空,如果是空指针,则不能引用这个指针,否则会造成系统崩溃。所以在动态内存分配的语句的后面一般紧跟一条if语句以判断分配是否成功。语言程序设计教程第二版
第九章指针C语言程序设计教程第二版
第九章指针C
(2)calloc
函数calloc()用于给若干个同一类型的数据项分配连续的存储空间,其中每个数据项的长度单位为字节。通过调用函数calloc()所分配的存储单元,系统将其自动置初值0。其函数的原型为:void*calloc(unsignedintnum,unsignedintsize);说明:num表示向系统申请的内存空间的数量,size表示申请的每个内存空间的字节数。如果分配内存失败,将返回空指针(NULL);如果成功,将返回一个void类型的连续存储空间的首地址。intn,*pscore;scanf("%d",&n);//分配n个连续的整型单元,首地址赋给pscorepscore=(int*)calloc(n,sizeof(int));//分配内存失败,则给出错误信息后退出if(pscore==NULL){
printf("Insufficientmemoryavailable!");exit(0);}……//可对pscore所指向的单元进行其它处理语言程序设计教程第二版
第九章指针C
(3)ralloc
函数realloc()用于改变原来分配的存储空间的大小。
其函数的原型为:void*realloc(void*p,unsignedintsize);
功能:将指针p所指向的存储空间的大小改为size个字节。
返值:如果分配内存失败,将返回空指针(NULL);如果成功,将返回新分配的存储空间的首地址,该首地址与原来分配的首地址不一定相同。
函数realloc()主要应用场合是:当先前通过动态内存分配的存储空间因实际情况需要进行扩充或缩小时,就可以使用函数realloc()来解决,其好处是原存储空间中的数据值能保持不变。例如有下列程序段:语言程序设计教程第二版
第九章指针Cchari,*p;p=(char*)malloc(4*sizeof(char));for(i=0;i<4;i++)*(p+i)=i+1;1234p4字节6字节1234p=(char*)realloc(p,6*sizeof(char));p3、动态内存释放计算机中最宝贵的资源就是内存。因此需要动态分配内存的程序一定要坚持“好借好还,再借不难”的原则。释放动态内存的函数free其原型为:voidfree(void*block);例:free(pscore);
注意:调用malloc,calloc,realloc和free函数的源程序中要包含stdlib.h或malloc.h或alloc.h(在TC、BC下)。malloc或calloc或realloc与free一般成对出现!语言程序设计教程第二版
第九章指针C【例】编写程序先输入学生人数,然后输入学生成绩,最后输出学生的平均成绩、最高成绩和最低成绩。
#include<stdio.h>#include<stdlib.h>#include<malloc.h>voidmain(){
intnum,i;
int
maxscore,minscore,sumscore;
int*pscore;floataverscore;
printf("inputthenumberofstudent:");
scanf("%d",&num);if(num<=0)return;
pscore=(int*)malloc(num*sizeof(int));
if(pscore==NULL){
printf("Insufficientmemoryavailable\n");exit(0);}
printf("inputthescoresofstudentsnow:\n");for(i=0;i<num;i++)
scanf("%d",pscore+i);
maxscore=pscore[0];
minscore=pscore[0];
sumscore=pscore[0];for(i=1;i<num;i++){if(pscore[i]>maxscore)
maxscore=pscore[i];if(pscore[i]<minscore)
minscore=pscore[i];
sumscore=sumscore+pscore[i];}
averscore=(float)sumscore/num;
printf("----------------------------------------------\n");
printf("theaveragescoreofthestudentsis%.1f\n",
averscore);
printf("thehighestscoreofthestudentsis%d\n",
maxscore);
printf("thelowestscoreofthestudentsis%d\n",
minscore);
free(pscore);
//释放动态分配的内存}运行结果:inputthenumberofstudent:4↙inputthescoresofstudentsnow:45768894↙----------------------------------------------theaveragescoreofthestudentsis75.8thehighestscoreofthestudentsis94thelowestscoreofthestudentsis45语言程序设计教程第二版
第九章指针C9.7多级指针定义:指向指针的指针一级指针:指针变量中存放目标变量的地址p1&p2&i3p2(指针变量)i(整型变量)例
int
**p1;
int*p2;
inti=3;p2=&i;p1=&p2;**p1=5;二级指针:指针变量中存放一级指针变量的地址例
int*p;
inti=3;p=&i;*p=5;&i3p(指针变量)i(整型变量)一级指针单级间接寻址二级指针一级指针目标变量二级间接寻址语言程序设计教程第二版
第九章指针C定义形式:[存储类型]数据类型**指针名;如char**p;例
inti,**p;p=&i;()//p是二级指针,不能用变量地址为其赋值指针本身的存储类型最终目标变量的数据类型*p是p间接指向对象的地址**p是p间接指向对象的值例
inti=3;
int*p1;
int
**p2;p1=&i;p2=&p1;**p=5;p1p2i3**p2,*p1*p2多级指针例三级指针int***p;
四级指针char****p;108020002020108020005语言程序设计教程第二版
第九章指针C【例】利用二级指针来处理字符串#include<stdio.h>#defineNULL0voidmain(){char**p;char*name[]={"hello","good","world","bye",""};p=name+1;
printf("%x:%s",*p,*p);p+=2;while(**p!=NULL)
printf("%s\n",*p++);}name[0]name[1]name[2]name[3]name[4]'h''e''l''l''o'0
'g''o''o''d'0
'w''o''r''l''d'0'b''y''e'00
p运行结果:42003C:goodpbyep用*p可输出地址(%o或%x),也可用它输出字符串(%s)注意:二级指针与指针数组的关系:int**p与int*q[10指针数组名是二级指针常量;
p=q;p+i是q[i]的地址;指针数组作形参时,int*q[]与int**q完全等价;但作为变量定义两者不同。系统只给p分配能保存一个指针值的内存区;而给q分配10块内存区,每块可保存一个指针值。语言程序设计教程第二版
第九章指针C9.7指针作为函数的参数
参数传递方式:传值
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年中国纳米级碳酸钙行业供需态势、竞争格局及投资前景分析报告(智研咨询)
- 《计算机网络基础与应用(第三版)》 课件 项目七 互联网的接入
- 初中数学综合实践活动课案例
- 消化内科危重症用药课件
- 儿童诺如病毒患者护理查房
- 《Ysg外科感染》课件
- (高清版)DB37∕T 3007-2017 金针菇菌渣蔬菜(茄果类·辣椒)集约化育苗技术规程
- 《胸痛中心的概念》课件
- 《项目的选择》课件
- 《黄芪冬虫夏草》课件
- 学前教育钢琴基础介绍课件
- 桥式起重机日常检查保养记录表
- 五年级小数乘法竖式计算300道(可直接打印)
- 半导体制造技术导论
- 英语演讲技巧和欣赏课件
- 物流托运单模板
- CNC设备具体参数
- 湿式石灰石法烟气脱硫的工艺流程
- 7S目视化管理标准
- 酒店成本管理系统PICC
- 文科学术规范与学术论文写作课件
评论
0/150
提交评论