实验9 指针与引用
- 格式:doc
- 大小:103.00 KB
- 文档页数:5
一、指针概述1. 地址C++程序中每一个实体,如变量、数组和函数等,都要在内存中占有一个可标识的存储区域。
每一个存储区域由若干个字节组成,在内存中,每一个字节都有一个“地址”,一个存储区的“地址”指的是该存储区中第一个字节的地址。
2.指针C++具有获得和操纵变量地址的能力,这一点对于成功地进行C++程序设计是很重要的。
指针的功能很强大,同时又很危险,用好指针是学好C++的关键。
指针就是存储区域的地址。
一个地址指向一个程序实体的存储空间。
直接访问:通过变量名或地址访问程序中一个实体的存储空间的方式(其实通过变量名访问也就是通过地址访问)。
间接访问:把一个变量的地址放在另一个变量中。
3.指针变量专门用来存放地址的变量就叫指针变量,需要专门加以定义。
二、指针的类型与指针的定义指针也是具有类型的。
指针的类型就是它所指向的变量的类型。
例如,一个指向int型的指针,一个指向一维数组的指针。
指针定义语句由数据类型名、星号和指针变量名组成。
它的定义形式如下:类型标识符*指针变量名;例如:int *p;定义了一个指向整型数据的指针变量p。
即p是一个存放整型变量地址的变量。
应当特别注意的是,定义一个指针变量必须用符号“*”,它表示其后的变量为指针变量,指针变量为p,而不是*p。
要想使一个指针变量指向一个变量,必须将变量的地址赋给指针变量。
例如:int *p, i=3;p=&i;指针变量也可以定义为指向实型、字符型以及其它类型的变量。
如:float *p ;char *q ;float value;float *point1=&value;//定义的同时初始化下面是一个简单的程序,它描述了指针的应用。
//2-3指针与引用.cpp#include <iostream.h>void main( ){i=3 ; j=90;p=&i;cout<<”p的值是:”<<p<<endlcout<<”p指向:”<<*p<<endl;(*p)++;cout<<”i的值是:”<<i<<endl;cout<<”p指向:”<<*p<<endl;p=&i;cout<<”p的值是:”<<p<<endl;cout<<”p指向:”<<*p<<endl;}三、指针运算符在C++语言中,有两个有关指针的运算符:&:为取地址运算符,&x的值为x的地址。
指针与引用1.引用:所关联对象的另一个名字,引用主要用作函数的形式参数;不能定义引用类型的引用;(1) 引用必须用与该引用同类型的对象初始化:例:int ival = 1024;int &refval = ival; //正确:refval与对象ival关联int &refval2; //错误:定义引用必须初始化int &refval3 = 10; //错误:必须使用对象初始化引用(2) 作用在引用上的操作实际上都是作用在该引用关联的对象上:例:refval += 2; //实际上是将ival加2int i = refval; //把ival的值赋给irefval = 5; //修改ival的值为52.const引用:指向const对象的引用例:const int ival1 = 1024;int ival2 = 256;const int &refval1 = ival1; //正确:const引用关联const对象 //正确:const引用关联非const对象const int &refval2 = ival2;int &refval3 = ival1; //错误:非const引用不能关联const对象int &refval4 = ival2; //正确:非const引用关联非const对象注:可以读取但不能修改refval1,任何对refval1的赋值都是不合法的;不能直接对ival1赋值,也不能通过refval1来修改ival1。
(1) const引用:指向const对象的引用,但也可以关联非const相关类型的对象或字面值常量(指向const对象的引用可以用字面值常量初始化);例:int ival = 42;/* const引用关联字面值常量,r1 = 42,值不可修改,但可以赋给其它引用或变量 */const int &r1 = 42;const int &r2 = r1 + ival; //const引用关联非const同类型对象double dval = 3.14;const int &r3 = dval; //const引用关联非const相关类型对象(2) 非const引用:指向非const对象的引用,只能关联到与该引用同类型的对象(指向非const对象的引用只能用非const对象初始化)。
一概括指针和引用,在C++的软件开发中非常常见,如果能恰当的使用它们能够极大的提高整个软件的效率,但是很多的C++学习者对它们的各种使用情况并不是都了解,这就导致了实际的软件开发中经常会内存泄漏,异常抛出,程序崩溃等问题。
对于C和C++的初学者,那更是被它们搞的迷迷糊糊。
本篇作为[深入 C++]系列的第一节,我们就带领大家把指针和引用这个基本功练好。
二指针指针,指针的定义是什么呢?好像要想给个直接的定义还是很难的哦,所以我们这里用它的语法结合图来认识它。
int i = 10;int *p = NULL;p = &i;int j = *p; int **pP = NULL; pP = &p;在上面的几条语句中,&用来定义引用变量或对变量取其地址,*用来定义指针或得到指针所指向的变量,其中p为定义的指针变量,它指向int变量i,而pP 为二级指针变量,它指向指针变量p。
相应的示意图如下:C++是对C的扩展,我们首先来看指针在C中的使用,下面的经典实例来自林锐的《高质量编程》,记住函数的默认参数传递方式为按值传递,即实参被传入函数内时进行了拷贝,函数内其实是对拷贝对象的操作,还有当函数使用return 返回变量时,其实返回的是原对象的一个拷贝,此时的实参和原对象有可能是一般变量也有可能是指针变量。
Code<!-- <br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />/<br /><br/>-->#pragma once#include < cstring >#include < cstdio >#include < cstdlib >// -----------------------------------------------void GetMemory1( char * p, int num){p = ( char * )malloc(num);}void Test1( void ){char * str = NULL;GetMemory1(str, 100 );strcpy(str, "hello world" );printf(str);}// -----------------------------------------------void GetMemory2( char ** p, int num){* p = ( char * )malloc(num);}void Test2( void ){char * str = NULL;GetMemory2( & str, 100 );strcpy(str, "hello world" );printf(str);free(str);}// -----------------------------------------------char * GetMemory3( void ){char p[] = "hello world" ;return p;}void Test3( void ){char * str = NULL;str = GetMemory3();printf(str);}// -----------------------------------------------char * GetMemory4( void ){char * p = "hello world" ;return p;}void Test4(){char * str = NULL;str = GetMemory4();printf(str);}// -----------------------------------------------char * GetMemory5( void ){char * p = ( char * )malloc( 100 );strcpy(p, "hello world" );return p;}void Test5(){char * str = NULL;str = GetMemory5();printf(str);free(str);}// -----------------------------------------------void Test6( void ){char * str = ( char * )malloc( 100 );strcpy(str, "hello" );free(str);if (str != NULL){strcpy(str, "world" );printf(str);}}// -----------------------------------------------void TestPointerAndReference(){// -----------------------------------------------//请问运行Test1函数会有什么样的结果?////答:程序崩溃。
从概念上讲。
指针从本质上讲就是存放变量地址的一个变量,在逻辑上是独立的,它可以被改变,包括其所指向的地址的改变和其指向的地址中所存放的数据的改变。
而引用是一个别名,它在逻辑上不是独立的,它的存在具有依附性,所以引用必须在一开始就被初始化,而且其引用的对象在其整个生命周期中是不能被改变的(自始至终只能依附于同一个变量)。
在C++中,指针和引用经常用于函数的参数传递,然而,指针传递参数和引用传递参数是有本质上的不同的:指针传递参数本质上是值传递的方式,它所传递的是一个地址值。
值传递过程中,被调函数的形式参数作为被调函数的局部变量处理,即在栈中开辟了内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个副本。
值传递的特点是被调函数对形式参数的任何操作都是作为局部变量进行,不会影响主调函数的实参变量的值。
而在引用传递过程中,被调函数的形式参数虽然也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。
被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量。
正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。
引用传递和指针传递是不同的,虽然它们都是在被调函数栈空间上的一个局部变量,但是任何对于引用参数的处理都会通过一个间接寻址的方式操作到主调函数中的相关变量。
而对于指针传递的参数,如果改变被调函数中的指针地址,它将影响不到主调函数的相关变量。
如果想通过指针参数传递来改变主调函数中的相关变量,那就得使用指向指针的指针,或者指针引用。
为了进一步加深大家对指针和引用的区别,下面我从编译的角度来阐述它们之间的区别:程序在编译时分别将指针和引用添加到符号表上,符号表上记录的是变量名及变量所对应地址。
指针变量在符号表上对应的地址值为指针变量的地址值,而引用在符号表上对应的地址值为引用对象的地址值。
符号表生成后就不会再改,因此指针可以改变其指向的对象(指针变量中的值可以改),而引用对象则不能修改。
C++中的指针与引⽤写在前⾯指针和引⽤形式上很好区别,但是他们似乎有相同的功能,都能够直接引⽤对象,对其进⾏直接的操作。
但是什么时候使⽤指针?什么时候使⽤引⽤呢?这两者很容易混淆,在此我详细介绍⼀下指针和引⽤,⼒争将最真实的⼀⾯展现给⼤家。
如果我喷得不够好,希望嘴下留情、⼿下留命,还请指点⼀⼆;如果感觉还不错,请⼤家⿎掌。
1、指针和引⽤的定义在深⼊介绍之前我们⾸先来看⼀下指针和引⽤的定义、指针和引⽤的区别,然后分别针对指针和引⽤展开讨论,深⼊细节为何有这些差异。
指针的权威定义:In a declaration T D where D has the form* cv-qualifier-seq opt D1And the type of the identifier in the declaration T D1 is "derived-declarator-type-list T", then the type of the identifier of D is "derived-declarator-type-list cv-qualifier-seq pointer to T". The cv-qualifiersapply to the pointer and not to the object pointer to.——摘⾃《ANSI C++ Standard》注:可能有些读者并不明⽩cv-qualifier-seqCV-qualifiers(CV限定符)CV-qualifiers有三种:const-qualifier(const限定符)、volatile-qualifier(volatile限定符)、以及const-volatile-qualifier(const-volatile限定符)。
const类对象的⾮静态、⾮mutable、以及⾮引⽤数据成员是const-qualified;volatile类对象的⾮静态、⾮引⽤数据成员是volatile-qualified;const-volatile类对象的⾮静态、⾮引⽤数据成员是const-volatile-qualified。
指针参数传递和引用参数传递指针参数传递和引用参数传递都是 C++ 程序中常用的参数传递方式。
在 C++ 中,参数传递分为值传递、指针传递和引用传递三种方式。
值传递方式是将参数本身的值传递给函数,而指针传递和引用传递方式则是传递参数在内存中的地址。
在一些情况下,我们需要修改函数中传递的参数,例如在排序函数中交换数组中的两个元素。
此时,如果使用值传递方式,函数将无法直接修改参数本身的值,而只能复制一份参数的值进行修改。
C++ 提供了指针和引用两种方式,以便在函数内部修改调用者传递的参数。
下面,我们将详细介绍指针参数传递和引用参数传递两种方式的原理和使用方法,并比较它们之间的优缺点。
一、指针参数传递在 C++ 中,可以将一个变量的地址传递给另一个变量,这个变量就是指针。
指针变量用于存储内存地址,我们可以通过解引用操作符 * 获取指针所指向的变量的值,也可以通过指针访问变量的地址和修改变量的值。
在函数中,可以通过参数将指针传递给函数。
通过修改指针所指向的变量的值,可以直接修改函数外部的变量值。
因为指针传递的是变量的地址,因此在函数内部对变量的操作会影响到函数外部相同地址的变量。
下面是一个例子,演示了如何使用指针参数传递来交换两个变量的值:```#include <iostream>using namespace std;void swap(int* x, int* y) {int temp = *x;*x = *y;*y = temp;}通过调用 swap 函数并传递 a 和 b 的地址,可以在函数内部交换 a 和 b 的值。
这样,在函数外部也能看到交换后的结果。
函数外部定义的 a 和 b 变量并没有被修改,而是修改了它们在内存中的值。
引用传递是 C++ 中一种另外的参数传递方式。
引用传递在语法上与指针传递类似,但是使用起来却更加简单和方便。
引用传递的优点在于能够将被调用的函数中的值返回到调用函数中,同时又能够保留被调用函数中的原始值。
C++中指针和引⽤的区别指针和引⽤主要有以下区别:1. 引⽤必须被初始化,但是不分配存储空间。
指针不声明时初始化,在初始化的时候需要分配存储空间。
2. 引⽤初始化后不能被改变,指针可以改变所指的对象。
3. 不存在指向空值的引⽤,但是存在指向空值的指针。
注意:引⽤作为函数参数时,会引发⼀定的问题,因为让引⽤作参数,⽬的就是想改变这个引⽤所指向地址的内容,⽽函数调⽤时传⼊的是实参,看不出函数的参数是正常变量,还是引⽤,因此可能引发错误。
所以使⽤时⼀定要⼩⼼谨慎。
从概念上讲。
指针从本质上讲就是存放变量地址的⼀个变量,在逻辑上是独⽴的,它可以被改变,包括其所指向的地址的改变和其指向的地址中所存放的数据的改变。
⽽引⽤是⼀个别名,它在逻辑上不是独⽴的,它的存在具有依附性,所以引⽤必须在⼀开始就被初始化,⽽且其引⽤的对象在其整个⽣命周期中是不能被改变的(⾃始⾄终只能依附于同⼀个变量)。
在C++中,指针和引⽤经常⽤于函数的参数传递,然⽽,指针传递参数和引⽤传递参数是有本质上的不同的:指针传递参数本质上是值传递的⽅式,它所传递的是⼀个地址值。
值传递过程中,被调函数的形式参数作为被调函数的局部变量处理,即在栈中开辟了内存空间以存放由主调函数放进来的实参的值,从⽽成为了实参的⼀个副本。
值传递的特点是被调函数对形式参数的任何操作都是作为局部变量进⾏,不会影响主调函数的实参变量的值。
⽽在引⽤传递过程中,被调函数的形式参数虽然也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。
被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量。
正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。
引⽤传递和指针传递是不同的,虽然它们都是在被调函数栈空间上的⼀个局部变量,但是任何对于引⽤参数的处理都会通过⼀个间接寻址的⽅式操作到主调函数中的相关变量。
⽽对于指针传递的参数,如果改变被调函数中的指针地址,它将影响不到主调函数的相关变量。
[C++⾯试题]之指针与引⽤(1)指针是C系语⾔的特⾊。
指针是C++提供的⼀种颇具特⾊的数据类型,允许直接获取和操纵数据地址,实现动态存储分配。
指针问题,包括常量指针、数组指针、函数指针、this指针、指针传值、指向指针的指针等,这些问题也是各⼤公司常备考点,下⾯让我们⼀起学习其中的重点与难点。
1、指针与引⽤的区别?答案:(1)⾮空区别。
在任何情况下都不能使⽤指向空值的引⽤。
因此如果你使⽤⼀个变量并让它指向⼀个对象,但是该变量在某些时候也可能不指向任何对象,这时你应该把变量声明为指针,因为这样你可以赋空值给该变量。
相反,如果变量肯定指向⼀个对象,例如你的设计不允许变量为空,这时你就可以把变量声明为引⽤。
不存在指向空值的引⽤这个事实意味着使⽤引⽤的代码效率⽐使⽤指针要⾼。
(2)合法性区别。
在使⽤引⽤之前不需要测试它的合法性。
相反,指针则应该总是被测试,防⽌其为空。
(3)可修改区别。
指针与引⽤的另⼀个重要的区别是指针可以被重新赋值以指向另⼀个不同对象。
但是引⽤则总是指向在初始化时被指定的对象,以后不能改变,但是指定的对象其内容可以改变。
2、下⾯5个函数哪个能成功进⾏两个数的交换?#include<iostream>using namespace std;void swap1(int p,int q){int temp;temp=p;p=q;q=temp;}void swap2(int *p,int *q){int *temp;*temp=*p;*p=*q;*q=*temp;}void swap3(int *p,int *q){int *temp;temp=p;p=q;q=temp;}void swap4(int *p,int *q){int temp;temp=*p;*p=*q;*q=temp;}void swap5(int &p,int &q){int temp;temp=p;p=q;q=temp;}int main (){int a=1,b=2;//swap1(a,b);//swap2(&a,&b);//swap3(&a,&b);//swap4(&a,&b);//swap5(a,b);cout << "a:"<< a <<endl;cout << "b:"<< b <<endl;return 0;}解析:这道题考察的是参数传递、值传递、指针传递(地址传递)和引⽤传递。
一引用和指针的区别:引用是对已有名称的数据块起的一个别名,它与原先的名字作用一样,都对该数据块有操作权限,二者始终数据一致。
int a =5;int &b =a;a 与 b所指的数据都是分给5的那块。
所以 &a == &b二者地址是一样的。
#include "stdafx.h"#include <iostream>using namespace std;void main(){int a= 5;int &b =a;if (&a == &b){cout<<"Same"<<endl;//会执行到这里}getchar();}指针是申请一个地址空间来存放目标数据块的地址,他们也是对数据同一个数据快进行操作,只是它比引用多申请了一个存放地址的空间。
void main(){int a = 4;int *b = NULL;b = &a;cin>>*b;cout<<*b<<endl;cout<<a<<endl;cout<<&b<<endl;cout<<&a<<endl;//a与b地址空间不同 a与 *b的值始终一致。
}引用不可以这样写int a = 5;int &b; b =a;编译时回报错 error C2530: 'b' : references must be initialized;而指针却可以先不进行赋值操作,所以引用一版没有空引用,而指针却又空指针,正常情况下用引用的安全保障比用指针的高,用指针要经常判断是否为空指针的情况。
二指针与引用的超能力表现由于指针和引用都是直接对数据地址的操作,所以在使用时一定要注意指针和引用的这方面的操作。
C++程序设计实验报告
学号姓名系别班级计科专教师实验日期同组成员
一、实验编号及名称:实验9 指针与引用
二、实验目的:
1.要求能够使用指针,能够用指针给函数传递参数;
2.理解指针、数组和字符串之间的紧密联系,能够声明和使用字符串数组;
3.掌握引用的语法,用引用传递函数的方法。
三、实验内容及要求
1.P168 ch8_17字符指针的操作
2. P172 ch8_20把一个字符指针数组传递给函数
3. P179 ch8_24(函数指针用作函数参数)计算以0.10为步长,特定范围内的三角函数之和
4.P187 ch9_3给引用赋新值
5.P164 ch8_13用指针实现两个数据交换
P190 ch9_4用引用实现两个数据交换
6. P190 ch9_5 用引用实现函数返回两个值。
四、实验材料、工具、或软件:VC++6.0
五、实验步骤(或记录)
1.
程序如下:
#include<iostream.h>
int main()
{
char buffer[10]="ABC";
char *pc;
pc="hello";
cout<<pc<<endl;
pc++;
cout<<pc<<endl;
cout<<*pc<<endl;
pc=buffer;
cout<<pc;
}
运行的结果:
2.编写的程序如下:
#include<iostream.h>
void Print(char*[],int);
void main()
{ char* pn[]={"Fred","Barney","Wilma","Betty"};
int num =sizeof(pn)/sizeof(char*);
Print(pn,num);
}
void Print(char* arr[], int len)
{ for(int i=0; i<len; i++)
cout <<(int)arr[i] <<" "
<<arr[i] <<endl;
}
运行的结果:
3.程序如下:
#include<iostream.h>
#include<math.h>
double sigma(double(*func)(double),double dl,double du)
{
double dt=0.0;
for(double d=dl; d<du; d+=0.1)
dt+=func(d);
return dt;
}
void main()
{
double dsum;
dsum=sigma(sin,0.1,1.0);
cout<<"the sum of sin from 0.1 to 1.0 is"<<dsum<<endl;
dsum=sigma(cos,0.5,3.0);
cout<<"the sum if cos from 0.5 to 3.0 is"<<endl;
}
运行的结果:
4.程序如下:
运行的结果:
5.程序如下:
(用指针实现)
--------------------Configuration: 1 - Win32 Debug-------------------- Linking...
1.exe - 0 error(s), 0 warning(s)
运行的结果:
(用引用实现)
#include<iostream.h>
void swap(int &x,int &y);
void main()
{
int x=5,y=6;
cout<<"before swap,x:"<<" ,y:"<<y<<endl;
swap(x,y);
cout<<"after swap,x:"<<" ,y:"<<y<<endl;
}
void swap(int &rx,int &ry)
{
int temp=rx;
rx=ry;
ry=temp;
}
运行的结果:
6.程序如下:
#include<iostream.h>
bool Factor(int,int&,int&);
void main()
{
int number,squared,cubed;
bool error;
cout<<"Enter a nuber(0~20):";
cin>>number;
error=Factor(number,squared,cubed);
if (error)
cout<<"Error encoutered?\n";
else{
cout<<"Number:"<<number<<endl;
cout<<"Squared:"<<squared<<endl;
cout<<"Cubed:"<<cubed<<endl;
}
}
bool Factor(int n,int& rSquared,int& rCubed)
{
if(n>20 || n<0)
return true;
rSquared = n*n;
rCubed = n*n*n;
return false;
}
运行的结果:
六、实验存在问题和解决办法
1.
2.
3.
4.
5.
6.
七、意见和建议:
八、教师评语(或成绩)
教师签字:
年月日。