一、数组名和指针的深入理解
指针是C/C++语言的特色,而数组名与指针有太多的相似,甚至很多时候,数组名可以作为指针使用。于是乎,很多程序设计者就被搞糊涂了。
魔幻数组名
请看程序(本文程序在WIN32平台下编译):
#include <iostream> using namespace std; int main() { char str[10]; char* pStr = str; cout << "sizeof(str): \t" << sizeof(str) << endl; cout << "sizeof(pStr): \t" << sizeof(pStr) << endl; system("pause"); return 0; }
1、数组名不是指针
我们先来推翻"数组名就是指针"的说法,用反证法。
证明 数组名不是指针
假设:数组名是指针;
则:pStr和str都是指针;
因为:在WIN32平台下,指针长度为4;
所以:sizeof(str)和sizeof(pStr)的输出都应该为4;
实际情况是:
图片内容为:
sizeof(str):10
sizeof(str):4
所以:假设不成立,数组名不是指针
2、数组名神似指针
上面我们已经证明了数组名的确不是指针,但是我们再看看程序的这一:char* pStr = str;。该行程序将数组名直接赋值给指针,这显得数组名又的确是个指针!
我们还可以发现数组名显得像指针的例子:
#include <iostream> using std::cout; using std::endl; int main() { char str1[10] = "I love U."; char str2[10]; strcpy(str2, str1); cout << "string array 1: " << str1 << endl; cout << "string array 2: " << str2 << endl; system("pause"); return 0; }
标准C库函数strcpy的函数原形中能接纳的两个参数都为char型指针,而我们在调用中传给它的却是两个数组名!
函数输出:
图片内容为:
string array 1:I Love U.
string array 2:I Love U.
数组名再一次显得像指针!
既然数组名不是指针,而为什么到处都把数组名当指针用?
揭密数组名(对上面的总结)
现在到揭露数组名本质的时候了,先给出三个结论:
(1)数组名的内涵在于其指代实体是一种数据结构,这种数据结构就是数组;
(2)数组名的外延在于其可以转换为指向其指代实体的指针,而且是一个指针常量;
(3)指向数组的指针则是另外一种变量类型(在WIN32平台下,长度为4),仅仅意味着数组的存放地址!
1、数组名指代一种数据结构:数组(数组也是一种数据结构)
现在可以解释为什么第1个程序的这一行:sizeof(str);的输出为10的问题,根据结论1,数组名str的内涵为一种数据结构,即一个长度为10的char型数组,所以sizeof(str)的结果为这个数据结构占据的内存大小:10字节。
再看:
2. cout << sizeof(intArray) ;
第2行的输出结果为40(整型数组占据的内存空间大小)。
如果C/C++程序可以这样写:
2. cout << sizeof(intArray) ;
我们就都明白了,intArray定义为int[10]这种数据结构的一个实例,可惜啊,C/C++目前并不支持这种定义方式。
2、数组名可作为指针常量
根据结论2,数组名可以转换为指向其指代实体的指针,所以程序1中的第5行数组名直接赋值给指针,程序2第7行直接将数组名作为指针形参都可成立。
下面的程序成立吗?
2. intArray++;
读者可以编译之,发现编译出错。原因在于,虽然数组名可以转换为指向其指代实体的指针,但是它只能被看作一个指针常量,不能被修改。
而指针,不管是指向结构体、数组还是基本数据类型的指针,都不包含原始数据结构的内涵,在WIN32平台下,sizeof操作的结果都是4。
顺 便纠正一下许多程序员的另一个误解。许多程序员以为 sizeof是一个函数,而实际上,它是 一个操作符,不过其使用方式看起来的确太像一个函数了。语句sizeof(int)就可以说明sizeof的确不是一个函数,因为函数接纳形参(一个变量),世界上没有一个C/C++函数接纳一个数据类型(如int)为"形参"。
3、数组名可能失去其数据结构内涵 (变成一个很平民的指针)
请看下面一段程序:
#include <iostream> using std::cout; using std::endl; void arrayTest(char str[]) { cout << "sizeof(str):" << sizeof(str) << endl; } int main() { char str1[10] = "I love U."; arrayTest(str1); system("pause"); return 0; }
程序的输出结果为:
图片内容为:
sizeof(str):4
一个可怕的数字,前面已经提到其为指针的长度!
结论1指出,数组名内涵为数组这种数据结构,在arrayTest函数体内,str1是数组名,那为什么sizeof的结果却是指针的长度?这是因为:
(1)数组名作为函数形参时,在函数体内,其失去了本身的内涵,仅仅只是一个指针;
(2)很遗憾,在失去其内涵的同时,它还失去了其常量特性,可以作自增、自减等操作,可以被修改。
所以,数组名作为函数形参时,其全面沦落为一个普通指针!它的贵族身份被剥夺,成了一个地地道道的只拥有4个字节的平民。
参考:http://www.cnblogs.com/wuzhenbo/archive/2012/05/29/2523777.html
二、函数名与函数指针
一、 通常的函数调用
一个通常的函数调用的例子:
#include <iostream> using std::cout; using std::endl; void MyFun(int x); //此处也可以声明为:void Myfun(int); int main() { MyFun(10); //这里是调用MyFun(int x);函数 system("pause"); return 0; } void MyFun(int x) { cout << "x: " << x << endl; }
这个MyFun函数是一个无返回值的函数,他相当于把MyFun函数的主体放到主函数中。看主函数中调用MyFun函数的书写格式:MyFun(10);
思考:函数名到底又是什么东西呢?
(不要以为这是没有什么意义的事噢!)
二、 函数指针变量的声明
就象某一数据变量的内存地址可以存储在相应的指针变量中一样,函数的首地址也以存储在某个函数指针变量里的。这样,我就可以通过这个函数指针变量来调用所指向的函数了。
在C++系列语言中,任何一个变量,总是要先声明,之后才能使用的。那么,函数指针变量也应该要先声明吧?那又是如何来申明呢?以上面的例子为例,来声明一个可以指向MyFun函数的函数指针变量FunP。
申明FunP变量的方法:void (*FunP)(int) ; 也可写成void (*FunP)(int x);
整个函数指针变量的申明格式如同函数MyFun的申明处一样,只不过,把MyFun改成(*FunP)而已,这样就有了一个能指向MyFun函数的指针FunP了。(当然,这个FunP指针变量也可以指向所有其它具有相同参数及返回值的函数了。)
三、 通过函数指针变量调用函数
有了FunP指针变量后,我们就可以对它赋值指向MyFun,然后通过FunP来调用MyFun函数了。
如何通过FunP指针变量来调用MyFun函数的:
#include <iostream> using std::cout; using std::endl; void MyFun(int x); //此处也可以声明为:void Myfun(int); void (*FunP)(int); //声明一个用以指向同样参数,返回值函数的指针变量 int main() { MyFun(10); //这里是调用MyFun(int x);函数 FunP = &MyFun; //将MyFun函数的地址赋给FunP变量 (*FunP)(20); //这是通过函数指针变量FunP来调用MyFun函数的 system("pause"); return 0; } void MyFun(int x) //MyFun函数的定义 { cout << "x: " << x << endl; }
#include <iostream> using std::cout; using std::endl; void MyFun(int x); //此处也可以声明为:void Myfun(int); void (*FunP)(int); //申明一个用以指向同样参数,返回值函数的指针变量 int main() { MyFun(10); //这里是调用MyFun(int x);函数 FunP = MyFun; //将MyFun函数的地址赋给FunP变量 (*FunP)(20); //这是通过函数指针变量FunP来调用MyFun函数的 system("pause"); return 0; } void MyFun(int x) //MyFun函数的定义 { cout << "x: " << x << endl; }
#include <iostream> using std::cout; using std::endl; void MyFun(int x); //此处也可以声明为:void Myfun(int); void (*FunP)(int); //申明一个用以指向同样参数,返回值函数的指针变量 int main() { MyFun(10); //这里是调用MyFun(int x);函数 FunP = &MyFun; //将MyFun函数的地址赋给FunP变量 FunP(20); //这里是通过函数指针变量来调用MyFun函数的 system("pause"); return 0; } void MyFun(int x) //MyFun函数的定义 { cout << "x: " << x << endl; }
代码之四:
#include <iostream> using std::cout; using std::endl; void MyFun(int x); //此处也可以声明为:void Myfun(int); void (*FunP)(int); //申明一个用以指向同样参数,返回值函数的指针变量 int main() { MyFun(10); //这里是调用MyFun(int x);函数 FunP = MyFun; //将MyFun函数的地址赋给FunP变量 (*FunP)(20); //这里是通过函数指针变量来调用MyFun函数的 system("pause"); return 0; } void MyFun(int x) //MyFun函数的定义 { cout << "x: " << x << endl; }
#include <iostream> using std::cout; using std::endl; void MyFun(int x); //此处也可以声明为:void Myfun(int); void (*FunP)(int); //申明一个用以指向同样参数,返回值函数的指针变量 int main() { (*MyFun)(10); //看,函数名MyFun也可以有这样的调用格式 FunP = MyFun; //将MyFun函数的地址赋给FunP变量 (*FunP)(20); //这里是通过函数指针变量来调用MyFun函数的 system("pause"); return 0; } void MyFun(int x) //MyFun函数的定义 { cout << "x: " << x << endl; }
#include <iostream> using std::cout; using std::endl; void MyFun(int x); //此处也可以声明为:void Myfun(int); typedef void (*FunType)(int); //这样只是定义一个指针类型 FunType FunP; //然后用FunType类型来声明全局Funp变量 int main() { //FunType Funp; //函数指针变量当然也可以是局部的,那就请在这里声明 (*MyFun)(10); //看,函数名MyFun也可以有这样的调用格式 FunP = &MyFun; //将MyFun函数的地址赋给FunP变量 (*FunP)(20); //这里是通过函数指针变量来调用MyFun函数的 system("pause"); return 0; } void MyFun(int x) //MyFun函数的定义 { cout << "x: " << x << endl; }
看黑体部分:
首先,在void (*FunType)(int ); 前加了一个typedef 。这样只是定义一个名为FunType函数指针类型,而不是一个FunType变量。
然后,FunType FunP; 这句就如PINT px;一样地申明一个FunP变量。
其它相同。整个程序完成了相同的事。
这样做法的好处是:
有了FunType类型后,我们就可以同样地、很方便地用FunType类型来声明多个同类型的函数指针变量了。如下:
FunType FunP2;
FunType FunP3;
//……
六、 函数指针作为某个函数的参数:
既然函数指针变量是一个变量,当然也可以作为某个函数的参数来使用的。所以,还应知道函数指针是如何作为某个函数的参数来传递使用的。
给你一个实例:
要求:要设计一个CallMyFun函数,这个函数可以通过参数中的函数指针值不同来分别调用MyFun1、MyFun2、MyFun3这三个函数(注:这三个函数的定义格式应相同)。
实现:代码如下:
#include <iostream> using std::cout; using std::endl; void MyFun1(int x); void MyFun2(int x); void MyFun3(int x); typedef void(*FunType)(int); //2.定义一个函数指针FunType, 与1.函数类型一直 void CallMyFun(FunType fp, int x); int main() { CallMyFun(MyFun1, 10); //5.通过CallMyFun函数分别调用三个不同的函数 CallMyFun(MyFun2, 20); CallMyFun(MyFun3, 30); system("pause"); return 0; } void CallMyFun(FunType fp, int x) //3.参数fp的类型是Funtype { fp(x); //4.通过fp的指针执行传递进来的函数,注意fp所知的函数时有一个参数的 } void MyFun1(int x) { cout << "MyFun1: " << x << endl; } void MyFun2(int x) { cout << "MyFun1: " << x << endl; } void MyFun3(int x) { cout << "MyFun1: " << x << endl; }
分析见注释。
参考:http://www.cnblogs.com/wuzhenbo/archive/2012/05/29/2524400.html
三、函数参数的传递问题(一级指针和二级指针)
程序1:
void myMalloc(char *s) //我想在函数中分配内存,再返回
{
s=(char *) malloc(100);
}
void main()
{
char *p=NULL;
myMalloc(p); //这里的p实际还是NULL,p的值没有改变,为什么?
if(p) free(p);
}
程序2:
void myMalloc(char **s)
{
*s=(char *) malloc(100);
}
void main()
{
char *p=NULL;
myMalloc(&p); //这里的p可以得到正确的值了
if(p) free(p);
}
程序3:
#include <iostream> using namespace std; void fun(int *p) { int b = 100; p = &b; } main() { int a = 10; int *q; q = &a; printf("%d\n", *q); fun(q); printf("%d\n", *q); system("pause"); return 0; }
结果:
图片内容为:
10
10
程序4:
#include <iostream> using namespace std; void fun(int *p) { *p = 100; } main() { int a = 10; int *q; q = &a; printf("%d\n", *q); fun(q); printf("%d\n", *q); system("pause"); return 0; }
结果为
图片内容为:
10
100
为什么?
---------------------------------------------------------------
1.被分配内存的是形参s,p没有分配内存;
2.被分配内存的是形参s指向的指针p,所以分配了内存。
---------------------------------------------------------------
不是指针没明白,是函数调用的问题!看看这段:
程序5指针参数是如何传递内存的?
如果函数的参数是一个指针,不要指望用该指针去申请动态内存。程序5中,Test函数的语句GetMemory(str, 200)并没有使str获得期望的内存,str依旧是NULL,为什么?
#include <iostream> using namespace std; void GetMemory1(char *p, int num) { p = (char *)malloc(sizeof(char)*num); } int main() { char *str = NULL; GetMemory1(str, 100); // str仍然为 NULL strcpy(str, "hello") // 运行错误
system("pause"); return 0; }
程序5 试图用指针参数申请动态内存
毛病出在函数GetMemory中。编译器总是要为函数的每个参数制作临时副本,指针参数p的副本是 _p,编译器使 _p = p。如果函数体内的程序修改了_p的内容,就导致参数p的内容作相应的修改。这就是指针可以用作输出参数的原因。在本例中,_p申请了新的内存,只是把_p所指的内存地址改变了,但是p丝毫未变。所以函数GetMemory并不能输出任何东西。事实上,每执行一次GetMemory就会泄露一块内存,因为没有用free释放内存。
如果非得要用指针参数去申请内存,那么应该改用“指向指针的指针”,见程序6
#include <iostream> using namespace std; void GetMemory2(char **p, int num) { *p = (char *)malloc(sizeof(char)*num); } int main() { char *str = NULL; GetMemory2(&str, 100); // 注意参数是&str,而不是str strcpy(str, "hello"); cout << str << endl; free(str); system("pause"); return 0; }
程序6用指向指针的指针申请动态内存
由于“指向指针的指针”这个概念不容易理解,我们可以用函数返回值来传递动态内存。这种方法更加简单,见示例7-4-3。
#include <iostream> using namespace std; char *GetMemory3(int num) { char *p = (char *)malloc(sizeof(char)*num); return p; } int main() { char *str = NULL; str = GetMemory3(100); strcpy(str, "hello"); cout << str << endl; free(str); system("pause"); return 0; }
程序7 用函数返回值来传递动态内存
用函数返回值来传递动态内存这种方法虽然好用,但是常常有人把return语句用错了。这里强调不要用return语句返回指向“栈内存”的指针,因为该内存在函数结束时自动消亡,见程序8。
#include <iostream> using namespace std; char *GetString(void) { char p[] = "hello world"; return p; //编译器将提出警告 } int main() { char *str = NULL; str = GetString(); //str 的内容是垃圾 cout << str << endl; system("pause"); return 0; }
结果:
图片内容为:
Q=放假啊克雷格(乱码)
程序8 return语句返回指向“栈内存”的指针
用调试器逐步跟踪主函数,发现执行str = GetString语句后str不再是NULL指针,但是str的内容不是“hello world”而是垃圾。
如果把示例程序7改写成程序8,会怎么样?
#include <iostream> using namespace std; char *GetString2(void) { char *p = "hello world"; return p; //编译器将提出警告 } int main() { char *str = NULL; str = GetString2(); //str 的内容是垃圾 cout << str << endl; system("pause"); return 0; }
程序8 return语句返回常量字符串
函数程序8运行虽然不会出错,但是函数GetString2的设计概念却是错误的。因为GetString2内的“hello world”是常量字符串,位于静态存储区,它在程序生命期内恒定不变。无论什么时候调用GetString2,它返回的始终是同一个“只读”的内存块。
---------------------------------------------------------------
看看林锐的《高质量的C/C++编程》,上面讲得很清楚的
---------------------------------------------------------------
对于1和2:
如果传入的是一级指针S的话,
那么函数中将使用的是S的拷贝,
要改变S的值,只能传入指向S的指针,即二级指针
---------------------------------------------------------------
程序1:
void myMalloc(char *s) //我想在函数中分配内存,再返回
{
s=(char *) malloc(100); // s是值参, 函数返回后就回复传递前的数值,无法带回分配的结果
}
这个和调用 void func (int i) {i=1;}; 一样,退出函数体,i指复原的
程序2:void myMalloc(char **s)
{
*s=(char *) malloc(100); // 这个是可以的
}
等价于
void int func(int * pI) {*pI=1;} pI指针不变,指针指向的数据内容是变化的
值参本身不变,但是值参指向的内存的内容发生了变化。
程序3:
void fun(int *p)
{
int b=100;
p=&b; // 等同于第一个问题, b的地址并没有被返回
}
程序4:
void fun(int *p)
{
*p=100; // okay
}
结论:
1. 函数的返回值是指针类型的,检查是静态内存指针还是堆内存指针还是栈内存指针,栈内存指针是绝对要不得滴!
2. 函数需要使用指针参数进行传入传出的,在函数中只能对指针的指向的值(*p)进行修改,而不能修改指针指向,也就是指针地址!(函数中不得修改指针参数的地址,否则请使用指针的指针!)
参考:http://www.cnblogs.com/wuzhenbo/archive/2012/06/13/2547664.html
四、int* pInt = new int(5);和int* pInt = new int[5];
int *p = new int(5);
这句是从堆上分配一个int型变量所占的字节内存,这个内存单元存放的整数值为5,然后让一个整形的指针变量p指向它的地址。
释放方式:delete p;
int *p = new int[5];
这句相当于从堆上分配一个含有5个元素的整形数组所占的字节内存,然后让一个整形的指针变量p指向它的首址。
释放方式:delete []p;(注意这个[]不能掉了,如果掉了就会只释放P[0]所占的空间,p[1]到p[4]不会被释放,产生内存泄露。)
五、数组作为函数参数及作为函数模版参数的总结
今天编程序时发生了个这样的错误:
在头文件里 定义了一个数组:


