C++知识点-函数基础

这里总结下C++函数的一些基础知识。在工作中深刻体会到基础的重要性,以及理论指导实践,必须有一定的理论知识作为依据,才能写出健壮的代码以及有不错的解决问题的能力。如果总结的知识不对或者已过时还请大家指正。

基本知识

C++对于返回值的类型有一定的限制:不能是数组,但是可以是其他类型:整数,浮点数,指针,结构和对象。
通常,函数通过将返回值复制到指定的CPU寄存器或内存单元中来将其返回。随后,调用程序将查看该内存单元。
在编译阶段进行的原型化被称为静态类型检查(static type checking)

函数参数和按值传递

按值传递时,当函数被调用时,该函数会对传递的实参进行拷贝,因此函数中的操作不会影响到调用者的数据。这种情况比价简单,不做代码示例。

函数和数组

基本使用

C++将数组名解释为第一个元素的地址,即有一下等式: arr = &arr[0]
并且 int sum_arr(int arr[], int n);int sum_arr2(int * arr, int n); 这两个函数原型是等价的。在C++中, 当且仅当用于函数头或函数原型时, int arr[]int * arr 的含义才是相同的。我们可以记住一下两个恒等式:

  • arr[i] = *(arr + i)
  • &arr[i] = arr + i

将数组作为参数传递说明了什么:说明调用函数时并没有把数组内容传递给函数,而是将数组的位置(地址),包含元素的种类以及元素数目提交给函数。这也是按值传递,只不过传的是数组的地址。

#include <iostream>

const int ArrSize = 8;
// prototype
int sum_arr(int arr[], int n);
int sum_arr2(int * arr, int n);

int main() {
    using namespace std;
    int cookies[ArrSize] = {1, 2, 4, 8, 16, 32, 64, 128};

    std::cout << cookies << " = array address, ";
    std::cout << sizeof cookies << " = sizeof cookies\n";
    int sum = sum_arr(cookies, ArrSize);
    std::cout << "Total cookies eaten: " << sum << std::endl;
    sum = sum_arr(cookies, 3);      // a lie
    std::cout << "First three eaters ate " << sum << " cookies.\n";
    sum = sum_arr(cookies + 4, 4);  // another lie
    std::cout << "Last four eaters ate " << sum << " cookies.\n";

    return 0;
}


int sum_arr(int arr[], int n) {
    std::cout << arr << " = arr, ";
    std::cout << sizeof arr << " = sizeof arr\n";
    int total = 0;
    for (int i = 0; i < n; i++) {
        total += arr[i];
    }
    return total;
}

// This is ok
int sum_arr2(int * arr, int n) {
    std::cout << arr << " = arr, ";
    std::cout << sizeof arr << " = sizeof arr\n";

    int total = 0;
    for (int i = 0; i < n; i++) {
        total += *(arr + i);
    }
    return total;
}

输出结果:

0x7ffee07297f0 = array address, 32 = sizeof cookies
0x7ffee07297f0 = arr, 8 = sizeof arr
Total cookies eaten: 255
0x7ffee07297f0 = arr, 8 = sizeof arr
First three eaters ate 7 cookies.
0x7ffee0729800 = arr, 8 = sizeof arr
Last four eaters ate 240 cookies.

上述程序的结果显示,sizeof cookies = 32,而 sizeof arr = 4,因为 sizeof arr 只是指针的长度,从中可以得知指针本身没有数组的长度。

显示数组及用 const 保护数组

当编写显示数组的函数时,我们要注意确保原始数组不被修改,这是可以使用 const 修饰入参。这里要注意,当在函数原型中使用 const 修饰指针时,只能修饰指向基本类型的指针,而不能修饰指向指针的指针。

void show_array(const double ar[], int n);

以上函数原型表示,**ar指向的是常量数据,不能对其进行修改。**由此我们可以总结出常用的数组函数原型。

void f_modify(double ar[], int n);
void f_no_change(const double ar[], int n);

使用数组区间的函数

我们也可以用函数原型 int sum_arr(const int * begin, const int * end); 对数组的一个区间进行操作,以下是代码示例。

#include <iostream>

const int ArSize = 8;

int sum_arr(const int *begin, const int *end);

int main() {
    using namespace std;
    int cookies[ArSize] = {1, 2, 4, 8, 16, 32, 64, 128};
    // some systems require preceding int with static to
    // enable array initialization

    int sum = sum_arr(cookies, cookies + ArSize);
    cout << "Total cookies eaten: " << sum << endl;
    sum = sum_arr(cookies, cookies + 3);    // first 3 elements
    cout << "First three eaters ate " << sum << " cookies.\n";
    sum = sum_arr(cookies + 4, cookies + 8);    // last 4 elements
    cout << "Last four eaters ate " << sum << " cookies.\n";
    return 0;
}

// return the sum of an integer array
int sum_arr(const int* begin, const int* end) {
    const int* pt;
    int total = 0;
    for (pt = begin; pt != end; pt++) {
        total += *pt;
    }
    return total;
}

函数和二维数组

假设有一下代码:

int data[3][4] = {{1,2,3,4}, {1,2,3,4}, {1,2,3,4}};
int total = sum(data, 3);

那么我们必须使用如下的原型:

