C语言详解指针和数组
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
1.1 指针与数组的不相同
数组和指针是如何访问的
数组访问指针数据
使声明与定义相匹配
数组和指针的其他区别
1.1.1数组和指针是如何访问的 数组和指针是如何访问的
申明区别
extern int *x; -》声明x是个int型的指针 extern int y[] -》y是个int型数组,长度尚未确定
地址和内容的区别
为什么C语言把数组形参当作指针
数组与指针归纳总结
1.2.1 什么时候指针与数组相同
数组运用特性
数组声明
外部数组(external array)的声明 数组的定义 函数参数的声明
运用特性
作为函数参数的数组名可以通过编译器转换为指针 使用数组时,数组可以写成指针 ,可以互换
1.2.1 什么时候指针与数组相同
X=Y
在这个上下文环境里 符号x的含义是x ,符号x的含义是x所 代表的地址。 代表的地址。 这被称为左值。 这被称为左值。
在这个上下文环境里, 在这个上下文环境里, 符号Y的含义是Y 符号Y的含义是Y所代表 的地址的内容。 的地址的内容。 这被称为右值。 这被称为右值。
左值在编译时可知, 左值在编译时可知, 左值表示存储结果的 地方。 地方。
例:
指针:char *p 取值:c=*p
图B
运行步骤: 运行步骤: 1. 取地址 取地址4624的内容,就是‘5081’ 的内容, 的内容 就是‘ 2. 取地址5081的内容 。 的内容 取地址
5 0 8 1
4642 5081
编译器符号表有一个符号p, 编译器符号表有一个符号 ,它的地 址为4624 址为
数组声明
外部数组(external array)的声明 数组的定义 函数参数的声明
1.2.4 为什么 语言把数组形参当作指针 为什么C语言把数组形参当作指针
出于效率的考虑 ??? 传值调用与传址调用 C语言形参特性
非数组形式的数据实参均以传值形式 拷贝整个数据 拷贝整个数组,在时间上还是在内存空间上的开销都非常大
图A
运行步骤: 运行步骤: 1. 取i的值,将它与 的值, 的值 将它与9980相加 相加 2. 取地址(9980+i)的内容。 的内容。 取地址 + 的内容
…
+1 9980
+2
+3
+4
+i
编译器符号表具有一个地址9980 编译器符号表具有一个地址
1.1.2 数组访问指针数据
指针访问特点
必须首先在运行时取得它的当前 值 间接进行操作
重点
指针和数组混淆的原因 指针传递多维数组参数
难点
指针和数组混淆的原因 创建和使用动态数组
本章结构
指针与数组不相同
指针与数组相同
怎样使用数组
再论指针和数组
指针运算
指针数组和数组指针
函数指针和指针函数
1 再论指针和数组
指针与数组的不相同 指针与数组的相同 怎样使用指针 指针运算 函数指针和指针函数 指针数组和数组指针
取得符号表中P的地址,提取存储于此处的指针。 把下标所表示的偏移量与指针的值相加,产生一个地址。 访问上面这个地址,取得字符。
1.1.3 数组和指针的其他区别
指 针 保存数据的地址 间接访问数据, 间接访问数据,首先取得指针的内容 把它作为地址, ,把它作为地址,然后从这个地 址提取数据。 址提取数据。 如果指针有一个下标[I], 如果指针有一个下标 ,就把指针的 内容加上I作为地址 作为地址, 内容加上 作为地址,从中提取数 据 通常用于动态数据结构 相关的函数为malloc(),free()。 , 相关的函数为 。 通常指向匿名数据 保存数据
右值直到运行时才知。 右值直到运行时才知。 如无特别说明, 如无特别说明, 右值 表示“ 的内容” 表示“Y的内容”。
1.1.1数组和指针是如何访问的 数组和指针是如何访问的
数组下标引用特点
地址在编译时可知 直接进行操作
例:
数组:char a[9]=“abedefgh”; 取值:c=a[i] ...
1.1.2 数组访问指针数据
数组访问指针特点
对内存进行直接的引用转化为间接引用
例:
数组:char a[9]=“abedefgh”; 取值:c=a[i] ...
图C
运行步骤: 运行步骤: 1. 取地址 取地址4624的内容,即‘5081’。 的内容, 的内容 。 2. 取得 的值,并将它与 取得i的值 并将它与5081相加。 的值, 相加。 相加 3. 取地址 取地址[508l+i]的内容。 的内容。 的内容 5081+i
编译器符号表显示p可以取址,从堆栈指针sp偏移14个位置运行时 步骤1:从sp偏移14个位置找到函数的活动记录,取出实参。 步骤2:取i的值,并与5081相加。 步骤3:取出地址(508+i)的内容。
1.2.4 为什么 语言把数组形参当作指针 为什么C语言把数组形参当作指针
数组, 数组,指针实参的一般用法
访问数组第i个元素的三张方式 访问数组第 个元素的三张方式
p = a; p[i];
p = a; *(p+i);
p = a+i; *p;
1.2.3.1 “表达式中的数组名”就是指针 表达式中的数组名”
数组的引用不能用指向该数组第一个元素的指针规则
数组作为sizeof()的操作数一显然此时需要的是整个数组的大小,而不是 指针所指向的第一个元素的大小。
p=a; for(i=0;i<10;i++) *(p+i)=0;
装入Rl 把[R0]装入 装入 存储至U[R1] 把0存储至 存储至 的结果装入Rl 把R5+R1的结果装入 的结果装入 存储到[R0] 把Rl存储到 存储到
1.2.4 为什么 语言把数组形参当作指针 为什么C语言把数组形参当作指针
数组运用特性
1.2.5 数组与指针归纳总结
用a[i]这样的形式对数组进行访问总是被编译器“改写”或 解释为像*(a+1)这样的指针访问。
指针始终就是指针。它绝不可以改写成数组。
在特定的上下文中,也就是它作为函数的参数(也只有这 种情况),一个数组的声明可以看作是一个指针。作为函数 参数的数组(就是在一个函数调用中)始终会被编译器修改 成为指向数组第一个元素的指针。
5 0 8 1
4642 5081
+1
+2
+3
…
+i
编译器符号表有一Hale Waihona Puke Baidu符号p, 编译器符号表有一个符号 ,它的地 址为4624 址为
1.1.2 数组访问指针数据
指针访问特点
char *p=“abcdefgh”;…p[3] -》 d char a[]=”abcdefgh”; …a[3] -》 d
访问特点
数 组
直接访问数据, 只是简单地以 只是简单地以a*1为地址取得 直接访问数据,a[I]只是简单地以 为地址取得 数据
通常用于存储固定数目且数据类型相同的元素。 通常用于存储固定数目且数据类型相同的元素。 隐式分配和删除 自身即为数据名
1.2 指针与数组的相同
什么时候指针与数组相同
混淆的原因
数组和指针规则
所有的数组在作为参数传递时都转换为指向数组起始 地址的指针,而其他的参数均采用传值调用 函数的返回值绝不能是一个函数数组,而只能是指向 数组或函数的指针
1.2.4 为什么 语言把数组形参当作指针 为什么C语言把数组形参当作指针
例:
展示了对一个下标形式的数组形参进行访问所需要的几个步骤。 Func(char p[]); Func(char *p); … … c=p[i] c=p[i]
使用&操作符取数组的地址。
数组是一个字符串(或宽字符串)常量初始值。
1.2.3.2 C语言把数组下标作为指针的偏移量 语言把数组下标作为指针的偏移量
数组访问模式分析
数组访问
把左值(a)装入 可以提到循环外 把左值 装入Rl(可以提到循环外 装入 可以提到循环外) 把左值(i)装入 装入R2(可以提到循环外 可以提到循环外) 把左值(i)装入R2(可以提到循环外)
for(i=0;i<10;i++) A[i]=0;
装入R3 把[R2]装入 装入 如果需要, 如果需要,对R3的步长进行调整把 的步长进行调整把 R1+R3 的结果装入R4中 的结果装入 中 存储到[R4] 把0存储到 存储到
1.2.3.2 C语言把数组下标作为指针的偏移量 语言把数组下标作为指针的偏移量
附录一
再论指针和数组
预习检查
链表单元有哪几个部分组成
如何申请链表单元,及释放链表单元
实现单链表插入的基本语法
简述一下快速排序基本理论要点
课程目标
本章概述
指针与数组什么时候相同 C语言为什么把数组参数当作指针 C语言的多维数组,及如何创建动态数组。
本章目标
掌握指针什么时候和数组相同,以为容易混淆的原因 掌握多维数组的内存布局。 使用指针向函数传递多维数组参数 使用指针返回多维数组 使用指针创建和使用动态数组
当把一个数组定义为函数的参数时,可以选择把它定义为 数组,也可以定义指针。不管选择哪种方法,在函数内部 事实上获得的都是一个指针。
定义和声明必须匹配
1.2.3.1 “表达式中的数组名”就是指针 表达式中的数组名”
数组下标的引用
一个指向数组的起始地址的指针加上偏移量” 下标值的步长调整到数组元素的大小
整型数的长度是4个字节,那么a[i+1]和a[i]在内存中的距离就是4(而不是1)
例:访问a[i]:
int a[10]; int*p; Int i=2 ;
调用时的实参 func(&my_int); func(my_int_ptr); ; func(my_int_array); func(&my_int_array[i])
类 型 一个整型数的地址 指向整型数的指针 整型数组 一个整型数组某个元素的地址
通常目的 一个int参数的传址调用 一个 参数的传址调用 传递一个指针 传递一个数组 传递数组的一部分
p=a; for(i=0;i<10;i++) p[i]=0;
1.2.3.2 C语言把数组下标作为指针的偏移量 语言把数组下标作为指针的偏移量
数组访问模式分析
指针备选方案1
把左值(p)装入 可以提到循环外) 把左值 装入R0(可以提到循环外 装入 可以提到循环外 装入Rl(可以提到循环外 把[R0]装入 可以提到循环外 装入 可以提到循环外) 把左值(i)装入 可以提到循环外) 把左值 装入R2(可以提到循环外 装入 可以提到循环外 装入R3 把[R2]装入 装入 如果需要, 如果需要,对R3的步长进行调整 的步长进行调整 把R1+R3的结果装入 中 的结果装入R4中 的结果装入 存储到[R4]。 把0存储到 存储到 。
1.2.2 数组和指针混淆的原因
数组和指针是相同的规则
表达式中的数组名(与声明不同)被编译器当作一个指向该数组第一个元素 的指针1。
下标总是与指针的偏移量相同
在函数参数的声明中,数组名被编译器当作指向该数组第一个元素的指 针
1.2.3 数组和指针规则
“表达式中的数组名”就是指针 C语言把数组下标作为指针的偏移量 “作为函数参数的数组名”等同于指针
数组与指针
编译器处理时是不同的
一个数组就是一个地址 一个指针就是一个地址的地址
在运行时的表示形式也是不一样的
可能产生不同的代码
1.2.2 数组和指针混淆的原因
分析: char my _array[10] char* my_ptr ; ... j = strlen(my_array); ; J = strlen(my_ptr); ; printf(”%s %s”,my_ptr,my_array); % , , ;
数组访问模式分析
指针备选方案1
把左值(p)装入 可以提到循环外) 把左值 装入R0(可以提到循环外 装入 可以提到循环外 装入Rl(可以提到循环外 把[R0]装入 可以提到循环外 装入 可以提到循环外) 把左值(i)装入 可以提到循环外) 把左值 装入R2(可以提到循环外 装入 可以提到循环外 装入R3 把[R2]装入 装入 如果需要, 如果需要,对R3的步长进行调整 的步长进行调整 把R1+R3的结果装入 中 的结果装入R4中 的结果装入 存储到[R4]。 把0存储到 存储到 。
p=a; for(i=0;i<10;i++) *p++=0;
1.2.3.2 C语言把数组下标作为指针的偏移量 语言把数组下标作为指针的偏移量
数组访问模式分析
指针备选方案2
所指对象的大小装入R5 把P所指对象的大小装入 所指对象的大小装入 (可以提到循环外 可以提到循环外) 可以提到循环外 把左值(p)装入 可以提到循环外 把左值 装入Rl(可以提到循环外 装入 可以提到循环外)