二维数组的指针表示 与复杂的指针例子 专题研讨课之三.

Slides:



Advertisements
Similar presentations
第九章 指针 西安工程大学.
Advertisements

第七章 指针 计算机公共教学部.
第六章 指针 指针的概念 指针变量 指针与数组 指针与函数 返回指针值的函数.
第7章 指针 存储地址的变量的类型就是指针类型 能直接对内存地址操作, 实现动态存储管理 容易产生副作用, 初学者常会出错
二级指针与二维数组.
C语言程序设计基础 第10章 指针进阶 刘新国.
10.1 二级指针 10.2 指针与二维数组 10.3 指针的动态存储分配 10.4 函数指针 10.5 main函数的参数
第一章 C语言概述 计算机公共教学部.
補充: Input from a text file
第6章 指针 6.1 指针的概念 6.2 变量与指针 6.3 数组与指针 6.4 字符串与指针 6.5 函数与指针 6.6 返回指针值的函数
6.4 字符串与指针 1. 用字符数组存放一个字符串.
第六节 二维数组和指针 二维数组的地址 对于一维数组: (1)数组名array表示数组的首地址, 即array[0]的地址;
8.1 指针的概念 8.2 指针变量 8.3 指针变量的基础类型 8.4 指针的运算 8.5 指针与一维数组 8.6 指针应用实例
C++中的声音处理 在传统Turbo C环境中,如果想用C语言控制电脑发声,可以用Sound函数。在VC6.6环境中如果想控制电脑发声则采用Beep函数。原型为: Beep(频率,持续时间) , 单位毫秒 暂停程序执行使用Sleep函数 Sleep(持续时间), 单位毫秒 引用这两个函数时,必须包含头文件
第九章 字符串.
第6章 指针 学习目的与要求: 了解指针的概念和相关术语 熟练掌握指向变量、数组和字符串的指针变量的使用方法 了解指向函数的指针变量
编译原理与技术 类型检查 2018/11/21 《编译原理与技术》-类型检查.
第 十 章 指 针.
C语言高级编程(第四部分) 字符串 北京大学 信息科学技术学院.
程序设计专题 第2讲 - 结构 刘新国.
STRUCTURE 授課:ANT 日期:2010/5/12.
Chap 8 指针 8.1 寻找保险箱密码 8.2 角色互换 8.3 冒泡排序 8.4 电码加密 8.5 任意个整数求和*
辅导课程六.
第五章 指针 5.1 指针的概念和定义 5.2 指针运算 5.3 指针和数组 5.4 字符串指针 5.5 指针数组 5.6 指向指针的指针
Zhao4zhong1 (赵中) C语言指针与汇编语言地址.
第一单元 初识C程序与C程序开发平台搭建 ---观其大略
C语言 程序设计基础与试验 刘新国、2012年秋.
C语言程序设计基础 第8章 指针 刘新国.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
欲穷千里,更上层楼 第十章 指 针 指针是C语言中广泛使用的一种数据类型。 运用指针编程是C语言最主要的风格之一。利用指针变量可以表示各种数据结构; 能很方便地使用数组和字符串; 并能象汇编语言一样处理内存地址,从而编出精练而高效的程序。指针极大地丰富了C语言的功能。 学习指针是学习C语言中最重要的一环,
第五章 习题课 电子信息与计算机科学系 曾庆尚.
第七章 操作符重载 胡昊 南京大学计算机系软件所.
第1章 概述 本章要点: C语言程序结构和特点 C语言程序的基本符号与关键字 C语言程序的编辑及运行 学习方法建议:
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
简单介绍 用C++实现简单的模板数据结构 ArrayList(数组, 类似std::vector)
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
C语言复习3----指针.
C语言大学实用教程 第7章 指针 西南财经大学经济信息工程学院 刘家芬
指针 几个概念:  指针也是一种数据类型,具有指针类型的变量,称为指针变量。
<编程达人入门课程> 本节内容 内存的使用 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群: ,
C语言程序设计 第一章 数据类型, 运算符与表达式 第二章 顺序程序设计 第三章 选择结构程序设计 第四章 循环控制 第五章 数组.
第4章 Excel电子表格制作软件 4.4 函数(一).
C语言程序设计 李祥 QQ:
C qsort.
C程序设计.
第4章 数 组.
<编程达人入门课程> 本节内容 为什么要使用变量? 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ:
C++语言程序设计 C++语言程序设计 第四章 数组及自定义数据类型 C++语言程序设计.
第九节 赋值运算符和赋值表达式.
3.16 枚举算法及其程序实现 ——数组的作用.
第二章 类型、对象、运算符和表达式.
本节内容 结构体 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
第2章 数据类型与表达式 学习目的与要求: 掌握C 语言的基本数据类型及使用方法 掌握C程序中常用的运算符和表达式 了解数据类型的转换.
Review 1~3.
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
C程序设计.
本节内容 指针类型.
本节内容 结构体.
結構、檔案處理(Structure, File)
本章主題 C++的程式結構 資料型態與宣告 算術運算 簡易的輸入輸出指令 程式編譯(Compile)的過程與原理.
C++语言程序设计 C++语言程序设计 第一章 C++语言概述 第十一组 C++语言程序设计.
C语言程序设计 第8章 指针.
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
基本知识 数据类型、变量、常量、运算符.
C/C++基礎程式設計班 C語言入門、變數、基本處理與輸入輸出 講師:林業峻 CSIE, NTU 3/7, 2015.
基本資料型態 變數與常數 運算子 基本的資料處理 授課:ANT 日期:2014/03/03.
第八章 指 针 北京邮电大学出版社.
變數與資料型態  綠園.
本节内容 指针类型 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
Presentation transcript:

