资源预览内容
第1页 / 共65页
第2页 / 共65页
第3页 / 共65页
第4页 / 共65页
第5页 / 共65页
第6页 / 共65页
第7页 / 共65页
第8页 / 共65页
第9页 / 共65页
第10页 / 共65页
亲,该文档总共65页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
再论指针和数组,附录一,预习检查,链表单元有哪几个部分组成 如何申请链表单元,及释放链表单元 实现单链表插入的基本语法 简述一下快速排序基本理论要点,课程目标,本章概述 指针与数组什么时候相同 C语言为什么把数组参数当作指针 C语言的多维数组,及如何创建动态数组。 本章目标 掌握指针什么时候和数组相同,以为容易混淆的原因 掌握多维数组的内存布局。 使用指针向函数传递多维数组参数 使用指针返回多维数组 使用指针创建和使用动态数组 重点 指针和数组混淆的原因 指针传递多维数组参数 难点 指针和数组混淆的原因 创建和使用动态数组,本章结构,指针与数组不相同,再论指针和数组,指针数组和数组指针,指针与数组相同,函数指针和指针函数,怎样使用数组,指针运算,1 再论指针和数组,指针与数组的不相同 指针与数组的相同 怎样使用指针 指针运算 函数指针和指针函数 指针数组和数组指针,1.1 指针与数组的不相同,数组和指针是如何访问的 数组访问指针数据 使声明与定义相匹配 数组和指针的其他区别,1.1.1数组和指针是如何访问的,申明区别 extern int *x; 声明x是个int型的指针 extern int y y是个int型数组,长度尚未确定 地址和内容的区别,1.1.1数组和指针是如何访问的,数组下标引用特点 地址在编译时可知 直接进行操作 例: 数组:char a9“abedefgh”; . 取值:c=ai,编译器符号表具有一个地址9980,运行步骤: 取i的值,将它与9980相加 取地址(9980i)的内容。,图A,1.1.2 数组访问指针数据,指针访问特点 必须首先在运行时取得它的当前值 间接进行操作 例: 指针:char *p 取值:c=*p,编译器符号表有一个符号p,它的地址为4624,运行步骤: 取地址4624的内容,就是5081 取地址5081的内容 。,5081,4642,图B,1.1.2 数组访问指针数据,数组访问指针特点 对内存进行直接的引用转化为间接引用 例: 数组:char a9“abedefgh”; . 取值:c=ai,编译器符号表有一个符号p,它的地址为4624,运行步骤: 1. 取地址4624的内容,即5081。 2. 取得i的值,并将它与5081相加。 3. 取地址508l+i的内容。,5081,4642,5081+i,图C,1.1.2 数组访问指针数据,指针访问特点 char *p=“abcdefgh”;p3 d char a=”abcdefgh”; a3 d 访问特点 取得符号表中P的地址,提取存储于此处的指针。 把下标所表示的偏移量与指针的值相加,产生一个地址。 访问上面这个地址,取得字符。,1.1.3 数组和指针的其他区别,1.2 指针与数组的相同,什么时候指针与数组相同 混淆的原因 数组和指针规则 为什么C语言把数组形参当作指针 数组与指针归纳总结,1.2.1 什么时候指针与数组相同,数组运用特性 数组声明 外部数组(external array)的声明 数组的定义 函数参数的声明 运用特性 作为函数参数的数组名可以通过编译器转换为指针 使用数组时,数组可以写成指针 ,可以互换,1.2.1 什么时候指针与数组相同,数组与指针 编译器处理时是不同的 一个数组就是一个地址 一个指针就是一个地址的地址 在运行时的表示形式也是不一样的 可能产生不同的代码,1.2.2 数组和指针混淆的原因,分析:,char my _array10 char* my_ptr ; . j = strlen(my_array); J = strlen(my_ptr); printf(”s s”,my_ptr,my_array);,1.2.2 数组和指针混淆的原因,数组和指针是相同的规则 表达式中的数组名(与声明不同)被编译器当作一个指向该数组第一个元素的指针1。 下标总是与指针的偏移量相同 在函数参数的声明中,数组名被编译器当作指向该数组第一个元素的指针,1.2.3 数组和指针规则,“表达式中的数组名”就是指针 C语言把数组下标作为指针的偏移量 “作为函数参数的数组名”等同于指针,1.2.3.1 “表达式中的数组名”就是指针,数组下标的引用 一个指向数组的起始地址的指针加上偏移量” 下标值的步长调整到数组元素的大小 整型数的长度是4个字节,那么ai+1和ai在内存中的距离就是4(而不是1) 例:访问ai: int a10; int*p; Int i=2 ;,p = a; pi;,p = a; *(p+i);,p = a+i; *p;,访问数组第i个元素的三张方式,1.2.3.1 “表达式中的数组名”就是指针,数组的引用不能用指向该数组第一个元素的指针规则 数组作为sizeof()的操作数一显然此时需要的是整个数组的大小,而不是指针所指向的第一个元素的大小。 使用 c=pi Func(char *p); c=pi 编译器符号表显示p可以取址,从堆栈指针sp偏移14个位置运行时 步骤1:从sp偏移14个位置找到函数的活动记录,取出实参。 步骤2:取i的值,并与5081相加。 步骤3:取出地址(508i)的内容。,1.2.4 为什么C语言把数组形参当作指针,数组,指针实参的一般用法,1.2.5 数组与指针归纳总结,用ai这样的形式对数组进行访问总是被编译器“改写”或解释为像*(a+1)这样的指针访问。 指针始终就是指针。它绝不可以改写成数组。 在特定的上下文中,也就是它作为函数的参数(也只有这种情况),一个数组的声明可以看作是一个指针。作为函数参数的数组(就是在一个函数调用中)始终会被编译器修改成为指向数组第一个元素的指针。 当把一个数组定义为函数的参数时,可以选择把它定义为数组,也可以定义指针。不管选择哪种方法,在函数内部事实上获得的都是一个指针。 定义和声明必须匹配,1.3 怎样使用数组,多维数组 向函数传递一个多维数组 从函数返回一个数组,1.3.1 多维数组,多维数组特性 多维数组内存布局 如何分解多维数组 如何对数组进行初始化,1.3.1.1 多维数组特性,定义和引用多维数组惟一的方法就是使用数组的数组 注意:ijk 与I,j,k 多维数组看作是一种向量 多维数组的定义 声明一个1020的多维字符数组 char carrot1020; 或者声明一种看上去更像“数组的数组”形式: typedef char vegetable20; vegetable carrot10; 不论哪种情况,访问单个字符都是通过carrotij的形式, 编译器在编译时会把它解析为*(*(carrot+i)+j)的形式,1.3.1.2 多维数组的内存布局,多维数组内存布局 pea12的内存表示:线性存储 表达式为:*(*(pea+i)+j),Pea0,Pea1,Pea1,Pea1,Pea0 1 2 3,Pea12,1.3.1.3 如何分解多维数组,分解特点: 多维数组是如何分解为几个单独的数组的 多维数组每一个单独的数组都可以看作是一个指针 不能把一个数组赋值给另一个数组 多维数组分解 int apricot235 sizeof(apricot) 区域 sizeof(apricoti) sizeof(apricotij) sizeof(apricotijk),1.3.1.4 如何对数组进行初始化,嵌套的花括号进行初始化多维数组 如 short cantaloupe25= 10,12,3,4,一5, 31,22,6,0,-5, ; 如 int rhubarb3=0,0,0,1,1,1,;,1.3.1.4 如何对数组进行初始化,建立指针数组进行初始化多维数组 如 如,只有字符串常量才可以初始化指针数组 指针数组不能由非字符串的类型直接初始化 int *weights= 1,2,3,4,5, 6,7, 8,9,10 ;,char vegetables 9 = “carrot”, “celery”, “corn”, “cilantro”, “crispy fried patatoes”,char *vegetables= “carrot”, “celery”, “corn”, “cilantro”, “crispy fried patatoes” ,1.3.1.4 如何对数组进行初始化,建立数组进行初始化多维数组 如:,int row_1=1,2,3,4,5,-1; *一1是行结束标志* int row_2=6,7,-1; int row_3=8,9,10,-1; int *weight= row_1, row_2, row_3 ;,1.3.2 向函数传递一个多维数组,方法1 模式:my_function(int my_array1020); 特点: 最简单的方法 作用最小的 例子,int a33 = 1, 1, 1, 2, 2, 2, 3, 3, 3 ; / 函数定义 void Func(int array33); ,Main() / 函数调用 Func(a33); ,1.3.2 向函数传递一个多维数组,方法2 模式:my_function(int my_array20) ; 例: 方法3 (指针传递模式) 模式:my_function(char *my_array),int a33 = 1, 1, 1, 2, 2, 2, 3, 3, 3 ; / 函数定义 void Func(int *array); ,Main() / 函数调用 Func(a); ,1.3.3 从函数返回一个数组,怎样返回一个数组 一个指向任何数据结构的指针 一个指向数组的指针 例:,int(*pal()20; int(*pal()20 /*声明一个指向包含20个int元素的数组的指针*/ int(*pear)20; pear=calloc(20,sizeof(int); if(!pear)longjmp(error,1); return pear; ,阶段小节,数组在什么时候和指针相同 数组与指针混淆原因是什么 数组当作函数传递的好处是什么 如何向一个函数传递一维数组,1.4 指针运算,什么是间接引用 最多可以使用几层指针 void指针与空指针 指针运算,1.4.1 什么是间接引用,间接引用: 指向变量或内存中的对象的指针 指针就是对对象值的间接引用 一个间接引用的例子,#include Int main() int i; int * p ; i = 5; p = / * see FAQ XVI. 4 * / ,1.4.2 最多可以使用几层指针,一个指针时最多可以包含几层间接引用 至少可以有12层 如: 最多可以使用多少层指针而不会使程序变得难读 不要使用两层以上的指针 程序运行时最多可以有几层指针 无限层,int i = 0; int * ip0l = ,1.4.2 最多可以使用几层指针,例:一个有无限层间接引用的循环链表,/*Would run forever if you didnt limit it to MAX */ # include struct circ_list char value 3 ; struct circ_list * next; ; struct circ_list suffixes = th , ,# define MAX 20 main() int i = 0; struct circ_list *p = suffixes; while (i value); + +i; p = p-next; ,1.4.3 void指针与空指针,什么是空指针 什么是void指针 NULL总是被定义为0吗,1.4.3.1 什么是空指针,空指针 并不指向任何对
收藏 下载该资源
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号