指针 数据结构 线性表基础(基于c++)

指针

    A 什么是指针:

      在计算机中访问数据需要的一个东西叫做 地址:内存区的每个字节都有的一个编号。(区分:地址   &   地址对应的内容)

      在内存中一般是通过变量名来对内存单元进行存取操作。但其实,程序编译后已经将变量名转换为变量的地址,对变量名的存取都是通过地址进行的。

      直接存取(直接访问):按变量地址存取变量值的方式(变量名也算是变量地址的一种形式,属于直接访问)

      间接存取(间接访问):将变量 i 的地址存放在另一个变量中。可以定义一种特殊的变量,它是用来专门存放地址的。

i_pointer=&i;

      & 是取地址运算符,&i 是  i 的地址。地址指向该变量单元(通过地址就能找到该变量单元)。

      因此,形象地称:地址指针(通过它能访问以他为地址的内存单元)。一个变量的地址称为该变量的指针。对应,一个变量的指针就是变量的地址

    一个专门用来存放地址(即指针)的变量,指针变量。

   B 引用指针变量:

     & 取地址运算符;

     * 指针运算符(间接访问运算符)

     &a 为变量a的地址,*p 指针变量p所指向的存储单元。

      例子1:

#include <iostream>
using namespace std;
int main()
{
	int a=100,b=233;
	int *p1,*p2;
	p1=&a;
	p2=&b;
	cout<<a<<' '<<b<<endl;
	cout<<*p1<<' '<<*p2<<endl;
	return 0;
}

      在程序的第6行最然定义了两个指针变量 p1 和 p2 ,但是它们并未指向任一个整形变量,而是只提供两个基类型为整型的指针变量。(用 int* 定义)

      & 和 * 的优先级别相同,按从右而左方向结合。故:& * p1和 & a 相同,都是和“ a 变量的地址” 等价;* & a 与 a 等价。

      例子2:

      输入a和b两个整数,按先大后小的顺序输出 a 和 b (用指针变量处理,不交换整形变量的值,而是交换变量指针的值, a 和 b 的内容并未交换。)

#include <iostream>
using namespace std;
int main()
{
	int a,b;
	cin>>a>>b;
	int *p1,*p2;
	p1=&a;
	p2=&b;
	if(a<b)
	{
		int *p=p1;
		p1=p2;
		p2=p;
	}
	cout<<*p1<<' '<<*p2<<endl;
	return 0;
}

     C 用指针作函数参数

       函数的参数也可以是指针类型,它的作用是:将一个变量的地址传送给被调用函数的形参。

       例子3:

        输入a和b两个整数,按先大后小的顺序输出 a 和 b (要求用函数处理,并且用指针变量作为函数参数。)

#include <iostream>
using namespace std;
int main()
{
	void pai(int *p1,int *p2);
	int a,b;
	cin>>a>>b;
	int *p1,*p2;
	p1=&a;
	p2=&b;
	if(a<b)
	{
		pai(p1,p2);
	}
	cout<<a<<' '<<b<<endl;
	return 0;
}
void pai(int *p1,int *p2)
{
	int t;//形参指针p1和p2是无法通过void函数改变的 
	t=*p1;//所以这里通过地址(虚)访问并改变参变量(实)的值,虚实结合 
	*p1=*p2;
	*p2=t;
}

       注:1. 本次选择了交换整形变量的值而非指针变量。p1依旧指向 a ,而p2也依旧指向 b 。

              2. 由于虚实结合的方式是采取单向的“值传递”的方式,只能从实参向形参传递数据,形参质的改变无法传递给实参。

              而通过把指针作为形参,实现了:通过调用函数使变量的值发生变化,在主调函数中使用这些改变了的值。

              3. 和任意其他数据类型一样,不能通过改变形参指针变量的值而使实参指针变量的值改变。

              4. 总结2、3两条,调用函数时不会改变实参指针变量的值,但可以改变指针变量所指向变量的值。

              5. 函数的调用可以(而且只可以)得到一个返回值(即函数值),而使用指针变量作函数参数,就可以通过指针变量改变主调函       数中变量的值。相当于通过函数调用从被调用的函数中得到多个值,如果不用指针变量是难以做到的。

       例子4:

       输入a和b和c三个整数,按先大后小的顺序输出 a 和 b 和 c(要求用函数处理,并且用指针变量作为函数参数。)

