IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++ Primer Plus 笔记(7~8章) -> 正文阅读

[C++知识库]C++ Primer Plus 笔记(7~8章)

7 函数——C++的编程模块

7.1复习函数的基本知识

要使用C++函数,必须完成如下工作:

  • 提供函数定义

  • 提供函数原型

  • 调用函数

7.1.1 定义函数

没有返回值的函数和有返回值的函数,没有返回值的函数被称为void函数

void cheers(int n)
{
 ? ?fot(int i = 0;i<n;i++)
 ? ? ? ?std::cout<<"Cheers! ";
 ? ?std::cout << std::endl;
}

C++对于返回值有一定的限制:不能是数组,但可以是其他任何类型——整数,浮点数,指针,甚至可以是结构和对象

7.1.2 函数原型和函数调用

原型描述了函数到编译器的接口,将函数返回值的类型以及参数的类型和数量告诉编译器

另外,函数原型中的变量名只是占位符,可以与函数定义中的变量不同,甚至可以省略

void cheers(int);

7.2 函数参数和按值传递

double cube(double x);

该函数将创建一个新的名为x的double变量,将其初始化为5。这样,cube()执行的操作将不会影响main()中的数据,因为cube()使用的是side的副本,不是原数据。其中,用于接收传递值的变量叫形参,传递给函数的叫实参。

7.3 函数与数组

#include <iostream>
const int Arsize = 8;
int sum_arr(int arr[], int n);
int main()
{
    using namespace std;
    int cookies[Arsize] = { 1,2,4,8,16,32,64,128 };
    int sum = sum_arr(cookies, Arsize);
    cout << "Total cookies eaten: " << sum << "\n";
    return 0;
}
int sum_arr(int arr[], int n)
{
    int total = 0;
?
    for (int i = 0; i < n; i++)
        total = total + arr[i];
    return total;
}

7.3.1 函数如何使用指针来处理数组

C++将数组名解释为其第一个元素的地址:

cookies == &cookies[0];

该规则有一些例外。首先,数组声明使用数组名来标记存储位置;其次,对数组名使用sizeof将得到整个数组的长度(以字节为单位);最后,正如第4章指出的,将地址运算符&用于数组名时,将返回整个数组的地址,例如&cookies将返回一个32字节内存块的地址

以下有两个恒等式:

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

将指针(包括数组名)加1,实际上是加上了一个与指针指向的类型长度(以字节为单位)相等的值。对于遍历数组而言,使用指针加法和数组下标是等效的

7.3.2 将数组作为参数意味着什么

将数组内容传递给函数,而是将数组位置(地址),包含的元素种类(类型)以及元素数目(n变量)提交给函数

sizeof cookies是整个数组的长度,而sizeof arr只是指针变量的长度

7.3.3 更多数组函数实例

填充数组

int fill_array(double ar[],int limit)
{
 ? ?using namespace std;
 ? ?double temp;
 ? ?int i;
 ? ?for(i=0;i<limit;i++)
 ?  {
 ? ? ? ?cout << "Enter value #" << (i + 1) << ": ";
 ? ? ? ?cin >> temp;
 ? ? ? ?if(!cin)
 ? ? ?  {
 ? ? ? ? ? ?cin.clear();
 ? ? ? ? ? ?while(cin.get()!='\n')
 ? ? ? ? ? ? ? ?continue;
 ? ? ? ? ? ?cout << "Bad input; input progress terminated.\n";
 ? ? ? ? ? ?break;
 ? ? ?  }
 ? ? ? ?else if(temp < 0)
 ? ? ? ? ? ?break;
 ? ? ? ?ar[i] = temp;
 ?  }
 ? ?return i;
}

显示数组及用const保护数组

为防止函数无意中修改数组的内容,可在声明形参时使用关键字const

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

7.3.4 使用数组区间的函数

传统的C++方法是,将指向数组起始处的指针作为一个参数,将数组长度作为第二个参数

还有一种方法,可以通过传递两个指针来完成:一个指针标识数组的开头,另一个指针标识数组的尾部

int sum_arr(const int * begin, const int * end)
{
 ? ?const int * pt;
 ? ?int total = 0;
 ? ?for(pt = begin;pt != end; pt++)
 ? ? ? ?total = total + *pt;
 ? ?return total;
}

7.3.5 指针和const

