1 / 45

Visual C++ 与面向对象程序设计教程

Visual C++ 与面向对象程序设计教程. 第 6 章 指针. 教学目标. 介绍C ++ 中指针的基本概念。. 学习要求. 掌握指针的概念和定义方法。 掌握指针的操作符和指针的运算 掌握指针与数组的关系。 掌握指针与字符串的关系。 掌握 new 和 delete 操作符作用和使用方法。 学会使用 Visual C++ 帮助系统. 授课内容. 6.1 地址与指针 6.2 指针运算 6.3 指针与数组 6.4 动态存储分配 6.5 指针和函数(自学内容) 调试技术 程序设计举例. 6.1 地址与指针. 地址的概念 什么是地址?

buffy-floyd
Télécharger la présentation

Visual C++ 与面向对象程序设计教程

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Visual C++与面向对象程序设计教程 第 6章 指针

  2. 教学目标 • 介绍C++中指针的基本概念。

  3. 学习要求 • 掌握指针的概念和定义方法。 • 掌握指针的操作符和指针的运算 • 掌握指针与数组的关系。 • 掌握指针与字符串的关系。 • 掌握new和delete操作符作用和使用方法。 • 学会使用Visual C++帮助系统

  4. 授课内容 • 6.1 地址与指针 • 6.2 指针运算 • 6.3 指针与数组 • 6.4 动态存储分配 • 6.5 指针和函数(自学内容) • 调试技术 • 程序设计举例

  5. 6.1 地址与指针 • 地址的概念 • 什么是地址? • 如何表示地址? • 指针的概念 • 什么是指针? • 指针如何表示? • 地址和指针的关系

  6. 地 址 • 计算机的内存储器就象一个一维数组,每个数组元素就是一个存储单元。 • 地址是存放信息数据的内存单元的编号。 • 程序中定义的任何变量、数组或函数等,在编译时都会在内存中分配一个确定的地址单元。 • C++规定: • 变量的地址: 可以用取地址运算符‘&’ 来获取 • 数组的地址: 可以用数组名表示 • 函数的地址: 可以用函数名表示

  7. 图6.1 存储结构简图

  8. 指 针 • 指针是C++语言中的一种数据类型,是专门用来处理地址的;也可以说:指针是包含另一个变量地址的变量。 • 指针变量用星号‘*’表示,定义指针变量是通过定义该指针所指向的变量类型进行的。 • 例如: int *ptr; ptr是一个整形的指针变量 • 指针运算符‘*’具有取地址内容的作用。 • 例如: x=5; ptr=&x; *(&x) 即取x地址中值5

  9. 1000 x 1004 ptr 1000 3 1000 3 1004 &x 1000 5 &x 1004 地址和指针的关系 • 用来存放地址的变量就叫作指针变量。 • 设 int x,*ptr ; 当定义了整型变量x和指针ptr后,系统分配两个存储单元1000和1004; • 执行 x=3; • 执行 ptr=&x ; • 执行 *ptr = 5;

  10. 指针的声明 • 声明的一般格式: 类型描述符 *指针变量名表; • 举例: int * ptr; float *array; char *s1,*s2; • 指针类型 内存地址值是固定不变的,不同类型的指针本身所占据的存储区域都一样大。 • 规定了用指针间接访问数据时的访问方式 • 为指针的算术运算提供依据

  11. 指针声明的举例 • 指针在定义后必须初始化才能使用;否则,结果不确定。 • 指针初始化的一般格式: 指针变量名 = 数据对象; 数据对象可以是变量、数组、函数、结构等。 • 举例: int *ptr,i=10; ptr=&i; //指向单个变量 char *sp=“string”; //指向字符串 int a[5],*ap; ap=a; //指向数组 int max(),(*fp)(); fp=max; //指向函数

  12. 6.2 指针的运算 1.“*”和“&”运算符 2.指针变量算术运算 3.指针变量比较运算 4.指针变量下标运算

  13. 1.“*”和“&”运算符 • “&”称为取地址运算符,用以返回变量的指针,即变量的地址; • “*”称为指针运算符,用以返回指针所指向的基类型变量的值。 • 例如: • int *ptr; //声明ptr是一个int型指针 • y = *ptr; //将指针ptr所指向的值赋给变量y • int &ref; //声明一个int型的引用ref • ptr = &x; //取变量x的地址 • *ptr = 2;

  14. 例6.1 交换两个变量的值 • 算 法: 交换两个变量x和y的值一定要用到第三个变量t作为周转: t = x; x = y; y = t; • 实参与形参有3种结合方式: 值调用、地址调用和引用调用

  15. 例6.1 交换两个变量的值 void swap(int x,int y) { int tmp; tmp = x; x = y; y = tmp; } void main() { int x = 2, y = 3; cout<<“x=“<<x<<“,y=“<<y<<endl; swap(x, y); cout<<"After exchange x&y:”<<endl; cout<<“x=“<<x<<“,y=“<<y<<endl; }

  16. 图6.2 验证函数swap( )时的内存分配示意图

  17. 图6.3 函数swap()中的运算结束时的内存分配示意图

  18. 例6.1 交换两个变量的值(修改后) void swap(int *xp,int *yp) { int tmp; tmp = *xp; *xp = *yp; *yp = tmp; } void main() { int x = 2, y = 3; cout<<“x=“<<x<<“,y=“<<y<<endl; swap(&x, &y); cout<<"After exchange x&y:”<<endl; cout<<“x=“<<x<<“,y=“<<y<<endl; }

  19. 图6.4 函数swap()中的运算结束时的内存分配示意图

  20. 指针变量的其他运算 • 指针赋值 将一个指针赋值给另一个指针,结果是两个指针指向一个相同的地址单元。 例如, jp=&a;ip=jp; ip和jp都指向a。 • 指针的关系运算 表示所指变量在内存中的位置关系 例如, ip = =jp • 指针的算术运算 只进行加减,完成指针移动,实现对不同数据单元的访问操 作。对不同的类型,移动的单位长度不同。 指针+/- 整数表达式 例如, ptr++; 指针ptr右移一个地址。

  21. 6.3、指针与数组 • 计算机中处理数组时,实际上是将a[i]转换成*(a+下标表达式值)的形式。即 a[i] *(a+i) 因为数组名可以表示该数组的首地址,所以也就有: a[i] *(a+i) *(ptr+i) 其中,ptr是指向a的指针。 • 由此可见,用指针处理数组及元素是最快捷的方式

  22. 例题分析 B 1000 1001 1002 1003 1004 1005 • 设 char *ptr,*qtr; char string[6]; • 令 ptr=string; string[1] = = *(ptr+1) qtr=ptr+strlen(string); i g \0 1000 1003

  23. 例6.2 字符串复制 • 算法分析 ①令指针指向字符串1首地址 ②将当前地址内容送字符串2 ③串1地址+1 ④重复②、③直到整个字符串复制完毕为止; ⑤ 用循环语句实现,结束条件是当前值不为0。

  24. 例6.2 子函数 //Example 6.2: 复制字符串 mystrcpy(char *destin, char *source) { while(*source!=0) { *destin = *source; source ++; destin ++; } *destin = 0; }

  25. 例6.2 主函数 /*- 用于调试函数 mystrcpy() 的主函数 ----*/ #include <iostream.h> main() { char s1[81]; char s2[] = "This is a sample."; mystrcpy(s1, s2); cout<<"The result is: ”<<s1<<endl; }

  26. 例6.3 数组清零 • 算法分析(用指针实现) ①令指针指向数组首地址 ②向当前地址赋0值 ③指针++ ④重复②、③直到整个数组处理完毕为止; ⑤ 用循环语句实现,结束条件是循环N次,N是数组的元素个数。

  27. 例6.4 数组清零 void clear_array(float *ptr, int len) { float *qtr = ptr+len; while(ptr<qtr) { *ptr = 0.0; ptr++; } }

  28. 6.4 动态存储分配 • 运算符new用来申请所需的内存 <指针> = new <类型>(<初值>); 也可以为数组申请内存: <指针> = new <类型>[<元素数>]; • 运算符delete用于释放先前申请到的存储块 delete <指针>; • 若要释放数组的空间,必须放一个空的方括号[]在操作符delete和指向该类对象数组的指针之间。 • int *p = new int [size]; • …… • delete []p;

  29. 例6.4 利用动态数组来求斐波那挈数列的前n项 // Example 6.4:用动态数组来求斐波那挈数列的前n项 #include <iostream.h> void main() { int *p, n; cout<<"Please input n=?"; cin>>n; p=new int[n+1]; if ( p==0 || n<=0 )return;//如果没有申请到内存或数据输入有误,则返回 p[0]=0; p[1]=1; cout<<p[0]<<endl; cout<<p[1]<<endl; for(int i=2;i<=n;i++) { p[i]=p[i-2]+p[i-1]; cout<<p[i]<<endl; } delete []p; }

  30. 自学内容 • 指针和函数 • 指针的数组 • 指针的初始化

  31. 6.5 指针与函数 • 指针作为函数的参数 • 返回指针的函数 • 指向函数的指针

  32. 指针作为函数的参数 • 通过地址调用,对形参操作将影响其对应的实参值。 • 例6.1 交换两个变量的值 • 以指针作为函数的形参有三个作用: • 1.使实参与形参指针指向共同的内存空间,以达到参数双向传递的目的。 • 2.减小函数调用时数据传递的开销。 • 3.通过指向函数的指针传递函数代码的首地址

  33. 返回指针的函数 • 一个函数只能有一个返回值。 • 通过返回一个指针,函数就可以和调用者交换大量数据。 例如: 返回诸如数组、字符串等包含多个数值的数据类型。 • 例6.2 将月份的数值(1-12)转换成对应的英文月份名称。

  34. 例6-5 将表示月份的数值(112)转换成对应的英文月份名称。 char *month_name(int n) { static char *month[]= { "Illegal month", "January", February", "March", "April", "May", "June", "July", "August", "September", “October”, “November”, “December” }; return (n>=1 && n<=12)?month[n]:month[0]; }

  35. 例6-5主函数 void main( ) { cout<<endl; cout<<month_name(3); cout<<“ 15,2000”; }

  36. 指向函数的指针 • 说明格式 <函数返回值类型说明符> (*<指针变量名>)(<参数说明表>); • 例: double (*func)() = sin; // 说明一个指向函数的指针 double y, x; // 说明两个双精度类型的变量 x = ...; // 计算自变量x的值 y = (*func)(x); // 通过指针调用库函数求x的正弦 • 例6-7 通用数值积分函数

  37. 例6-6 通用数值积分函数 #include <iostream.h>#include <math.h>double integral(double a, double b, double (*fun)(), int n) { double h = (b-a)/n; double sum = ((*fun)(a)+(*fun)(b))/2; int i; for(i=1; i<n; i++) sum += (*fun)(a+i*h); sum *= h; return sum; }

  38. 通用数值积分函数的主函数 // 用于调试函数 integral() 的主函数 double func(double x) { return sin(x)+x; } void main() { double sum; sum = integral(0.0, 1.0, func, 1000); cout<<("The Integral of sin(x)+x, [0, 1] is ”<< sum; }

  39. 6.6 指针的数组 • 声明一维指针数组的语法形式为: 数据类型 *数组名[下标表达式]; 例如: char *ptr[10]; int *index[10][2];

  40. 6.7 指针的初始化 • 指针变量的初始化 数据类型标识符 *指针变量名 = 初始地址值; 例如: int i; int *ptr = &i; • 指针数组的初始化 例如: char *func_namelist[] = { "strcat", "strchr", "strcmp", "strcpy", "strlwr", "strstr", "strupr" };

  41. 图6.7 MSDN界面 调试技术:Visual C++的帮助功能

  42. 程序设计举例 • 例6-8 计算50的阶乘。 算法 求阶乘n!,当n较大时,由于计算机字长有限,不能直接机算,可采用数组的方法来实现。每个数组存放一位数字,假如我们用有100个元素的数组来计算,则精度可达100位,用这种方法就可以计算出n=50时的阶乘值。

  43. 例6-9 编写一个字符串比较函数 • 算法 int mystrnicmp(char *str1, char *str2, int n) • 例5-11介绍了字符串比较函数mystrcmp( )的编写方法,但那时我们是通过下标对数组进行操作。其实,使用指针处理这类操作会更加方便。为了达到在比较时不区分大小写字母的目的,可以使用库函数toupper( ),其原型为: • int toupper(int c); • 其中参数c为待转换的ASCII代码,如果c是一个小写字母,则该函数返回与其对应的大写字母。

  44. 上机练习题目 1.编一程序,将字符串“Hello,C++!”赋给一个字符数组,然后从第一个字母开始间隔地输出该串(请用指针完成)。 2.编写程序,把10个浮点小数1.0、2.0、…、1.0赋予某个doublet型数组,然后用double型指针输出该数组元素的值。 3.编写一个函数,用于生成一个空字符串,其原型为: char *mystrspc(char *string, int n); 其中参数string为字符串, n为空白字符串的长度 (空格符的个数)。返回值为指向string的指针。 4.编写一个函数,用于去掉字符串尾部的空格符,其原型为: char *mytrim(char *string); 其中参数string为字符串,返回值为指向string的指针。 5.编写一个函数,用于去掉字符串前面的空格,其原型为: char *myltrim(char *string); 其中参数string为字符串,返回值为指向string的指针。

  45. 结 束 语 • 学好程序设计语言的唯一途径是 上机练习。 • 你的编程能力与你在计算机上投入的时间成 正比。

More Related