• A compound statement may be needed to execute many times
  • You can copy them several times, but you can use functions ```cpp

    include

    include

struct Matrix { int rows; int cols; float *pData; };

int main() { using namespace std;

  1. Matrix matA = {3, 4};
  2. matA.pData = new float[matA.rows * matA.cols]{1.f, 2.f, 3.f};
  3. Matrix matB = {4, 8};
  4. matB.pData = new float[matB.rows * matB.cols]{10.f, 20.f, 30.f};
  5. Matrix matC = {4, 2};
  6. matC.pData = new float[matC.rows * matC.cols]{100.f, 200.f, 300.f};
  7. // some operations on the matrices
  8. float maxa = FLT_MIN;
  9. float maxb = FLT_MIN;
  10. float maxc = FLT_MIN;
  11. //find max value of matA
  12. for (int r = 0; r < matA.rows; r++)
  13. for (int c = 0; c < matA.cols; c++)
  14. {
  15. float val = matA.pData[r * matA.cols + c];
  16. maxa = (maxa > val ? maxa : val);
  17. }
  18. //find max value of matB
  19. for (int r = 0; r < matB.rows; r++)
  20. for (int c = 0; c < matB.cols; c++)
  21. {
  22. float val = matB.pData[r * matB.cols + c];
  23. maxb = (maxb > val ? maxb : val);
  24. }
  25. //find max value of matC
  26. for (int r = 0; r < matC.rows; r++)
  27. for (int c = 0; c < matC.cols; c++)
  28. {
  29. float val = matC.pData[r * matC.cols + c];
  30. maxc = (maxc > val ? maxc : val);
  31. }
  32. cout << "max(matA) = " << maxa << endl;
  33. cout << "max(matB) = " << maxb << endl;
  34. cout << "max(matC) = " << maxc << endl;
  35. delete[] matA.pData;
  36. delete[] matB.pData;
  37. delete[] matC.pData;
  38. return 0;

}

// result // max(matA) = 3 // max(matB) = 30 // max(matC) = 300

上面代码中,构建了三个结构体实例,找出每个结构体中最小的元素,那么不使用函数的话,会依次对三个结构体的`pData`进行遍历比较,得到结果,相似的运算会重复执行三遍。

So, We can put the compound statement into a function.
```cpp
#include <iostream>
#include <float.h>

struct Matrix
{
    int rows;
    int cols;
    float *pData;
};

float matrix_max(struct Matrix mat)
{
    float max = FLT_MIN;
    //find max value of mat
    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 *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
    return p;
}

bool matrix_add(const Matrix &matA, const Matrix &matB, Matrix &matC)
{
    // check the dimensions of the three matrices
    // re-create matC if needed
    // do: matC = matA + matB
    // return true if everything is right
    return true;
}

int main()
{
    using namespace std;

    Matrix matA = {3, 4};
    matA.pData = new float[matA.rows * matA.cols]{1.f, 2.f, 3.f};

    Matrix matB = {4, 8};
    matB.pData = new float[matB.rows * matB.cols]{10.f, 20.f, 30.f};

    Matrix matC = {4, 2};
    matC.pData = new float[matC.rows * matC.cols]{100.f, 200.f, 300.f};

    // some operations on the matrices

    float maxa = matrix_max(matA);
    float maxb = matrix_max(matB);
    float maxc = matrix_max(matC);

    cout << "max(matA) = " << maxa << endl;
    cout << "max(matB) = " << maxb << endl;
    cout << "max(matC) = " << maxc << endl;

    delete[] matA.pData;
    delete[] matB.pData;
    delete[] matC.pData;

    return 0;
}
  • If Matrix::pData is NULL or an invalid value, how to tell the calling function from the called one?
    • The pointer should be checked first!
    • 函数一开始,需要对数据进行一系列严谨的检查

函数在程序中的位置

  • 函数必须在其被调用之前定义
  • 或者先声明,然后函数的调用和实现的顺序就没关系了。声明的时候需要返回类型,函数名字,参数列表,参数列表中要有每个参数的数据类型 ```cpp // 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;

}

更加清晰的代码组织结构<br />我们会将同一类的函数放在同一个`.cpp`文件中,这个文件中的所有函数需要有**声明,声明会统一放到头文件中,在头文件中,还需要写宏定义。**
```cpp
#ifndef __DRAW_H__
#define __DRAW_H__

...
#endif

如果调用了两遍#include <draw.h>头文件时,这时候函数的声明就会出现两次,编译就会出错。所以宏定义的功能:如果已经调用了一次头文件,第二次调用的时候就会为空,相当与没有include
6.1 functions - 图1

// draw.h
#ifndef __DRAW_H__
#define __DRAW_H__
bool drawLine(int x1, int y1, int x2, int y2);
bool drawRectangle(int x1, int y1, int x2, int y2);
#endif
// draw.cpp
#include <draw.h>

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;
}
// main.cpp
#include <draw.h>

int main()
{
    // ...
    drawRectangle(10, 20, 50, 100);
    // ...
}

How are functions called?

  • A call stack can store information about the active functions of a program
    • Store the address the program returns after the function call
    • Store the registers
    • Store the local variables

    • // do some work of the called function

    • Restore the registers
    • Restore the local variables
    • Store the function returned result
    • Jump to the return address

The cost to call a function!