1.、通过指针参数申请动态内存。
2、利用函数返回值申请动态内存。
3、返回栈内存的(或静态存储区的)指针或引用。
以上知识请参考 内存管理。
4、函数参数的三种传递方式
(1)、值传递
这个应该简单吧,来看个经典程序
#include <iostream>
#include <stdio.h>
using namespace std;
void Swap(int a,int b)
{
int temp=a;
a=b;
b=temp;
}
int main()
{
int a=10;
int b=20;
Swap(a, b);
cout<<a<<" "<<b<<endl;//10 20
return 0;
}
这个好理解,函数Swap 为 a,b制作副本,然后交换副本,然而实参没有改变,所以实际上没有交换。值传递需要进行数据的复制,制作副本,如果不是内部数据类型,那么会降低效率。
(2)、引用传递
通过引用传递,在调用函数时,不会再为形参分配内存空间因此此时形参就是实参的本身,在函数中对形参的任何操作,本质上都是对实参进行操作。
#include <iostream>
#include <stdio.h>
using namespace std;
void Swap(int &a,int &b)
{
int temp=a;
a=b;
b=temp;
cout<<"形参a的地址:"<<&a<<endl;
}
int main()
{
int a=10;
int b=20;
cout<<"变量a的地址:"<<&a<<endl;
Swap(a, b);
cout<<a<<" "<<b<<endl;
return 0;
}
(3)、指针传递
#include <iostream>
#include <stdio.h>
using namespace std;
void Swap(int *a,int *b)
{
int temp=*a;
*a=*b;
*b=temp;
cout<<"形参a的地址:"<<a<<endl;
}
int main()
{
int a=10;
int b=20;
cout<<"变量a的地址:"<<&a<<endl;
Swap(&a, &b);
cout<<a<<" "<<b<<endl;
return 0;
}
在调用函数时,int 型 变量temp和形参(指针变量a和b)被创建并用主函数中的变量a,b的地址给 形参a,b复制,这时,间接引用*a和*b实际上等价于直接对实参进行操作,虽然在函数swap执行完毕后,形参和函数内的变量都会被撤销,对应的内存也会被回收,但是函数在执行过程中已经通过指针, 改变了实参的值了。
#include<stdio.h>
#include <iostream>
using namespace std;
void swap(int *p1,int *p2)
{
int *p;
p=p1;
p1=p2;
p2=p;
cout<<"函数内"<<endl;
cout<<"p1存的地址:"<<p1<<endl;
cout<<"p2存的地址:"<<p2<<endl<<endl;
}
int main()
{
int a=10,b=20;
int *p1,*p2;
p1=&a;
p2=&b;
cout<<"函数前:"<<endl;
cout<<"p1存的地址:"<<p1<<endl;
cout<<"p2存的地址:"<<p2<<endl;
cout<<"a地址:"<<&a<<endl;
cout<<"b的地址:"<<&b<<endl<<endl;
swap(p1,p2);
cout<<"函数后"<<endl;
cout<<"p1存的地址:"<<p1<<endl;
cout<<"p2存的地址:"<<p2<<endl;
cout<<"a地址:"<<&a<<endl;
cout<<"b的地址:"<<&b<<endl;
cout<<a<<" "<<b<<endl;
cout<<*p1<<" "<<*p2<<endl;
return 0;
}
看看怎么a,b没有交换成功呢,仔细看看,明明在函数体内,二者的地址就发生了变化的,但是为什么退出来又还原了呢???
分析:请看指针传递中红色字体部分---------指针也被制作了副本,函数会制作副本,使_p1=p1 ,_p2=p2,,让两个指针(_p1,_p2)的值进行交换,但是这是副本,对真实的指针不起作用的。只用通过副本指针改变了变量的值,那么对真实的指针才有用。所以在退出函数后p1,p2又还原了。
swap函数这样改过后:
void swap(int **p1,int **p2)
{
int *p;
p=*p1;
p1=p2;
p2=&p;
cout<<"函数内"<<endl;
cout<<"p1存的地址:"<<p1<<endl;
cout<<"p2存的地址:"<<p2<<endl<<endl;
}
关于二级指针请参看 指针与数组
a ,b实际上还是没有交换,但是两个指针的值却发生了交换(p1指向了b,p2指向了a),可以看出,指针也是一个普通的变量,也存在指针式的”值传递“方式,如果需要改变指针的值,那么需要对指针采用”指针传递“或"引用传递"的方式,说白了就是需要传入指针的地址。
void swap( int **p1, int **p2)
{
int *p3,*p4,temp;
p3=*p1;
p4=*p2;
temp=*p3;
*p3=*p4;
*p4=temp;
}
这种同上,其实意思都是一样,p1指向的是一个存变量地址的指针(*p1),p3=*p1,让指针p3指向了*p1,然后交换了*p3,*p4,也是就交换了*p1与*p2的值,所以改变了它们的指向。
#include<stdio.h>
#include <iostream>
using namespace std;
void Swap(int **p1, int **p2)
{
int temp;
temp=**p1;
**p1=**p2;
**p2=temp;
}
int main()
{
int a=10,b=20;
int *p1,*p2;
p1=&a;
p2=&b;
int **p3=&p1;
int **p4=&p2;
int temp;
temp=**p3;
**p3=**p4;
**p4=temp;
//或者swap(&p1,&p2);
cout<<a<<" "<<b<<endl;
cout<<*p1<<" "<<*p2<<endl;
return 0;
}
这种就可以改变实参的值,而没有改变指针的指向。
再看看这个肯定就更清楚了
#include <stdio.h>
void func(int* ptr, int &value)
{
ptr = &value;
}
int main()
{
int i = 10, j = 5;
int *ptr = &i;
func( ptr, j);
printf("%d", *ptr);
return 0;
}
结果是好多呢-----------自己运行一下吧
5、缺省参数调用
在函数声明语句中预先初始化一些参数的值,在调用语句中相应地参数可以缺省。
#include <iostream>
#include <stdio.h>
using namespace std;
void show(char *str,int n=1)
{
for (int i=0; i<n; i++)
{
cout<<str[i];
}
cout<<endl;
}
int main()
{
char str[]="hello";
show(str,4);
show(str);
return 0;
}
缺省参数调用规则:
(1)参数缺省必须按照从后向前的顺序,下面这个函数声明是不合法的
void show(char *str,int n=1,int m)
换句话说,在函数声明时,如果对第n个参数进行初始化,那么 它后面的所有参数都应该进行初始化,所以,在函数定义时,应该合理安排形参列表的顺序。
(2)和函数声明一样,在函数调用时省略某个参数,必须省略其后面所有的参数。
void show(char *str,int n=1,int m=4);
show(str,,4);//非法
7、指针函数
先看下面的函数声明,注意,此函数有返回值,返回值是指针类型的。
char *GetMerory()
用法举例:
<span style="font-size:14px;">#include <iostream>
#include <stdio.h>
using namespace std;
char *GetMerory()
{
char *p=(char*)malloc(sizeof(char)*10);
return p;
}
int main()
{
char *str;
str=GetMerory();
strcpy(str, "hello");
cout<<str<<endl;
free(str);
return 0;
}</span>
8、函数指针
顾名思义函数指针就是指向函数的指针
通过函数指针可以很方便的调用函数。
声明方式(必须要括号哟):
int (*Compare)(const char*,const char*);
举例:
#include <iostream>
#include <stdio.h>
using namespace std;
int (*Fun)(const char*,const char*);
int Display(const char *s1,const char *s2)
{
cout<<s1<<endl;
cout<<s2<<endl;
return 0;
}
int main()
{
char s1[]="hello";
char s2[]="hello word";
Fun=strcmp;
int result=Fun(s1,s2);
if(result==0)
{
cout<<"两个字符串不相等";
}
else if(result==1)
{
cout<<"第一个字符串大";
}
else
{
cout<<"第二个字符串大";
}
cout<<endl;
Fun=Display;
Fun(s1,s2);
cout<<endl;
return 0;
}
通过函数指针将函数作为另一个函数的参数(注意返回类型要一致)
#include <iostream>
#include <stdio.h>
using namespace std;
void (*fun)(int);
void Display(int i)
{
cout<<i<<" ";
}
void Call(void(*fun)(int))
{
int a[4]={1,2,3,4};
for (int i=0; i<4; i++)
{
fun(a[i]);
}
cout<<endl;
}
int main()
{
fun=Display;
Call(fun);
return 0;
}
指向函数的指针还可以组成指针数组,称为函数指针数组。
#include <iostream>
#include <stdio.h>
using namespace std;
void (*fun[4])(int);
void Sub_Print(int i)
{
cout<<i-1<<" ";
}
void Add_print(int i)
{
cout<<i+1<<" ";
}
void Print(int i)
{
cout<<i<<" ";
}
void Call(char *name[],void(*fun[])(int))
{
int a[4]={1,2,3,4};
for (int k=0; k<3; k++)
{
cout<<name[k]<<endl;
for (int i=0; i<4; i++)
{
fun[k](a[i]);
}
cout<<endl;
}
}
int main()
{
char *name[]={"输出","减1输出","加1输出"};
fun[0]=Print;
fun[1]=Sub_Print;
fun[2]=Add_print;
Call(name,fun);
cout<<endl;
return 0;
}
采用typedef简化函数指针
#include <iostream>
#include <stdio.h>
using namespace std;
typedef void (*f)(int);
void Sub_Print(int i)
{
cout<<i-1<<" ";
}
void Add_print(int i)
{
cout<<i+1<<" ";
}
void Print(int i)
{
cout<<i<<"";
}
void Call(const char *name,f fun )
{
int a[4]={1,2,3,4};
cout<<name<<endl;
for (int i=0; i<4; i++)
{
fun(a[i]);
}
}
int main()
{
char *name[]={"输出","减1输出","加1输出"};
f fun[]={Print,Sub_Print,Add_print};
for (int i=0; i<3; i++)
{
Call(name[i], fun[i]);
cout<<endl;
}
return 0;
}
和普通指针一样,函数指针也可以作为另一个函数的返回值
#include <iostream>
#include <stdio.h>
using namespace std;
typedef int (*f)(int,int);
int Add(int m,int n)
{
return m+n;
}
int Multiplay(int m,int n)
{
return m*n;
}
f lookup(int choice)
{
if(choice==0)
{
return Add;
}
else
{
return Multiplay;
}
}
int main()
{
int num1,num2,x,result;
cout<<"请输入两个整数以选择要进行的操作:";
cin>>num1>>num2;
cout<<"相加(0),相乘(其它):";
cin>>x;
f fun=lookup(x);
result=fun(num1,num2);
cout<<"结果:"<<result<<endl;
return 0;
}
带参主函数
实际上main函数也可以带参数,main函数的操作是由操作系统来传的,c++规定main函数的参数只能有两个,agrc,argv.
第一个参数agrc必须是整型变量,称作参数计数器,其值包括命令名在内的参数的个数,第二个参数argv必须是指向字符指针数组,存放命令名和参数字符串的地址。
#include <iostream>
#include <stdio.h>
using namespace std;
int main(int argc,char *argv[])
{
for (int i=argc-1; i>=0; i--)
{
cout<<argv[i]<<endl;
}
return 0;
}
编译链接上面代码文件,假设名字为example.exe,复制到c盘根目录下,在DOS环境下输入命令。
附上在Mac上的测试数据(命令不一样):
数组名做参数(这里说说多维数组做参数):
多维数组做函数参数,第一维的大小可以省略,但是其它维大小不能省略。
#include <iostream>
#include <stdio.h>
using namespace std;
int a[2][3][4];
void Display(int a[][3][4],int n)
{
for (int i=0; i<n; i++)
{
for (int j=0; j<3; j++)
{
for (int k=0; k<4; k++)
{
cout<<a[i][j][k]<<" ";
}
}
}
}
int main()
{
for (int i=0; i<2; i++)
{
for (int j=0; j<3; j++)
{
for (int k=0; k<4; k++)
{
a[i][j][k]=i+j+k;
}
}
}
Display(a,2);
return 0;
}