二维数组的指针表示 与复杂的指针例子 专题研讨课之三

问题 – 计算矩阵的行列式 编写函数计算一个 NxN 矩阵 A 的行列式 矩阵 A 可以用一个二维数组表示 a[i][j] 表示第i行、第j列的元素Aij 2

问题 – 计算矩阵的行列式 今天我们不关注算法实现 定义函数的原型 函数原型可以等价地写成 double Det(double a[100][100], int n); 函数原型可以等价地写成 double Det(double a[ ][100], int n); double Det(double (*a)[100], int n); 为什么?数组到底是什么? 3

内容提要 指针的要素,多级指针 指针与数组关系 二维数组与多维数组 4

指针的要素:基类型, 地址值 类型名 * 指针变量名 例如: int * p1; p1的基类型是int char * p2; p2的基类型是char double * p3; p2的基类型是double double ** p4; p4的基类型是double* double ***p5; p5的基类型是double** 5

指针的值或者地址值 double a, x[10]; double *p1, **p2; p1和p2都是指针 p1的基类型是double,p2的基类型是double*; 目前都还没有确定(有意义的)地址值 执行赋值操作:p1 = &a; 那么 p1的值是a的地址,称作:p1指向a *p1 和 a 是同一个对象,都是变量 a x的地址值是什么? 6

代码举例 错误的代码(指针值不合法) 正确代码 读入一个字符串: 读入一个整数 引用指针 char str[100], *s; scanf(“%s”, s); 读入一个整数 int a,*p; scanf(“%d”,p); 引用指针 int c, a = 2, *p; c = 3 + *p; s = str; scanf(“%s”, s); p = &a; scanf(“%d”,p); p = & a; c = 3 + *p; 7

使用指针之前,一定要赋值 scanf(“%s”, s); scanf(“%d”,p); c = 3 + *p; 根据指针p的地址,从内存的相应地方读取一个整数(p的基类型是整数) 8

指针的基类型与(地址)值 指针的加法对地址值的影响 地址值的增量 = sizeof(基类型) 定义 基类型 p所指向对象的地址(假设) char *p; char (1 byte) 1000020 1000021 short *p; short (2 bytes) 1000040 1000042 long *p; long (4 bytes) 1000080 1000084 … 9

数组与指针 int a[5],x[100]; 数组名既是一个数组,又是一个指针 它的基类型就是它的元素的类型 它的值是首元素地址 数组名是个指针常量,不是变量,不能再赋值 int *p = a + 1; 可以 p = a + 2; 可以 a = a + 1; 不可以 10

理解运算符[] 以下程序输出什么? 运算符 [ ]的意义:x[y]  *(x+y) void main() { int a[5]={1, 3, 5, 7, 9},*p = a; printf("%d\t%d\n", a[3], 3[a]); } 运算符 [ ]的意义:x[y]  *(x+y) 所以 a[3]  *(a+3)  *(3+a)  3[a] 因此,输出是 7 7 a[i] 和 p[i] 没有区别 11