1 char s[]="1234567890";
又定义了一个现显示组的函数:


1 void Display(char* c);
通过下面这两条语句分别在现实函数和主函数中现实数组的大小:


1 sizeof(c); 2 sizeof(s);
现实结果却大相径庭,在主函数中为11,在现实函数中却为4。
经过思考发现,在主函数中s代表的是一个数组,而在现实函数中c代表的是一个指向数组头的指针。数组的大小为11,指针的大小为4。
主程序如下:


1 #include<iostream> 2 #include<stdlib.h> 3 using namespace std; 4 5 char s[]="1234567890"; 6 void Display(char* c); 7 8 void main() 9 { 10 char a; 11 cout<<"这个是在主函数中对数组长度的测试:"<<sizeof(s)<<endl; 12 Display(s); 13 cin>>a; 14 } 15 16 17 void Display(char* c) 18 { 19 cout<<"这个是在子函数中对数组长度的测试:"<<sizeof(c)<<endl; 20 }
现实结果:
我的问题是怎样可以在主函数和子函数中都指的是数组而不是一个指向数组头的指针???
在网上查了几种将数组作为函数参数进行传递的方法,列举如下:


1 #include<iostream> 2 #include<stdlib.h> 3 #include<vector> 4 using namespace std; 5 6 char s[]="1234567890"; 7 int a[10]={0,1}; 8 int b[10]={0,1}; 9 void Display(char* c); 10 void PutArray1(int *p,int length1); 11 void PutArray2(int p[],int length1); 12 void PutArray3(int p[10]); 13 void PutArray4(int (&p)[10]); 14 void PutArray5(vector<int>verc); 15 16 void main() 17 { 18 char q; 19 cout<<"这个是在主函数中对数组长度的测试:"<<sizeof(s)<<endl; 20 Display(s); 21 cout<<"*********************************************"<<endl; 22 PutArray1(a,10); 23 PutArray2(a,10); 24 PutArray3(a); 25 PutArray4(b); 26 cin>>q; 27 } 28 29 30 void Display(char* c) 31 { 32 cout<<"这个是在子函数中对数组长度的测试:"<<sizeof(c)<<endl; 33 } 34 void PutArray1(int *p,int length1) 35 { 36 int length2=sizeof(p); 37 cout<<"第一种方法的输出:"<<endl; 38 cout<<"第一种方法数组的长度为:"<<length2<<endl; 39 for(int i=0;i<length1;i++) 40 { 41 cout<<p[i]; 42 } 43 cout<<endl; 44 } 45 void PutArray2(int p[],int length1) 46 { 47 int length2=sizeof(p); 48 cout<<"第二种方法的输出:"<<endl; 49 cout<<"第二种方法数组的长度为:"<<length2<<endl; 50 for(int i=0;i<length1;i++) 51 { 52 cout<<p[i]; 53 } 54 cout<<endl; 55 } 56 void PutArray3(int p[10]) 57 { 58 int length2=sizeof(p); 59 cout<<"第三种方法的输出:"<<endl; 60 cout<<"第三种方法数组的长度为:"<<length2<<endl; 61 for(int i=0;i<9;i++) 62 { 63 cout<<p[i]; 64 } 65 cout<<endl; 66 } 67 void PutArray4(int (&p)[10]) 68 { 69 int length2=sizeof(p); 70 cout<<"第四种方法的输出:"<<endl; 71 cout<<"第四种方法数组的长度为:"<<length2<<endl; 72 for(int i=0;i<9;i++) 73 { 74 cout<<p[i]; 75 } 76 cout<<endl; 77 } 78 void PutArray5(vector<int>verc) 79 { 80 vector<int>::iterator begin_iter=verc.begin(); 81 vector<int>::iterator end_iter=verc.end(); 82 int size=verc.size(); 83 cout<<"第五种方法的输出:"<<endl; 84 cout<<"第五种方法数组的长度为:"<<size<<endl; 85 cout<<"下面这种方法是采用向量遍历的方法遍历数组:"<<endl; 86 for(vector<int>::iterator iter=begin_iter;iter!=end_iter;iter++) 87 { 88 cout<<*iter; 89 } 90 cout<<endl; 91 cout<<"下面这种方法是采用普通遍历数组的方法遍历数组:"<<endl; 92 for(int i=0;i<size-1;i++) 93 { 94 cout<<verc[i]; 95 } 96 cout<<endl; 97 }
在这里,int *arr和int arr[]的含义相同,编译器自动将 int arr[]替换为int *arr,所以这也解释了上面在主函数和子函数中利用数组名求数组长度会得到不同结果的原因。这种情况只有在数组作为函数参数进行传递时才会发生(C++ Primer Plus,P192)。
其中第四种方法没有理解,疑问暂时留在这里吧。
另外虽然上面四种方法都可以正确地在子函数中传递数组作为参数,但是仍然不能满足博客刚开始的要求:在子函数中可以测的参数数组的长度。后来查看C++ Primer Plus发现书上已经明确指出没有实现这种想法的方法,数组的长度必须在函数中作为参数进行传递。
另外由于第五种方法需要重新定义向量模版,和主题不符,所以在主函数里并没有调用它。例程中给的程序如下所示:


1 vector<int> verc1(a,a+10); 2 vector<int> verc2(b,b+8); 3 PutArray5(verc1); 4 PutArray5(verc2);
上面这五种调用数组的方法只是在传递数组的方式上不同,可以归纳为传递数组的一种方法,即:传递指向数组头的指针和数组的长度。另外一种传递数组的方法是将指向数组头的指针和指向数组尾的指针作为两个参数进行传递,函数定义如下:


1 int sum_arr(const int* begin,const int* end);
在学习这个知识点时是有一些感想的,虽说C++ Primer已经看了一遍,里面的知识点也认真地消化过,但是一到用的时候就使不上劲。看来应该在看书的同时多实践书上的代码,这样才能对代码的应用有更好的理解。
本篇收集自:http://www.cnblogs.com/tziyachi/archive/2012/02/11/2347073.html
我看了下,方法4在方法声明时就固定了数组的使用长度了,没有任何灵活性可言,方法5没看懂,有空再说把。不过发现一个终极解决方案如下:
我们知道,在C/C++中,向一个函数传递数组时,实际上传送的是这个数组的首地址,也即是一个指针类型。所以,在函数中,我们没有办法知道这个传递进来的数组的长度到底为多长,一个普遍的方法就是再增加一个参数,来记录传递进来的数组的长度。
不过在C++中,使用模板机制,可以很好地解决这个问题,如下面的代码所示:
#include <iostream>
using namespace std;
template<class T, int N>
void array(T (¶m)[N])
{
cout << "N= " << N << endl;
}
int main()
{
int i[100];
double d[20];
char c[6];
array(i);
array(d);
array(c);
return 0;
} 来源:
【补充个东西,函数模版的模版非类型参数,原始定义在书中是这样的:
template<class T,int size>
T max(T(&array)[size])
{
//函数体
}
上面模版方法定义中,size是一个模版非类型参数,专门用来表示数组array的长度,需要在编译之前确定他的值。
】