int sum(int (*arr)[4], int n);
// or use this
int sum(int arr[][4], int n);

其中要注意的是 int (*arr)[4] 表示的是数组的指针,是含有4个int组成的指针,而 int * arr[4] 表示的是含有4个指针的数组,是数组。

函数和C风格字符串

表示字符串的方式有三种:

  • char 数组
  • 用引号扩起的字符串常量
  • 被设置为字符串的地址的 char 指针
    上述三种类型都是 char 指针,可以将其作为函数参数。
char ghost[15] = "galling";
char * str = "galling";
int n1 = strlen(ghost); // ghost is &ghost[0]
int n2 = strlen(str); // pointer to char
int n3 = strlen("galling"); // address of string

char数组和C风格字符串的一个重要区别是,字符串有内置的结束字符,而包含字符但不以空值字符结尾的 char 数组只是数组,不是字符串。
以下列举一些字符串处理函数原型

// 与普通数组不同,不用传字符串长度,可以通过空值判断是否到达结尾
unsigned int c_in_str(const char * str, char ch);
char * buildstr(char c, int n);

函数和结构

使用结构编写结构相关的函数时,一共有三种方法。

  • 最直接的方式是和处理基本类型一样,按值传递,但这种方法需要复制结构,增加内存需求,降低系统的运行速度。
  • 传递结构的地址
  • 传递结构的引用
按值传递

按值传递代码案例

#include <iostream>

struct travel_time {
    int hours;
    int mins;
};
const int Mins_per_hr = 60;

travel_time sum(travel_time t1, travel_time t2);
void show_time(travel_time t);

int main() {
    using namespace std;
    travel_time day1 = {5, 45};     // 5 hrs, 45 min
    travel_time day2 = {4, 55};     // 4 hrs, 55 min

    travel_time trip = sum(day1, day2);
    cout << "Two-day total: ";
    show_time(trip);

    travel_time day3 = {4, 32};
    cout << "Three-day total: ";
    show_time(sum(trip, day3));

    return 0;
}

travel_time sum(travel_time t1, travel_time t2) {
    travel_time total;
    total.mins = (t1.mins + t2.mins) % Mins_per_hr;
    total.hours = t1.hours + t2.hours +
                  (t1.mins + t2.mins) / Mins_per_hr;
    return total;
}

void show_time(travel_time t) {
    using namespace std;
    cout << t.hours << " hours, "
         << t.mins << " minutes.\n";
}

output

Two-day total: 10 hours, 40 minutes.
Three-day total: 15 hours, 12 minutes.

这种情况就和处理基本类型的函数一样。

使用指针

传递结构的地址代码示例

#include <iostream>
#include <cmath>

// struct template
struct polar {
    double distance;
    double angle;
};

struct rect {
    double x;
    double y;
};

// prototypes
void rect_to_polar(const rect *pxy, polar *pda);
void show_polar(const polar *pda);

int main() {
    using namespace std;
    rect rplace;
    polar pplace;
    cout << "Enter the x and y values: ";
    while (cin >> rplace.x >> rplace.y) {
        rect_to_polar(&rplace, &pplace);    // pass addresses
        show_polar(&pplace);    // pass address
        cout << "Next two numbers (q to quit): ";
    }
    cout << "DONE.\n";
    return 0;
}

void show_polar(const polar *pda) {
    using namespace std;
    const double Rad_to_deg = 57.29577951;

    cout << "distance = " << pda->distance;
    cout << ", angle = " << pda->angle * Rad_to_deg << " degrees\n";
}

void rect_to_polar(const rect *pxy, polar *pda) {
    using namespace std;
    pda->distance = sqrt(pxy->x * pxy->x + pxy->y * pxy->y);
    pda->angle = atan2(pxy->y, pxy->x);
}

output

Enter the x and y values: 1
2
distance = 2.23607, angle = 63.4349 degrees

在函数中使用结构的指针避免了复制结构,整体效率更高。

按引用传递

入参是结构的函数最佳的还是按引用传递,因为这样省去了拷贝的过程

#include <iostream>
#include <cmath>

// struct template
struct polar {
    double distance;
    double angle;
};

struct rect {
    double x;
    double y;
};

// prototypes
void rect_to_polar(const rect &pxy, polar &pda);
void show_polar(const polar &pda);

int main() {
    using namespace std;
    rect rplace;
    polar pplace;
    cout << "Enter the x and y values: ";
    while (cin >> rplace.x >> rplace.y) {
        rect_to_polar(rplace, pplace);    // pass reference
        show_polar(pplace);    // pass reference
        cout << "Next two numbers (q to quit): ";
    }
    cout << "DONE.\n";
    return 0;
}

void show_polar(const polar &pda) {
    using namespace std;
    const double Rad_to_deg = 57.29577951;

    cout << "distance = " << pda.distance;
    cout << ", angle = " << pda.angle * Rad_to_deg << " degrees\n";
}

void rect_to_polar(const rect &pxy, polar &pda) {
    using namespace std;
    pda.distance = sqrt(pxy.x * pxy.x + pxy.y * pxy.y);
    pda.angle = atan2(pxy.y, pxy.x);
}

output

Enter the x and y values: 1
3
distance = 3.16228, angle = 71.5651 degrees

Reference

  1. 《C++ Primer Plus 6th》
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值