首先,声明一个指向常量的指针pt:

int age = 39;
const int * pt = &age;

pt指向age,而age不是const。可以直接通过age变量来修改age的值,但不能使用pt指针来修改它

*pt = 20;   //无效
age = 20;   //有效

将指针参数声明为指向常量数据的指针有两条理由:

  • 这样可以避免由于无意间修改数据而导致的编程错误

  • 使用const使得函数能够处理const和非const实参,否则将只能接受非const数据

如果条件允许,则应将指针形参声明为指向const的指针

7.4 函数和二维数组

将二维数组作为参数的函数原型有两种:

int sum(int (*ar2)[4],int size);
int sum(int ar2[][4],int size);

由于ar2指向数组的第一个元素,因此表达式ar2+r指向编号为r的元素,ar2[r]是编号为r的元素。

由于元素本身是一个有4个int组成的数组,因此ar2[r] [c]表示其中的一个元素

ar2;                    //指向(由4个int组成的)数组的第一个元素
ar2 + r;                //指向编号为r的数组
*(ar2 + r);             //编号为r的数组的值
*(ar2 + r) + c;         //指向r数组的c元素
*((ar2 + r) + c);       //r数组c元素的值
?
ar2[r][c] == *((ar2 + r) + c);

7.5 函数和C风格字符串

7.5.1 将C风格字符串作为参数的函数

假如要将字符串作为参数传递给函数,则表示字符串的方式有三种:

  • char数组

  • 用引号括起的字符串常量

  • 被设置为字符串的地址的char指针

unsigned int c_in_str(const char * str,char ch)
{
 ? ?unsigned int count = 0;
 ? ?while(*str)     //当*str = 0时退出循环
 ?  {
 ? ? ? ?if(*str == ch)
 ? ? ? ? ? ?count++;
 ? ? ? ?str++;
 ?  }
 ? ?return count;
}

7.5.2 返回c风格字符串的函数

函数无法返回一个字符串,但可以返回字符串的地址

char * buildstr(char c,int n)
{
 ? ?char * pstr = new char[n + 1];
 ? ?pstr[n] = '\0';
 ? ?while(n-- > 0)
 ? ? ? ?pstr[n] = c;
 ? ?return pstr;
}

7.6 函数与结构

7.6.1 传递和返回结构

#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 };
    travel_time day2 = { 4,55 };
?
    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";
}

7.6.2 传递结构的地址

void show_polar(const polar*pda)
{
 ? ?using namespace std;
 ? ?const double Red_to_deg = 57.29577951;
 ? ?
 ? ?cout << "distance = " << pda->distance;
 ? ?cout << ", angle = " << pda->angle * Red_to_deg;
 ? ?cout << " degrees\n";
}

需要注意三个地方:

  • 调用函数时,将结构的地址(&pplace)而不是结构本身(pplace)传递给它

  • 将形参声明为指向polar的指针,即polar*类型,由于函数不应该修改结构,因此使用了const修饰符

  • 由于形参是指针而不是结构,因此应使用间接成员符(->),而不是成员运算符(句点)

7.7 函数和string对象

void display(const string sa[],int n)
{
 ? ?for(int i = 0;i<n;i++)
 ? ? ? ?cout << i + 1 << ": " << sa[i] << endl;
}

7.8 函数和array对象

void fill(std::array<double,Seasons> * pa)
{
 ? ?using namespace std;
 ? ?for(int i = 0;i < Seasons; i++)
 ?  {
 ? ? ? ?cout << "Enter " << Snames[i] << " expense: ";
 ? ? ? ?cin >> (*pa)[i];
 ?  }
}

7.9 递归

void countdown(int n)
{
 ? ?using namespace std;
 ? ?cout << "Counting down ... " << n << endl;
 ? ?if(n > 0)
 ? ? ? ?countdown(n-1);
 ? ?cout << n << ": Kaboom!\n";
}

7.10 函数指针

7.10.1 函数指针的基础知识

获取函数的地址

process(think); //  获取think()函数的地址
thought(think())    //获取think()函数的值

声明函数指针

double (*pf)(int);

使用指针来调用函数

double pam(int);
double (*pf)(int);
pf = pam;               //让pf指针指向pam函数
double x = pam(4);      //使用函数名调用函数
double y = (*pf)(5);    //使用pf指针调用pam函数
?

