华嵌课件-c语言授课及日志_第1页
华嵌课件-c语言授课及日志_第2页
华嵌课件-c语言授课及日志_第3页
华嵌课件-c语言授课及日志_第4页
华嵌课件-c语言授课及日志_第5页
已阅读5页,还剩40页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

地址和指针的概念为了说清楚什么是指针,必须弄清楚数据在内存中是如何存储的,又是如何读取的。内存区的每一个字节有一个编号,这就是“地址”。如果在程序中定义了一个变量,在对程序进行编译时,系统就会给这个变量分配内存单元。1、按变量地址存取变量值的方式称为“直接访问”方式printf(″%d″,i);scanf(″%d″,&i);k=i+j;例如:地址和指针的概念另一种存取变量值的方式称为“间接访问”的方式。即,将变量i的地址存放在另一个变量中。在C语言中,指针变量是一种特殊的变量,它是存放地址的。假设我们定义了一个指针变量i_pointer用来存放整型变量的地址,它被分配地址为(3010)、(3011)、(3012)、(3013)的四个字节。可以通过语句:i_pointer=&i;将i的地址(2000)存放到i_pointer中。这时,

i_pointer的值就是(2000),即变量i所占用单元的起始地址。要存取变量i的值,可以采用间接方式:先找到存放“i的地址”的变量i_pointer

,从中取出i的地址(2000),然后到2000、2001、2002、2003字节取出i的值。指针和指针变量一个变量的地址称为该变量的“指针”。例如,地址2000是变量i的指针。如果有一个变量专门用来存放另一变量的地址(即指针),则它称为“指针变量”。上述的i_pointer就是一个指针变量。指针和指针变量的定义:指针变量的值(即指针变量中存放的值)是地址(即指针)。请区分“指针”和“指针变量”这两个概念。总结变量:命名的内存空间,用于存放各种类型的数据。变量名:变量名是给内存空间取的一个容易记忆的名字。 通过变量名直接访问内存单元变量的地址:变量所使用的内存空间的地址。变量值:在变量单元中存放的数值。即变量的内容。总结地址:内存单元的编号也叫做地址。指针:内存单元地址称为指针,即指针就是地址。指针变量:存放指针(地址)的变量称为指针变量。(间接访问)各种类型变量都有地址,通过地址(指针)或变量名访问变量。直接访问:在程序中使用变量名(变量地址)存取变量值的方式,称为“直接访问”方式。

间接访问:定义一个指针变量来存放了一个变量的地址,通过指针变量存取变量的值,称为“间接访问”方式。指针变量的定义变量的指针和指向变量的指针变量定义一个指针变量定义指针变量的一般形式为基类型*指针变量名;int*ptr;说明指针变量的类型:指明了该指针指向的内存空间所存储的数据类型。定义中的“*”表示所定义的变量是指针变量。变量名是ptr,而非*ptr。指针变量的引用请牢记,指针变量中只能存放地址(指针),不要将一个整数(或任何其他非地址类型的数据)赋给一个指针变量通过指针变量访问整型变量给指针赋值通过&运算符为指针赋值,例如:ptr_var=&var;通过另一个指向相同类型数据项的指针变量对指针进行赋值,例如:ptr_var2=ptr_var;将地址直接赋值给指针变量int*ptr_var3=(int*)malloc(sizeof(int)); malloc()函数申请动态分配内存空间,返回空间首地址; free()函数释放不用内存空间。 给指针变量赋值为符号常量NULL例如:float*ptr_var4=NULL;说明:NULL是一个空指针,表示该指针变量的值没有意义,作用是为了避免对没有被初始化的指针变量的非法引用,NULL的定义在“stdio.h”中。给指针赋值数组的首地址赋予指针变量。 例如:inta[5],*p;p=a;或写为:p=&a[0];或:inta[5],*p=a;字符串首地址赋予指针变量。 例如:char*pc;pc="Hello"; 或写为:char*pc="Hello"; 说明:并不是把整个字符串装入指针变量,而是把存放该字符串的首地址装入指针变量。函数的入口地址赋予指针变量。例如: int(*pf)(void);intfunc(void) pf=func;/*func为函数名*/指针运算符&是取地址运算符(一元运算符),它返回操作数的内存地址例如:intvar=12,*ptr; ptr=&var;*是取内容运算符,是&的反运算符,它也是一元运算符,返回指针指向的内存位置中的值例如:intvar=12,*ptr=&var; inttemp=*ptr; //等价于temp=var;指针运算符对“&”和“*”运算符说明:(“&”和“*”两个运算符的优先级别相同,但按自右而左方向结合)如果已执行了语句pointer_1=&a;pointer_2=&b;(1)pointer_2=&*pointer_1?先进行*

