目录
b)有具体返回值函数(可返回基本数据类型或组合类型(类、结构体))
一、函数
1.函数定义
目的:为编程模块化设计
示例:找到矩阵里最大值
struct Matrix
{
int rows;//行
int cols;//列
float * pData;//数据
};
//找到矩阵里最大值
Matrix matA;
float maxa = FLT_MIN;//float类型最小值
for(int r = 0; r < matA.rows; r++)
for (int c = 0; c < matA.cols; c++)
{
float val = matA.pData[ r * matA.cols + c];//r行c列元素
maxa = ( maxa > val ? maxa : val);
}
函数定义格式
//返回类型 函数名(参数列表)
{
函数体
}
float matrix_max(struct Matrix mat)
{
float max = FLT_MIN;
for(int r = 0; r < mat.rows; r++)
for (int c = 0; c < mat.cols; c++)
{
float val = mat.pData[ r * mat.cols + c];// mat.pData==null,不该返回,对输入数据检查
max = ( max > val ? max : val);
}
return max;
}
2.函数应该放在哪里
// draw.cpp
// The function must be defined before it was called
bool drawLine(int x1, int y1, int x2, int y2)
{
// Source code here
return true;
}
bool drawRectangle(int x1, int y1, int x2, int y2)画矩形
{
// some calculation here
drawLine(...);
drawLine(...);
drawLine(...);
drawLine(...);
return true;
}
// draw.cpp
// declared first, parameter names can be omitted
bool drawLine(int x1, int y1, int x2, int y2);//声明函数,告诉编译器有这个函数
bool drawRectangle(int x1, int y1, int x2, int y2)
{
// some calculation here
drawLine(...);
drawLine(...);
drawLine(...);
drawLine(...);//调用的函数在下面
return true;
}
// define it later
bool drawLine(int x1, int y1, int x2, int y2)
{
// Source code here
return true;
}
3.更加清晰的代码组织结构
4.函数的参数
a)参数是些变量名
b)把数据从调用的环境传到被调用的环境(传参)
5.传参方式
a)传递值
基本数据类型
int foo(int x)//传的是数据拷贝,x是函数内的局部变量,作用域在花括号里
{ // x is a copy
x += 10;
return x;//拷贝
}
int main()
{
int num1 = 20;
int num2 = foo(num1);// num1不会被改变,num1和x的存储地址不同
return 0;
}
指针类型
int foo(int * p)//地址拷贝进了函数
{
(*p) += 10;
return *p;
}
int main()
{
int num1 = 20;
int * p = &num1;
int num2 = foo( p );// num1被修改,num1地址传进去
return 0;
}
结构体类型
struct Matrix
{
int rows;
int cols;
float * pData;
};
float matrix_max(struct Matrix mat)
{
float max = FLT_MIN;
for(int r = 0; r < mat.rows; r++)
for (int c = 0; c < mat.cols; c++)
{
float val = mat.pData[ r * mat.cols + c];
max = ( max > val ? max : val);
}
return max;
}
Matrix matA = {3,4};
matrix_max(matA);
MatA拷贝mat,pdata是一个地址指向数据区new12个 数据空间
b)引用(c++)
一个对象或变量的别名
基本数据类型
int num = 0;
int & num_ref = num;//&放在类型后边是引用
num_ref是num的别名
num_ref = 10;
对象引用
struct Matrix
{
int rows;
int cols;
float * pData;
};
Matrix matA = {3,4};
matA.pData = new float[matA.rows * matA.cols]{};//堆区开辟内存空间
Matrix & matA_ref = matA;
Matrix * pMatA = &matA;//4or8(32位操作系统是4字节,64位是8个字节)
指针和引用的区别
int & num_ref; // error 引用一定要初始化
Matrix & mat_ref; // error
//引用比指针更安全,指针容易越界,不会乱指
结构体很大传参怎么办
struct PersonInfo
{
char firstname[256];
char middlename[256];
char lastname[256];
char address[256];
char nationalID[16];
// and more
};
char * fullname(struct PersonInfo pi)//拷贝需要很大一块内存
{
// ...
}
char * fullname(struct PersonInfo * ppi)
{
if (ppi == NULL)
{
cerr << "Invalid pointer" << endl;
return NULL;
}
// ...
}
引用不是拷贝,效率更高
但函数内部修改mat外面的mat也会变,因为是起别名
float matrix_max(const struct Matrix & mat)//就修改不了了
{
float max = FLT_MIN;
// ...
return max;
}
const引用注意事项:
(1)对const的引用可能引用一个并非const的对象:引用的对象是常量还是非常量可以决定其能参与的操作,却无论如何都不会影响到引用和对象的绑定关系。
r2绑定(非常量)整数i是合法的行为。然而,不允许通过r2修改i的值。尽管如此,i的值仍然允许通过其他途径修改,既可以直接给i赋值,也可以通过像r1一样绑定到i的其他引用来修改。
(2)初始化的必要性: 一旦引用已经定义,它就不能再指向其他的对象.
6.返回语句
a)无具体返回值函数
void print_gender(bool isMale)//void类型函数不需要具体返回值
{
if(isMale)
cout << "Male" << endl;
else
cout << "Female" << endl;
return;//可写可不写
}
b)有具体返回值函数(可返回基本数据类型或组合类型(类、结构体))
返回也是值传递
i)基本数据类型:常量或变量值拷贝传出
ii)指针:地址拷贝出去
iii)结构体:结构体拷贝
float maxa = matrix_max(matA);//函数内的局部变量消失,拷贝给maxa
Matrix * pMat = create_matrix(4,5);
Matrix * create_matrix(int rows, int cols)
{
Matrix * p = new Matrix{rows, cols};
p->pData = new float[p->rows * p->cols]{1.f, 2.f, 3.f};
// you should check if the memory is allocated successfully
// and don’t forget to release the memory
return p;
}
c)其他情况return
矩阵加法A+B->C
bool matrix_add(const Matrix & matA, const Matrix & matB, Matrix & matC)
{
//检查A和B的宽高是否相等,不相等 return false打印错误信息
// matC是引用,释放其内存,重新创建和AB一样大小的矩阵
// do: matC = matA + matB
// return true if everything is right
}
bool 函数是否正常运行的标识
利用引用避免内存拷贝,效率高,但有可能被修改加const
OpenCV
7.内联函数(重要:关乎程序运行效率)
A)函数的调用是有代价的,每次调用把数据压栈,跳转,做完事情再回来,然后把栈取出来,再执行
如果函数复杂计算量很大这个代价可以忽略不计
如果很小的函数,频繁调用,是非常搞的代价
inline float max_function(float a, float b)
{
if (a > b)
return a;
else
return b;
}
Inline只会建议编译器inline方式编译
B)宏处理(不鼓励使用)
#define MAX_MACRO(a, b) (a)>(b) ? (a) : (b)
宏是预处理在编译之前文本替换,而且类型不定可以int,float等
注意加括号,避免优先级出问题
宏虽然效率没问题,但是很危险