#include <iostream>
using namespace std;
int main()
{
	void pai(int *p1,int *p2);
	int a,b,c;
	cin>>a>>b>>c;
	int *p1,*p2,*p3;
	p1=&a;
	p2=&b;
	p3=&c;
	if(a<b) pai(p1,p2);
	if(b<c) pai(p2,p3);
	if(a<b) pai(p1,p2);
	cout<<a<<' '<<b<<' '<<c<<endl;
	cout<<*p1<<' '<<*p2<<' '<<*p3<<endl;
	return 0;
}
void pai(int *p1,int *p2)
{
	int t;//形参指针p1和p2是无法通过void函数改变的 
	t=*p1;//所以这里通过地址(虚)访问并改变参变量(实)的值,虚实结合 
	*p1=*p2;
	*p2=t;
}

     D 数组与指针

       指针既然可以指向变量,也就当然可以指向数组元素。所谓数组元素的指针就是数组元素的地址。

       

p=&a[0];
p=a;//在c++中这两个语句等价

       注:在第二行代码中数组名 a 并不代表整个数组。第二行代码的作用是:把 a 数组的首元素的地址赋给指针变量 p ,而绝非把 a 数组各个元素的值赋给p。

       可以通过指针引用数组元素:

*p=1;//对p当前所指向的数组元素赋予数值1

       ps:1. 若果指针变量p指向数组中的一个元素,则 p+i 指向同一数组中的下一个元素。(p+i 所代表的地址实际上是 p+i*d,d是一个          数组元素所占用的字节数)

               2. 数组名(如 a )代表是的数组首元素的地址,a+i 也是地址。和 p+i 同理。指针法(能使目标程序质量高,即占内存少,运行       速度快。)

               3. a[3] 数组名后的方括号“[ ]”,实际上是变址运算符。下标法

       例子1:

       下标法表示数组。

#include <iostream>
using namespace std;
int main()
{
	int a[10];
	for(int i=0;i<10;i++)
	{
		a[i]=i+1;
	}
	for(int i=0;i<10;i++)
	{
		cout<<a[i]<<' ';
	}
	return 0;
}

       例子2:

       指针法表示数组。

#include <iostream>
using namespace std;
int main()
{
	int a[10];
	for(int i=0;i<10;i++)
	{
		*(a+i)=i+1;
	}
	for(int i=0;i<10;i++)
	{
		cout<<*(a+i)<<' ';
	}
	return 0;
}

       例子3:

       指针变量法表示数组。

#include <iostream>
using namespace std;
int main()
{
	int a[10];
	int *p=a;
	for(int i=0;i<10;i++)
	{
		*(p+i)=i+1;
	}
	for(int i=0;i<10;i++)
	{
		cout<<*(p+i)<<' ';
	}
	return 0;
}

       注:1. 例子1、2 对每个a[ i ](或“*(a+i)”)都要计算地址,然后再访问元素。而例子3 是用指针变量直接指向元素,不必每次都重新计算地址。例子3 的效率和执行速度都是三个中最高的(但没有下标法直接)。

              2. 注意数组越界问题!

       用指针变量作为函数形参接受数组地址:

       数组名代表数组首元素地址。用数组名做函数参数传递的是数组首元素所对应的地址。因此,用指针变量作函数形参,同样可以接受从实参传来的数组首元素地址(此时,实参是数组名)。

       例子4:

       将10个整数按由小到大的顺序排列。

#include <iostream>
using namespace std;
int main()
{
	void pai(int *p,int n);
	int a[10];
	int *p=a;
	for(int i=0;i<10;i++)
	{
		cin>>*(p+i);
	}
	pai(a,10);
	for(p=a;p<(a+10);p++)
	{
		cout<<*p<<' ';
	}
	return 0;
}
void pai(int *p,int n)
{
	for(int i=0;i<n-1;i++)
	{
		for(int j=i+1;j<n;j++)
		{
			if(*(p+i)>*(p+j))
			{
				int t=*(p+i);
				*(p+i)=*(p+j);
				*(p+j)=t;
			}
		}
	}
}

      注:1. c++编译系统将形参数组名一律按照指针变量来处理。

             2. 实际上在函数调用时并不存在一个占用存储空间的形参数组!

             3. 实参数组名(如 a )代表一个固定的地址,或者是说是指针形常量,因此要改变 a 的值是不可能的!

             4. 而形参数组名是一个指针变量,并非一个固定的地址。因而它可以可以改变的。比如在函数开始时,就接受了实参数组首元素地址,在函数执行过程中,它也可以被赋值。

      E 字符串和指针

       在c++中有三种方法可以访问一个字符串。

       例子1:

       用字符数组来存放一个字符串。