pointer_1的运算,它就是变量a,再执行&运算。&*pointer_1与&a相同,即变量a的地址,就是将&a(a的地址)赋给pointer_2

指针运算符指针运算符(2)

*&a?&*a?先进行&a运算,得a的地址,再进行*运算。即&a所指向的变量,也就是变量a。*&a和*pointer_1的作用是一样的,它们都等价于变量a。即*&a与a等价。(3)

(*pointer_1)++和*pointer_1++*pointer_1++:++和*为同一优先级别,而结合方向为自右而左,因此它相当于*(pointer_1++)。由于++在pointer_1的右侧,是“后加”,因此先对pointer_1的原值进行*运算,得到a的值,然后使pointer_1的值改变,这样pointer_1不再指向a了。(*pointer_1)++:*pointer_1相当a,所以整个表达式相当于a++指针的算术运算只能进行加法和减法运算:+-++--+=-=两种形式:指针±整数或者指针-指针指针与整型值加减的结果是指针,表示使该指针指向该指针下移或上移存储单元个数(整型值)之后的内存地址。存储单元的大小就是该指针的数据类型所需的内存大小。指针与指针的减运算要求相减的两个指针属于同一类型,其结果是整数,表示两个指针之间的数据的个数。//不是字节数例如: intvar,*ptr_var; ptr_var=&var; ptr_var++; 假定var存储在地址1000中,因为整数的长度是4个字节,ptr_var的值将是1004在哪里有使用过指针-指针?指针的算术运算指针递增时,将指向其类型的下一个元素的内存位置,反之亦然操作意义++ptr_var或ptr_var++指向var后面的下一个整数--ptr_var或ptr_var--指向var前面的整数ptr_var+i指向var后面的第i个整数ptr_var-i指向var前面的第i个整数指针比较前提:两个指针都指向相同类型的变量假设ptr_a和ptr_b分别指向a和b操作意义ptr_a<ptr_b如果a存储在b的前面则返回trueptr_a<=ptr_b如果a存储在b的前面,或两个指针指向同一位置则返回trueptr_a==ptr_b如果两个指针指向同一位置则返回trueptr_a!=ptr_b如果两个指针指向不同位置则返回trueptr_a==NULL如果ptr_a是空值则返回true指针按地址传递指针可以作为参数把实参的地址传给形参允许函数访问内存位置被调函数能够修改主调程序的参数的值定义 getstr(char*ptr_str,int*ptr_int);使用 getstr(pstr,&var);指针和一维数组一个数组包含若干元素,每个数组元素都在内存中占用存储单元,它们都有相应的地址。指针变量既然可以指向变量的地址,当然也可以指向数组和数组元素。所谓数组的指针(数组的名称)是指数组的起始地址,也就是第一个元素的地址。数组的指针是个常量指针。数组元素的地址可以用两种方式表示在数组元素前面加“&”符号 &ary[2]数组名+下标 ary+2引用数组元素下标法:inta[8]={2,4,6,8,10,12,14,16};a[i]?指针int*p=a;或者int*p=&a[0];注意:a代表数组首地址,而不是整个数组引用数组元素 *(p+i)、*(a+i)、p[i]、a[i]此时,p++是允许的,a++是错误的。执行p++,p指向下一个元素,即a[1]。*p为a[1]的值。*p++,相当于*p,p++。*(p++)与*(++p)作用不同。(*p)++,表示将p所指向的元素值加1.数组作为参数传递一维数组元素作参数传递时,按值传递整个数组(数组名)当参数传递时,按地址传递,有以下三种等价的写法:voidtest_array(chararray[]);voidtest_array(chararray[LEN]);voidtest_array(char*array);数组作为参数传递归纳起来,如果有一个实参数组,想在函数中改变此数组中的元素的值,实参与形参的对应关系有以下4种情况:(1)形参和实参都用数组名,如:voidmain()voidf(intx[],intn){inta[10];{……