二维数组与行指针 int a[4][3]; 二维数组可以理解为 特殊的一维数组 它的每个元素都是一维数组! [0][1] [0][2] [0][0] [1][1] [1][2] [1][0] [2][1] [2][2] [2][0] [3][1] [3][2] [3][0] int a[4][3]; 二维数组可以理解为 特殊的一维数组 它的每个元素都是一维数组! a也是一个指针,它的基类型是“长度为3的int数组” 每一个a[i]都是长度为3的数组 a+i是什么? 指向谁? *( a+i )  a[i] a+i也是行指针,指向第i行 a的地址值, a[0]的地址值, 都是 a[0][0] 的地址 a[i]是一位数组,所以也是指针(数组名是指向首元素的指针) a[i]的基类型是int a[i] + j 是什么?指向谁? *( a[i]+j )  a[i][j] 基类型是一维数组的指针行指针 基类型是二维数组的指针面指针 基类型是三维数组的指针体指针 12

定义数组类型 typedef int IntA[10]; 等价于: IntA a; IntA b[5]; IntA *ap; 定义了一个行指针 int a[10]; int b[5][10]; int (*ap)[10]; 13

自定义类型-typedef语句 typedef 原类型名 新类型; typdef double Real; typdef char Byte; typdef int *Pointer; Pointer p  int * p; Pointer *q  int **q; 定义了一个二级指针 typdef int Array[10][10]; Array a  int a[10][10]; Array *p  int (*p)[10][10]; 定义了一个面指针 14

Typedef常用语结构类型 使用方便 struct _POINT { float x, y; }; typedef struct _POINT POINT; POINT p1, p2;  struct _POINT p1, p2; POINT *p  struct _POINT *p; typedef struct { float x, y } POINT; 无名结构 如果结构成员多,一般写成多行 typedef struct { float x; float y; } POINT; 15

typedef多个新类型 typedef struct { float x; float y; } POINT, * PPOINT; PPOINT x; x是什么类型? 16

typedef命令语法格式 类似于定义变量 double Real;  typedef double Real; Real x;  double x; double *PReal;  typedef double *PReal; struct _Point Point;  typdef struct _Point Point; Point p;  struct _Point p; int Array[10];  typedef int Array[10]; Array a;  int a[10]; int * PArray[20];  typedef int *PArray[20]; 这是指针数组 PArray p;  int *p[20]; int (*AP)[30];  typedef int (*AP)[30]; 只是行指针 AP p;  int (*p)[30]; 17

回答问题 定义函数的原型 函数原型可以等价地写成 double Det(double a[100][100], int n); 为什么? 作为形式参数 a[] 与 *a 等价 注意一下区别: double *a[100]; a是(指针)数组 double (*b)[100]; b是(数组)指针,即行指针 18

二维数组、数组指针 int a[5][10] = {55}; int (*p2)[10] = a; int * p1 = a; a的地址值 = a[0]的地址值 = a[0][0]的地址 int (*p2)[10] = a; int * p1 = a; 发生了强制类型转换! int[10]指针  int指针 编译器会警告 思考:指针的基类型 p1+1指向的地址、*p1是什么? p2+1指向的地址、*p2是什么?

指向指针的指针(二级指针) int a = 10; int *p = &a; int **pp = &p; 定义语法格式 类型名 **指针变量名; a 10 *pp *p **pp

多级指针 int a = 10; int *p = &a; int **pp = &p; 思考 pp = &(&a); 不可以!! 运算符&取得“操作数”的地址 该操作数必须在内存中有对应地址 &a变量a的地址值,是一个常量 常量没有地址值,例如5,7,10等等

多级指针 int a[5][10] = { 55 }, b = 66; int *p = &b, **pp = &p; 思考 pp = a; 发生了类型强制转换:行指针(int[10])int** a的地址值 = a[0]的地址值 = a[0][0]的地址 *pp是什么?等于什么? *pp 是 int*,它的值是 55; **pp是地址为55的内存数据(4个字节作为整数处理) 如果执行:int x = **pp;一般会报错

多级指针程序解析 程序 char *c[] = {"ENTER", "NEW", "POINT", "FIRST"}; char **cp[]= {c+3, c+2, c+1, c}; char ***cpp = cp; main() { printf("%s", **++cpp); printf("%s", *--*++cpp); printf("%s", *cpp[-2]+3); printf("%s\n", cpp[-1][-1]+1); }

多级指针程序解析 char *c[] = {"ENTER", "NEW", "POINT", "FIRST"}; char **cp[]= {c+3, c+2, c+1, c}; char ***cpp = cp; 示意图: “ENTER” “NEW” “POINT” “FIRST” ccp cp[0] cp[1] cp[2] cp[3] cp c[0] c[1] c[2] c[3] c

多级指针程序解析 语句printf("%s", **++cpp); 执行情况分析: 执行++cpp后,cpp指向了cp[1],此时的*cpp等价于cp[1],**cpp等价于*cp[1],也即c[2](因为此时的cp[1]指向c[2],如图示)。 最后打印结果:POINT “ENTER” “NEW” “POINT” “FIRST” ccp cp[0] cp[1] cp[2] cp[3] cp c[0] c[1] c[2] c[3] c