#include <iostream>
using namespace std;
int main()
{
	char str[]="I love HNU!";
	cout <<str;
	return 0;
}

       例子2:

       定义一个字符串变量并初始化,然后输出其中的字符串。

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string str="I love HNU!";
	cout <<str;
	return 0;
}

       例子3:

       定义一个字符串指针变量并初始化,然后输出它指向的字符。

#include <iostream>
using namespace std;
int main()
{
	char *str="I love HNU!";//注意这里要用char型! 
	cout<<str<<endl;
	cout<<*str;//这样的话就只会输出字符串首元素,即‘I’ 
	return 0;
}

       注:1. 第五行,在对字符指针变量初始化时,实际上是把字符串中的第一个字符的地址赋给 str。

               2.在输出时(第六行),系统先输出 str 所指向的第一个字符数据,然后使 str 自动加一,使之指向下一个字符,然后在输出一       个字符。。。如此,直至遇到字符串的结束标志为止。

               3. 在内存中字符串的最后被自动加了一个 ‘\0’ ,因此能在输出时确定字符串的终止位置。

               4. 利用字符串指针来进行两个字符串(字符数组形式)的赋值,是相当痛苦的,要一位一位的赋值。(推荐直接用string型)

     E 函数与指针

       指针变量也可以指向一个函数。一个函数在编译时被分配给一个入口地址。这个函数的入口地址就是函数的指针。可以用一个指针变量指向函数,然后通过该指针变量调用此函数。函数名代表函数的入口地址。

       例子1:

       求 a 和 b 中的大者。(用一个指向 max 的指针变量来调用该函数)

#include <iostream>
using namespace std;
int main()
{
	int max(int a,int b);//函数声明 
	int (*p)(int a,int b);//定义指向函数的指针变量p 
	int a,b;
	cin>>a>>b;
	p=max; //使p指向函数max 
	int m=p(a,b);
	cout<<m;
	return 0;
}
int max(int a,int b)
{
	if(a>b)
	{
		return a;
	}
	else 
	{
		return b;
	}
}

       注:语句 int (*p)(int a,int b); 中,依次的意义为,第一个int:指针变量所指向的函数的类型;(*p):p 是指向函数的指针变量;(int,int):p所指向的函数中的形参的函数类型。

              在定义指向函数的指针p时,(*p)两侧的括号不能省略,表示 p 先与 * 结合,在与右面的括号结合。如果省略的话,该语句的含义就变成了:定义一个返回值是指向 int 型的指针的函数!

              在定义完对应函数的指针变量后,还要进行一部操作:使指针 p 指向函数max。来使函数的入口地址赋给指针变量p。

     F 返回指针的函数

       简称为指针函数。在定义时,注意和定义指向函数的指针作区分。

int *p(int x,int y,int z);

     G 指针数组和指向指针的指针

       指针数组:一个数组其元素都为指针类型。指针数组的每一个值都相当于一个指针变量,它们的值都是地址。

       例子1:

       将若干字符串按字母序排序输出。

#include <iostream>
#include <string.h>
using namespace std;
int main()
{
	void sort (char *name[],int n);
	char *name[]={"bnji","fnhij","c++","phbj","co0"};
	int n=5;
	sort(name,n);
	for(int i=0;i<n;i++)
	{
		cout<<name[i]<<endl;
	}
	return 0;
}
void sort (char *name[],int n)
{
	for(int i=0;i<n-1;i++)
	{
		for(int j=i+1;j<n;j++)
		{
			if(strcmp(name[i],name[j])>0)
			{
				char *t=name[i];
				name[i]=name[j];
				name[j]=t;
			}
		}
	}
}

       注:排序函数sort的形参是指针数组明,实参是指针数组name的首元素地址。排序改变的是数组的不同元素所指向的字符串(即指针数组的值——地址)。

       指向指针(数据)的指针。就比如刚才的指针数据name,数组名name就是指针数组首元素的地址。所以name以及(name+ i )

       例子2:

       指向字符型数据的指针变量。

#include <iostream>
using namespace std;
int main()
{
	char **p;//定义指向指针的指针变量p 
	char *a[]={"aa","bb","cc","dd","ee"};//定义指针数组 
	p=a+2;
	cout<<*p<<endl;//输出name[2]指向的字符串(通过其首字母地址) 
	cout<<**p; //输出name[2]指向的字符串的首字母 
	return 0;
}

     H 感谢您的阅读!

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值