450 likes | 578 Views
Visual C++ 与面向对象程序设计教程. 第 6 章 指针. 教学目标. 介绍C ++ 中指针的基本概念。. 学习要求. 掌握指针的概念和定义方法。 掌握指针的操作符和指针的运算 掌握指针与数组的关系。 掌握指针与字符串的关系。 掌握 new 和 delete 操作符作用和使用方法。 学会使用 Visual C++ 帮助系统. 授课内容. 6.1 地址与指针 6.2 指针运算 6.3 指针与数组 6.4 动态存储分配 6.5 指针和函数(自学内容) 调试技术 程序设计举例. 6.1 地址与指针. 地址的概念 什么是地址?
E N D
Visual C++与面向对象程序设计教程 第 6章 指针
教学目标 • 介绍C++中指针的基本概念。
学习要求 • 掌握指针的概念和定义方法。 • 掌握指针的操作符和指针的运算 • 掌握指针与数组的关系。 • 掌握指针与字符串的关系。 • 掌握new和delete操作符作用和使用方法。 • 学会使用Visual C++帮助系统
授课内容 • 6.1 地址与指针 • 6.2 指针运算 • 6.3 指针与数组 • 6.4 动态存储分配 • 6.5 指针和函数(自学内容) • 调试技术 • 程序设计举例
6.1 地址与指针 • 地址的概念 • 什么是地址? • 如何表示地址? • 指针的概念 • 什么是指针? • 指针如何表示? • 地址和指针的关系
地 址 • 计算机的内存储器就象一个一维数组,每个数组元素就是一个存储单元。 • 地址是存放信息数据的内存单元的编号。 • 程序中定义的任何变量、数组或函数等,在编译时都会在内存中分配一个确定的地址单元。 • C++规定: • 变量的地址: 可以用取地址运算符‘&’ 来获取 • 数组的地址: 可以用数组名表示 • 函数的地址: 可以用函数名表示
指 针 • 指针是C++语言中的一种数据类型,是专门用来处理地址的;也可以说:指针是包含另一个变量地址的变量。 • 指针变量用星号‘*’表示,定义指针变量是通过定义该指针所指向的变量类型进行的。 • 例如: int *ptr; ptr是一个整形的指针变量 • 指针运算符‘*’具有取地址内容的作用。 • 例如: x=5; ptr=&x; *(&x) 即取x地址中值5
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;
指针的声明 • 声明的一般格式: 类型描述符 *指针变量名表; • 举例: int * ptr; float *array; char *s1,*s2; • 指针类型 内存地址值是固定不变的,不同类型的指针本身所占据的存储区域都一样大。 • 规定了用指针间接访问数据时的访问方式 • 为指针的算术运算提供依据
指针声明的举例 • 指针在定义后必须初始化才能使用;否则,结果不确定。 • 指针初始化的一般格式: 指针变量名 = 数据对象; 数据对象可以是变量、数组、函数、结构等。 • 举例: int *ptr,i=10; ptr=&i; //指向单个变量 char *sp=“string”; //指向字符串 int a[5],*ap; ap=a; //指向数组 int max(),(*fp)(); fp=max; //指向函数
6.2 指针的运算 1.“*”和“&”运算符 2.指针变量算术运算 3.指针变量比较运算 4.指针变量下标运算
1.“*”和“&”运算符 • “&”称为取地址运算符,用以返回变量的指针,即变量的地址; • “*”称为指针运算符,用以返回指针所指向的基类型变量的值。 • 例如: • int *ptr; //声明ptr是一个int型指针 • y = *ptr; //将指针ptr所指向的值赋给变量y • int &ref; //声明一个int型的引用ref • ptr = &x; //取变量x的地址 • *ptr = 2;
例6.1 交换两个变量的值 • 算 法: 交换两个变量x和y的值一定要用到第三个变量t作为周转: t = x; x = y; y = t; • 实参与形参有3种结合方式: 值调用、地址调用和引用调用
例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; }
图6.3 函数swap()中的运算结束时的内存分配示意图
例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; }
图6.4 函数swap()中的运算结束时的内存分配示意图
指针变量的其他运算 • 指针赋值 将一个指针赋值给另一个指针,结果是两个指针指向一个相同的地址单元。 例如, jp=&a;ip=jp; ip和jp都指向a。 • 指针的关系运算 表示所指变量在内存中的位置关系 例如, ip = =jp • 指针的算术运算 只进行加减,完成指针移动,实现对不同数据单元的访问操 作。对不同的类型,移动的单位长度不同。 指针+/- 整数表达式 例如, ptr++; 指针ptr右移一个地址。
6.3、指针与数组 • 计算机中处理数组时,实际上是将a[i]转换成*(a+下标表达式值)的形式。即 a[i] *(a+i) 因为数组名可以表示该数组的首地址,所以也就有: a[i] *(a+i) *(ptr+i) 其中,ptr是指向a的指针。 • 由此可见,用指针处理数组及元素是最快捷的方式
例题分析 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
例6.2 字符串复制 • 算法分析 ①令指针指向字符串1首地址 ②将当前地址内容送字符串2 ③串1地址+1 ④重复②、③直到整个字符串复制完毕为止; ⑤ 用循环语句实现,结束条件是当前值不为0。
例6.2 子函数 //Example 6.2: 复制字符串 mystrcpy(char *destin, char *source) { while(*source!=0) { *destin = *source; source ++; destin ++; } *destin = 0; }
例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; }
例6.3 数组清零 • 算法分析(用指针实现) ①令指针指向数组首地址 ②向当前地址赋0值 ③指针++ ④重复②、③直到整个数组处理完毕为止; ⑤ 用循环语句实现,结束条件是循环N次,N是数组的元素个数。
例6.4 数组清零 void clear_array(float *ptr, int len) { float *qtr = ptr+len; while(ptr<qtr) { *ptr = 0.0; ptr++; } }
6.4 动态存储分配 • 运算符new用来申请所需的内存 <指针> = new <类型>(<初值>); 也可以为数组申请内存: <指针> = new <类型>[<元素数>]; • 运算符delete用于释放先前申请到的存储块 delete <指针>; • 若要释放数组的空间,必须放一个空的方括号[]在操作符delete和指向该类对象数组的指针之间。 • int *p = new int [size]; • …… • delete []p;
例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; }
自学内容 • 指针和函数 • 指针的数组 • 指针的初始化
6.5 指针与函数 • 指针作为函数的参数 • 返回指针的函数 • 指向函数的指针
指针作为函数的参数 • 通过地址调用,对形参操作将影响其对应的实参值。 • 例6.1 交换两个变量的值 • 以指针作为函数的形参有三个作用: • 1.使实参与形参指针指向共同的内存空间,以达到参数双向传递的目的。 • 2.减小函数调用时数据传递的开销。 • 3.通过指向函数的指针传递函数代码的首地址
返回指针的函数 • 一个函数只能有一个返回值。 • 通过返回一个指针,函数就可以和调用者交换大量数据。 例如: 返回诸如数组、字符串等包含多个数值的数据类型。 • 例6.2 将月份的数值(1-12)转换成对应的英文月份名称。
例6-5 将表示月份的数值(112)转换成对应的英文月份名称。 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]; }
例6-5主函数 void main( ) { cout<<endl; cout<<month_name(3); cout<<“ 15,2000”; }
指向函数的指针 • 说明格式 <函数返回值类型说明符> (*<指针变量名>)(<参数说明表>); • 例: double (*func)() = sin; // 说明一个指向函数的指针 double y, x; // 说明两个双精度类型的变量 x = ...; // 计算自变量x的值 y = (*func)(x); // 通过指针调用库函数求x的正弦 • 例6-7 通用数值积分函数
例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; }
通用数值积分函数的主函数 // 用于调试函数 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; }
6.6 指针的数组 • 声明一维指针数组的语法形式为: 数据类型 *数组名[下标表达式]; 例如: char *ptr[10]; int *index[10][2];
6.7 指针的初始化 • 指针变量的初始化 数据类型标识符 *指针变量名 = 初始地址值; 例如: int i; int *ptr = &i; • 指针数组的初始化 例如: char *func_namelist[] = { "strcat", "strchr", "strcmp", "strcpy", "strlwr", "strstr", "strupr" };
图6.7 MSDN界面 调试技术:Visual C++的帮助功能
程序设计举例 • 例6-8 计算50的阶乘。 算法 求阶乘n!,当n较大时,由于计算机字长有限,不能直接机算,可采用数组的方法来实现。每个数组存放一位数字,假如我们用有100个元素的数组来计算,则精度可达100位,用这种方法就可以计算出n=50时的阶乘值。
例6-9 编写一个字符串比较函数 • 算法 int mystrnicmp(char *str1, char *str2, int n) • 例5-11介绍了字符串比较函数mystrcmp( )的编写方法,但那时我们是通过下标对数组进行操作。其实,使用指针处理这类操作会更加方便。为了达到在比较时不区分大小写字母的目的,可以使用库函数toupper( ),其原型为: • int toupper(int c); • 其中参数c为待转换的ASCII代码,如果c是一个小写字母,则该函数返回与其对应的大写字母。
上机练习题目 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的指针。
结 束 语 • 学好程序设计语言的唯一途径是 上机练习。 • 你的编程能力与你在计算机上投入的时间成 正比。