f(a,10);}}(2)实参用数组名,形参用指针变量。如:voidmain()voidf(int*x,intn){inta[10]; {……

f(a,10);} }数组作为参数传递(3)实参形参都用指针变量。例如:voidmain()voidf(int*x,intn){inta[10],*p=a; {……f(p,10); }}(4)实参为指针变量,形参为数组名。如:voidmain()voidf(intx[],intn){inta[10],*p=a;{……f(p,10)}}指向字符串常量的字符指针可以声明字符指针直接指向字符串常量,例如char*pStr=“e”;字符指针pStr将指向字符常量“e”“e”为字符串常量,因此其值不能修改,例如代码pStr[0]=‘h’;将引发一个错误区别字符数组Welcome\0字符串常量不能改变指向字符串变量的字符指针可以使用字符指针来存储和访问字符串声明字符指针语法:char*pStr;声明字符串:charstr[10]=“hello”;使用字符指针指向字符串:pStr=str;可以使用字符指针访问字符串,例如pStr[0]=‘a’;该代码将第一个字符修改为’a’char*pstr="e";charstr[]="e";pstr[0]='h'; str[0]='h';pstr="hello"; str="hello";字符串常量和字符串变量区别字符串常量和字符串变量一样,都是一个一维字符数组。两者的区别在于: 字符串变量的名字(一维字符数组名)及其所需的存储空间是显式定义的,并通过名字来引用相应的字符串变量。而字符串常量所需的存储空间是隐式定义的,并且其根本就没有名字。字符数组和字符指针的区别字符数组字符指针字符数组由若干个元素组成,每一个元素是一个字符。characBuf[]={“hello”};字符指针变量中存放的是字符串的首地址,而不是把字符放到字符指针变量中。char*ptr={“hello”};对于字符数组,只能对各个元素赋值,或者通过strcpy()整体赋值。acBuf=”123”;//错的字符指针变量可以直接通过赋值运算符,使用字符串对整体赋值。char*ptr;ptr=“hello”;新定义的数组在编译时分配内存单元,有确定的地址新定义的指针变量,无具体的值.解决办法是,把一个已定义的字符数组的地址赋给这个指针变量虽然字符数组名也表示数组的首地址,但是却不能通过赋值的方法改变字符指针变量的值是可以改变的,。字符数组和字符指针作返回值#include<stdio.h>char*print(){ characStr[]="helloworld"; returnacStr;}voidmain(){ char*pcStr;pcStr=print();puts(pcStr);}#include<stdio.h>char*print(){ char*pcStr="helloworld"; returnpcStr;}voidmain(){ char*pcStr;pcStr=print();puts(pcStr);}通过指针引用二维数组元素在C语言中,一个二维数组可以看成是一个一维数组,其中每个元素又是一个包含若干元素的一维数组。例如:inta[3][5];a[0]、a[1]和a[2]分别是包含五个元素的一维数组名,分别代表a数组元素的起始地址(即a[0]是第0行元素的首地址,a[1]是第1行元素的首地址)。a[i]和*(a+i)(无条件等价)都是第i行第0列元素的地址,那么a[i]+j、*(a+i)+j、&a[0][0]+3*i+j都是第i行第j列元素的地址。例如:inta[3][5],(*p)[5];p=a;对二维数组的引用有三种方式:下标法。如a[i][j]或p[i][j]。指针针法,如*(*(p+i)+j)或*(*(a+i)+j)。引用二维数组元素(1)用数组名表示二维数组的行地址inta[3][4];假设其首地址为2000 a为二维整型数组名,a=2000。(数组名总是代表数组的首地址) a+0就是第0行的首地址2000。即为a[0] a+1代表第一行首地址。为2008。即为a[1] a+2代表第二行首地址。即2016。即为a[2](2)用数组名表示二维数组元素地址 二维数组中a[0]、a[1]、a[2]都是地址, 则有:*(a+0)、*(a+1)和*(a+2)也是地址,它们分别是第0行、1行和2行的第0列地址。 因此,a[0]+1等介于*(a+0)+1,即&a[0][1]。 a[1]+2等介于*(a+1)+2,即&a[1][2]。 a[2]+3等介于*(a+1)+3,即&a[1][3]。 a[0][1]的值可表示为:*(a[0]+1)和*(*(a+0)+1) a[i][j]的值可表示应为:*(a[i]+j)和*(*(a+i)+j)。指针与二维数组示例#include<stdio.h>#include<stdlib.h>voidmain(){ intaiNum[3][3]={{1,2,3},{4,5,6},{7,8,9}};int(*p)[5];inti,j; p=aiNum; for(i=0;i<3;i++){ for(j=0;j<3;j++) printf("%d\t",*(*(p+i)+j));} putchar('\n');for(i=0;i<3;i++){for(j=0;j<3;j++) printf("%d\t",*(p[i]+j));}putchar('\n');for(i=0;i<3;i++){for(j=0;j<3;j++) printf("%d\t",*(&p[0][0]+i*3+j));}putchar('\n');for(i=0;i<3;i++){for(j=0;j<3;j++) printf("%d\t",(*(p+i))[j]);}putchar('\n');}二维数组作为函数参数当二维数组名作为函数实参时,对应的形参必须是一个行指针变量。和一维数组一样,数组名传送给变量的是一个地址值,因此,对应的形参也必须是一个类型相同的指针变量,在函数中引用的将是主函数中的数组元素,系统只为形参开辟一个存放地址的存储单元,而不可能在调用函数时为形参开辟一系列存放数组的存储单元。intmain(){ intiNum[3][4]; …… fun(iNum); ……}fun(int(*iNum)[4]){ ……}fun(intarray[][4]){ ......}数组元素三种形式引用:⑴a[i][j]下标法⑵*(a[i]+j)用一维数组名⑶*(*(a+i)+j)用二维数组名指针数组指针数组就是其元素为指针的数组每一个元素都是指针变量说明指针数组的语法格式为:数据类型*指针数组名[常量表达式];例如:int*p1[6];指针数组主要用于字符串的操作例如:char*name[3]={“Rose”,“Smith”,“John”};注意:与一个指向二维数组的指针变量的区别,int(*p1)[6]和int*p1[6]之间的区别指针数组的示例#include<stdio.h>intmain(){ inti; char*menu[5]= {"aaa","bbbb","ccc",”dd","ee"}; for(i=0;i<5;i++){ puts(menu[i]); } return0;}char*pmenu[5],menu[5][10]={"aaa","bbbb","ccc",”dd","ee"};for(i=0;i<5;i++) pmenu[i]=menu[i];for(i=0;i<5;i++) puts(pmenu[i]);char(*pmenu)[10],menu[5][10]={"aaa","bbbb","ccc",”dd","ee"};pmenu=menu;for(i=0;i<5;i++){ puts(pmenu[i]);}结构体指针结构体指针是通过在结构体变量名前放置一个星号(*)来进行声明的->运算符用于通过指针来访问结构体的元素示例:structstStudentstStu;structstStudent*pstStu;pstStu=&stStu;printf("%s",pstStu->acName);structstStudent{characName[10]; intiNO;intiAge;};结构体定义时不能定义自身结构体变量,但可以定义自身的指针指针的指针voidmain(){ inti=6,*p,**dp; p=&i; dp=&p; printf(“%4d,%4d,%4d\n”,i,*p,**dp); printf(“%4x,%4x,%4x\n”,&i,p,*dp); printf(“%4x,%4x”,&p,dp);}一种变量专门用来存放指针变量的地址,这种变量我们称之这指针的指针变量语法定义:type**name;示例:变量地址内存值i0x10106………p0x24360x1010………dp0x33440x2436内存示意图函数指针函数在内存中的物理位置-函数的入口点#include<stdio.h>intfun(inta,intb,int(*call)(int,int)){return(call(a,b));}intmain(){printf("max=%d\n",fun(1,2,max));printf("min=%d\n",fun(3,4,min));printf("sum=%d\n",fun(5,6,sum));return0;}指针数据类型小结定义含义int*p;p为指向整型数据的指针变量int*p[n];定义指针数组p,它有n个指向整型数据的指针元素int(*p)[n];p为指向含n个元素的一维数组的指针变量,行指针,数组指针int*p();p为带回一个指针的函数,该指针指向整型数据,函数返回值指针int(*p)();p为指向函数的指针,该函数返回一个整型值,函数指针int**p;p是一个指针变量,它指向一个指向整型数据的指针变量,指针的指针无类型指针无类型指针可以指向任何类型的数据无类型指针定义:void*p;可以将任意类型的指针赋给无类型指针,但不能将无类型指针赋给其它类型指针,如: int*q,*m; p=q; /*允许赋值*/ m=(int*)p; 不能将无类型指针参与算术运算,如:p++;//错误,进行算法操作的指针必须是确定知道其指向的数据类型大小,将其改成:((int*)p)++;则能通过无类型指针主要作用对函数返回的限定(malloc函数)对函数参数的限定(memcpy函数)const限定符最低访问原则——良好的程序设计风格可用于不允许被修改的变量和形式参数,保护实参 voidoutput(constdouble*pd) { printf(“%d”,*pd); /*允许*/ *pd=15.5; /*不允许!*/ }声明const变量时需要初始化constintstuNum=100;指向常量数据的指针指针的值可以改变,无法通过指针修改指向的内容关键字const放在指针类型前例如: inti,j,*q;

constint*p; /*等价于intconst*p;*/ p=&j; /*允许*/ p=&i; /*允许*/ i=10; /*允许*/ *p=5; /*不允许*/

指针常量指针常量又称为常指针指针的值不能修改,指向的内容可以修改关键字const放在“*”号和指针名之间例如:intvar1,var2;int*constp=&var1;*p=5; /*允许*/p=&var2; /*不允许*/指针与动态内存分配1、静态内存分配

当程序中定义变量或数组以后,系统就会给变量或数组按照其数据类型及大小来分配相应的内存单元,这种内存分配方式称为静态内存分配。intk;//系统将给变量k分配4个字节的内存单元charch[10];//系统将给这个数组ch分配10个字节的内存块,首地址就是ch的值静态内存分配一般是在已知道数据量大小的情况下使用

例如,要对10个学生的成绩按降序输出,则可定义一个数组:intscore[10];用于存放10个学生的成绩,然后再进行排序。

如果事先并不知道学生的具体人数,编写程序时,人数由用户输入,然后再输入学生的成绩。那又如何如何处理呢?intn;intscore[n];scanf("%d",&n);如何解决?动态内存分配指针与动态内存分配2、动态内存分配

所谓动态内存分配是指在程序运行过程中,根据程序的实

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论