多级指针程序解析 语句printf("%s", *--*++cpp); 执行情况分析: 执行++cpp后,cpp指向了cp[2], 此时的*cpp等价于cp[2], --*cpp等价于--cp[2], 执行后cp[2]指向了c[0], **cpp等价于c[0]。最后打印结果:ENTER “ENTER” “NEW” “POINT” “FIRST” ccp cp[0] cp[1] cp[2] cp[3] cp c[0] c[1] c[2] c[3] c

多级指针程序解析 语句printf("%s", *cpp[-2]+3); 执行情况分析: 注意,经过了上面两条语句的执行,此时的cpp指向了cp[2]。 cpp[-2]等价于*(cpp-2),即cp[0]。 “ENTER” “NEW” “POINT” “FIRST” ccp cp[0] cp[1] cp[2] cp[3] cp c[0] c[1] c[2] c[3] c

多级指针程序解析 语句printf("%s", *cpp[-2]+3); 执行情况分析: *cpp[-2]*cp[0]c[3]字符串“FIRST”的首地址。 *cpp[-2]+3c[3]+3 字符串“ST”的首地址。 打印结果:ST “ENTER” “NEW” “POINT” “FIRST” ccp cp[0] cp[1] cp[2] cp[3] cp c[0] c[1] c[2] c[3] c

多级指针程序解析 语句printf("%s\n", cpp[-1][-1]+1); 执行情况分析: 此时的cpp仍然指向cp[2]。 cpp[-1][-1](*(cpp-1))[-1] (cp[1])[-1]*(cp[1]-1)c[1]  字符串“NEW”的首地址。 cpp[-1][-1]+1c[1]+1“EW” 打印结果:EW “ENTER” “NEW” “POINT” “FIRST” ccp cp[0] cp[1] cp[2] cp[3] cp c[0] c[1] c[2] c[3] c

多级指针程序解析 综合结果:POINTENTERSTEW

行指针(数组指针)[续] #include <string.h> char (*defy(char *p))[5] { #include <stdio.h> #include <string.h> char (*defy(char *p))[5] { int i; for(i=0; i<3; i++) p[strlen(p)] = 'A'; return (char(*)[5])p+1; } void main() char a[] = "FROG\ØSEAL\ØLION\ØLAMB"; puts( defy(a)[1]+2 );

函数defy的参数和返回值 先看函数头 char (* defy(char *p)) [5] 按“从右到左”,找到defy defy左边是 *,表名defy()返回一个指针 假设函数的返回值是 x, 那么x的类型定义是 char (*x)[5]; 所以,函数的返回值是一个指针,而且是行指针 它的基类型是:长度为5的字符数组

如何更清晰地定义函数defy 函数defy的返回值是一个行指针,基类型是:长度为5的字符数组 利用typedef命令,程序更清晰 typedef char CA5[5]; CA5 *defy(char *p) { int i; for(i=0; i<3; i++) p[strlen(p)] = 'A'; return (CA5*)p+1; } char (*defy(char *p))[5] { int i; for(i=0; i<3; i++) p[strlen(p)] = 'A'; return (char(*)[5])p+1; }

函数defy的返回值 return (char (*)[5])p + 1; (char (*)[5])是一个强制类型转换 表示目标类型为数组指针(行指针) 该指针指向由5个char构成的一维数组。 注意这里的*必须用()括起来,强调指针优先 理解的时候可以设想*后面有一个变量p;

分析defy(a)的执行结果 A A A char a[] = "FROG\ØSEAL\ØLION\ØLAMB"; puts( defy(a)[1]+2 ); 先看defy(a)的执行 将字符串结束符\0变成A 执行三次 再看defy的返回值 (CA*)p是一个行指针 (CA*)p+1指向下一行 即指向: SEALA A A A CA5 *defy(char *p) { int i; for(i=0; i<3; i++) p[strlen(p)] = 'A'; return (CA5*)p+1; }

puts( defy(a)[1]+2 )的实际参数 执行defy(a)之后,数组a中数据是 “FROGASEALALIONALAMB” defy(a)的返回值是一个行指针 指向 SEALA defy(a)[1]  *(defy(a)+1) defy(a)[1]的类型 CA5 前面定义:typedef char CA5[5]; (长为5的字符数组) defy(a)[1]也是char * 指针。 defy(a)[1]+2指向 因此,函数puts的输出是:ONALAMB

End! 下载PPT,好好研读