指针,在C/C++语言中一直是很受宠的;几乎找不到一个不使用指针的C/C++应用。用于存储数据和程序的地址,这是指针的基本功能。用于指向整型数,用整数指针(int*);指向浮点数用浮点数指针(float*);指向结构,用对应的结构指针(struct xxx *);指向任意地址,用无类型指针(void*)。
有时候,我们需要一些通用的指针。在C语言当中,(void*) 可以代表一切;但是在C++中,我们还有一些比较特殊的指针,无法用(void*)来表示。事实上,在C++中,想找到一个通用的指针,特别是通用的函数指针简直是一个“不可能任务”。
C++是一种静态类型的语言,类型安全在C++中举足轻重。在C语言中,你可以用void*来指向一切;但在C++中,void*并不能指向一切,就算能,也失去了类型安全的意义了。类型安全往往能帮我们找出程序中潜在的一些BUG。
下面我们来探讨一下,C++中如何存储各种类型数据的指针。
1. 数据指针
数据指针分为两种:常规数据指针和成员数据指针
1.1 常规数据指针
这个不用说明了,和C语言一样,定义、赋值是很简单明了的。常见的有:int*, double* 等等。
如:
int * pn = & value;
1.2 成员数据指针
有如下的结构:
{
int key;
int value;
};
现在有一个结构对象:
MyStruct* pMe = &me;
我们需要 value 成员的地址,我们可以:
//或
int * pValue = &pMe->value;
当然了,这个指针仍然是属于第一种范筹----常规数据指针。
好了,我们现在需要一种指针,它指向MyStruct中的任一数据成员,那么它应该是这样的子:
//或
int MyStruct::* pMK = & MyStruct::key;
这种指针的用途是用于取得结构成员在结构内的地址。我们可以通过该指针来访问成员数据:
int key = me.*pMK; // 取得me的key成员数据。
那么,在什么场合下会使用到成员数据指针呢?
确实,成员指针本来就不是一种很常用的指针。不过,在某些时候还是很有用处的。我们先来看看下面的一个函数:
{
int result = 0 ;
for(int i = 0; i < count; ++ i)
result += objs[i].* pm;
return result;
}
这个函数的功能是什么,你能看明白吗?它的功能就是,给定count个MyStruct结构的指针,计算出给定成员数据的总和。有点拗口对吧?看看下面的程序,你也许就明白了:
{
{ 1,2},{3,4},{5,6},{7,8},{9,10},{11,12},{13,14},{15,16},{17,18},{19,20 }
};
int sum_value = sum(me, &MyStruct::value, 10 );
//计算10个MyStruct结构的value成员的总和: sum_value 值 为 110 (2+4+6+8++20)
int sum_key = sum(me, &MyStruct::key, 10 );
// 计算10个MyStruct结构的key成员的总和: sum_key 值 为 100 (1+3+5+7++19)
也许,你觉得用常规指针也可以做到,而且更易懂。Ok,没问题:
{
int result = 0 ;
for(int i = 0; i < count; ++ i)
result += objs[i].value;
return result;
}
一个常量的生命周期在于本函数空间结束时结束。
void main()
{
int a=1;
for(int i=0;i<2;i++)
{
int a=9;
cout<<a<<endl;
}
cout<<a<<endl;
}
结果:
9
9
2
如果 void main()
{
int a=2;
for(int i=0;i<2;i++)
{
cout<<a<<endl;
}
cout<<a<<endl;
}
结果:
2
2
2
如果 void main()
{
for(int i=0;i<2;i++)
{
int a=2;
cout<<a<<endl;
}
cout<<a<<endl;
}
结果错误;因为在for(int i=0;i<2;i++)表达式之前a还没有生命,int a在for结束时也结束了;
第二个a还没声明;
在函数中子常量可以在父常量中的到声明;父不可以在子中的到;
1,返回函数。
int GetMin(int a,int b)
{
}
int GetMin(void){
}
2.函数体
int GetMin(int a,int b){
if(a>b)
{return b;}
else
{
return a;
}
}
不能在函数体中定义别的一个函数;
如
void func1()
{
int func2(int a,int b)
{}
}
是错的;
函数的声明
int GetMin(int a,int b);
void main(){
int a=10;
int b=20;
cout<<GetMin(a,b)<<endl;
}
int GetMin(int a,int b)
{
if(a>b)
{return b:}
else
{
return a;
}
}
}
可以在定义在main()之前,可以省略声明;
3,函数调用
#include<iostream>
using namespace std;
int GetMax(int a,int b)
{
if(a>b)
{
return b;}
esle
{
return b;
}
}
void main()
{
int a=10;
int b=20;
int c=GetMax(a,b);
cout<<C<<endl;
}
4,参数的值专递调用;
#include <iostream>
using namespace std;
void func(int a,int b);
void main()
{
int a=10;
int b=20;
func(a,b);
cout<<"a="<<a<<"b="<<b<<endl;
}
void func(int a,int b)
{
a=30;
b=40;
cout<<"a="<<a<<"b="<<b<<endl;
}
结果30,40
10,20
5,变量及作用域
(1)全局数据区:存放全局变量、静态数据和变量。
(2)代码区:函数。
(3)伐区;函数运行时分配的局部变量、函数参数、返回数据、返回地址。
(4)堆区:内存中剩下的空间由程序员负责申请和释放。
5,静态局部变量static int nCout;
6.变量与作用域。
(1)语句块级
void main()
{
int a=10;
if(a>0)
{int a=20: cout<<a<<endl;}
cout<<a<<endl:
}
(2)函数级
作用在于所定义的函数体里
(3)文件级
Examplel.cpp
static int a;
static int b;
Example2.cpp
statac int a;
static int b;
作用在于文件里
(4)程序级
#include<iosetream>
using namespace std;
void func();//函数声明
int a=0;
void main()
{
func();
cout<<aendl;
}
extetn int a;//声明外部变量
void func()
{
a=10;
}
7。内部函数和外部函数
外部:[extern]可以作用在其他文件里
内部:static 不可以作用在其他文件里
1,一维数组的定义
int a[6];
不能是void main(){
int size=10;
int array[size];
}常量表达式中可以包括数字常量和符号常量,不能包括变量。
可以void main()
{
const int size =10;//声明为常量
int array[zisz];
}
2,一维数组的初始化
(1)int a[10]={1,2,3,4,5,6,7,8,9,0}
(2)int [5];
a[0]=1;a[1]=2;a[2]=3;a[3]=4;a[4]=5;
3,二维数组的定义
int a[2][3],b[3][4];
4,二维数组的初始化
int a[2][3]={{1,2,3},{4,5,6,};
int a[2][3]={1,2,3,4,5,6};
int a[][3]={1,2,3,4,5,6};
错误有:int a[2][3];
a[2][3]={1,2,3,4,5,6}
int a[][]={1,2,3,4,5,6}
5,字符数组的定义和初始化
char c[10];
c[0]='h';c[1]='e';c[2]='l';c[3]='l';c[4]='o';c[5]='w';c[6]='o';c[7]='r';c[8]='l';c[9]='d';
char c[10]={'h','e','l','l','o','w','o','r','l','d'}
char c[11]={"helloworld"};
1,指针变量的定义
char *pc;
int *pc;
float *cp1,*cp2;
2,指针的使用
(1)指针赋值
int a;
int *pa;
pa=&a;
int *pa1,*pa2;
pa1=&a;
pa2=pa1;
指针地址不能运算
指针的初始化
int *pa=0;
3,使用指针访问变量
#include<iostream>
void main()
{
int a=10;
int *pa=&a;定义指向变量的整数指针;
cout<<*pa<<endl;通过间接访问得到指针指向的地址数据
*pa=20;间接给指向的地址数据改写数据
cout<<*pa<<endl;
}
4 void指针
int a;
int *pa=&a;
void *pv=pa;
int *p=(int *)pv;
5.const指针
1)指向常量的指针
不能通过指针改变它指向的值,可以改变的本身的值
const int a=10;
int *pa=&a;
const int b=20;
pa=&b;
常量指针不能指向其他变量
const int *pa=&a;
pa=&b;//错
6,指针与数组
#include<iostream>
using namespace std;
void main()
{
cout int nsize=10;
int i;
int a[nsize]={1,2,3,4,5,6,7,8,9,0}
int *p=a;
for(i=0;i<nsize;i++)
{cout<<*p<<";";
p++;
}
for(i=0;i<nsize;i++)
{cout<<p[i]<<";";
}
cout<<end;
}
6,动态内存分配(new与delete)
#include<iostream>
using namespace std;
void main()
{
char*pc;
int *p;
pc=new char;
pi=new int(8);
*pc='a';
cout<<*pc<<endl;
cout<<*pi<<endl;
if(pc)
delete pc;
if(pi)
delete pi;
char *pstr =new char[20];
char ste[20];
strcpy(pstr,"ti is a string");
strcpy(str,"ti is a string, too);
cout<<pstr<<endl;
cout<<str<<endl;
if(pstr)
delete pstr;
}
6,引用
int a=10;
int &ra=a;
引用操作
#includes<iostream>
using namespace std;
void main(){
int a=10;
cout<<&a<<endl;//地址
int *pa=&a;
cout<<*pa<<endl;
int &ra=a;
cout<<&ra<<endl;//地址
cout<<ra<<endl;
int *&rpa=pa;
cout<<rpa<<endl;
}