7.10.2 函数指针示例

#include <iostream>
double betsy(int);
double pam(int);
?
void estimate(int lines, double (*pf)(int));
?
int main()
{
    using namespace std;
    int code;
    cout << "How many lines of code do you need? ";
    cin >> code;
    cout << "Here's Betsy's estimate:\n";
    estimate(code, betsy);
    cout << "Here's Pam's estimate:\n";
    estimate(code, pam);
    return 0;
}
?
double bestsy(int lns)
{
    return 0.05 * lns;
}
double pam(int lns)
{
    return 0.03 * lns + 0.0004 * lns * lns;
}
?
void estimate(int lines, double(*pf)(int))
{
    using namespace std;
    cout << lines << " lines will take ";
    cout << (*pf)(lines) << " hour(s)\n";
}

8 函数探幽

8.1 c++内联函数

要使用内联函数,必须采取下述措施:

  • 在函数声明前加上关键字inline

  • 在函数定义前加上关键字inline

通常的做法是省略原型,将整个定义(即函数头和所有函数代码)放在本应提供原型的地方

8.2 引用变量

8.2.1 创建引用变量

举个例子,要将rodents作为rats变量的别名,可以这样做:

int rats;
int & rodents = rats;

其中,&不是地址运算符,而是类型标识符的一部分。rats和rodents的值和地址相同,将rodents加1将影响这两个变量

8.2.2 将引用用作函数参数

void swapr(int & a, int & b)
{
 ? ?int temp = a;
 ? ?a = b;
 ? ?b = temp;
}
void swapp(int * p,int * q)
{
 ? ?int temp = *p;
 ? ?*p = *q;
 ? ?*q = temp;
}

引用传递(别名)和地址传递(指针)都可以交换a,b的值,但值传递不能

8.2.3 将引用用于结构

...
struct free_throws
{
 ? ?std::string name;
 ? ?int made;
 ? ?int attempts;
 ? ?float percents;
};
...
void display(const free_throws & ft)
{
 ? ?using std::cout;
 ? ?cout << "Name: " << ft.name << '\n';
 ? ?cout << " Made: " << ft.made << '\t';
 ?  ...
}
...

8.2.4 将引用用于类对象

string version1(const string & s1, const string & s2)
{
 ? ?string temp;
 ? ?temp = s2 + s1 + s2;
 ? ?return temp;
}

8.2.5 何时使用引用参数

  • 程序员能够修改调用函数中的数据对象

  • 通过传递引用而不是整个数据对象,可以提高程序的运行速度

8.3 函数重载

8.3.1 重载示例

#include <iostream>
unsigned long left(unsigned long num, unsigned ct);
char* left(const char* str, int n = 1);
?
int main()
{
    using namespace std;
    unsigned long n = 12312312;
    int i;
    char* temp;
    ...
    for (i = 1; i < 10; i++)
    {
        cout << left(n, i) << endl;
        temp = left(trip, i);
        cout << temp << endl;
        delete[] temp;
    }
    return 0;
}
unsigned long left(unsigned long num, unsigned ct)
{
    unsigned digits = 1;
    unsigned long n = num;
    ...
}
char* left(const char* str, int n)
{
    if (n < 0)
        n = 0;
    ...
}

8.4 函数模板

需要多个对不同类型使用同一种算法的函数时,可使用模板

template<typename AnyType>  //指出要建立一个模板,并将其类型命名为AnyType
void Swap(AnyType &a,AnyType &b)
{
 ? ?AnyType temp;
 ? ?temp = a;
 ? ?a = b;
 ? ?b = temp;
}

8.4.1 重载的模板

#include <iostream>
template <typename T>
void Swap(T &a, T &b);
?
int main()
{
 ?  ...
}
template <typename T>
void Swap(T &a,T &b)
{
 ? ?T temp;
 ? ?temp = a;
 ? ?a = b;
 ? ?b = temp;
}
template <typename T>
void Swap(T a[],T b[],int n)
{
 ? ?T temp;
 ? ?for(int i = 0; i < n; i++)
 ?  {
 ? ? ? ?temp = a[i];
 ? ? ? ?a[i] = b[i];
 ? ? ? ?b[i] = temp;
 ?  }
}
...

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-12 16:25:18  更:2021-08-12 16:27:02 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/20 8:04:36-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码