C++自学 | 3 函数运算 & 数组 & 字符串

本内容仅属于个人自学记录,欢迎交流和指正,请勿转载或发表不当言论。

主要学习网址:https://www.runoob.com/


3.1 Cplus/C++ 函数

 

1.  主函数 main() :

在逻辑上,划分通常是根据每个函数执行一个特定任务来划分的,有时也称为方法,子例程或程序等。

函数声明告诉编译器函数的名称,返回类型和参数,函数定义提供了函数的实际主体。


return_type function_name( parameter list );  //函数声明
return_type function_name( parameter list )
{
   body of the function
}

 

return_type:函数返回值的数据类型,不需要返回值的函数关键字可以写为 void。
function_name:函数实际名称,函数名和参数列表一起构成了函数签名。
parameter list:类似占位符。


2. 调用函数:
当程序调用函数时,程序控制权会转移给被调用的函数。被调用的函数执行已定义的任务,当函数的返回语句被执行时,或到达函数的结束括号时,会把程序控制权交还给主程序。


3. 函数参数:
如果函数要使用参数,则必须声明接受参数值的变量,这些变量称为函数的形式参数。
形式参数就像函数内的其他局部变量,在进入函数时被创建,退出函数时被销毁。
调用类型描述
传值调用 该方法把参数的实际值赋值给函数的形式参数。在这种情况下,修改函数内的形式参数对实际参数没有影响。
指针调用 该方法把参数的地址赋值给形式参数。在函数内,该地址用于访问调用中要用到的实际参数。这意味着,修改形式参数会影响实际参数。
引用调用 该方法把参数的引用赋值给形式参数。在函数内,该引用用于访问调用中要用到的实际参数。这意味着,修改形式参数会影响实际参数。
默认情况下,C++使用传值调用来传递参数,即函数内的代码不能改变用于调用函数的参数。


3. 参数的默认值:
定义一个函数时,可以为参数列表中后边的每一个参数指定默认值,当调用函数时,如果实际参数的值留空,则会使用这个默认值,若有指定的传递值,则会忽略默认值。


4. Lambda 函数和表达式:
C++11提供了对匿名函数的支持,称为 Lambda 函数,可以把函数看作对象,也可以像对象一样使用,比如可以将它们赋给变量和作为参数传递,还可以像函数一样对其求值。
表达式具体形式如下:
[capture](parameters) -> return-type{body}

  •  [capture]:捕捉列表。捕捉列表总是出现在 lambda 表达式的开始处。事实上,[] 是 lambda 引出符。编译器根据该引出符判断接下来的代码是否是 lambda 函数。捕捉列表能够捕捉上下文中的变量供 lambda 函数使用。
  •  (parameters):参数列表。与普通函数的参数列表一致。如果不需要参数传递,则可以连同括号 () 一起省略。
  •  mutable:mutable 修饰符。默认情况下,lambda 函数总是一个 const 函数,mutable 可以取消其常量性。在使用该修饰符时,参数列表不可省略(即使参数为空)。
  •  ->return_type:返回类型。用追踪返回类型形式声明函数的返回类型。出于方便,不需要返回值的时候也可以连同符号 -> 一起省略。此外,在返回类型明确的情况下,也可以省略该部分,让编译器对返回类型进行推导。
  •  {statement}:函数体。内容与普通函数一样,不过除了可以使用参数之外,还可以使用所有捕获的变量。

在 lambda 函数的定义式中,参数列表和返回类型都是可选部分,而捕捉列表和函数体都可能为空,C++ 中最简单的 lambda 函数只需要声明为:

[] {}

 

其他声明例如:
[](int x, int y)-> int {int z = x+y; return z + x ;}

 

若没有返回值可表达为,其返回类型可被完全忽略:
[capture] (parameters) {body}

//例如:
[]{ ++global_x; }
在 Lambda 表达式内可以访问当前作用域的变量,这被称为闭包(Closure)行为。C++中变量传递有传值和传引用的区别,可以通过[]来指定:
[]      // 沒有定义任何变量。使用未定义变量会引发错误。 
[x, &y] // x以传值方式传入(默认),y以引用方式传入。
[&]     // 任何被使用到的外部变量都隐式地以引用方式加以引用。
[=]     // 任何被使用到的外部变量都隐式地以传值方式加以引用。
[&, x]  // x显式地以传值方式加以引用。其余变量以引用方式加以引用。
[=, &z] // z显式地以引用方式加以引用。其余变量以传值方式加以引用。

 

其中,传值方式捕捉的变量,函数调用运算符的重载方法是 const 属性,如果想对此进行改动的话,就可以使用 mutable :
int main()
{
    int x = 10;

    auto add_x = [x](int a) mutable { x *= 2; return a + x; };  // 复制捕捉x

    cout << add_x(10) << endl; // 输出 30
    return 0;
}


此外,对于 [=] 和 [&]的形式,表达式可以直接使用 this 指针,但对于 [] 的形式,如果要使用 this 指针,必须显示传入:
[this]() { this -> someFunc() ;} ();

【实例 1:

std::vector<int> v = { 1, 2, 3, 4, 5, 6 };  //val取该范围内的值。
int even_count = 0;
for_each(v.begin(), v.end(), [&even_count](int val){
    if(!(val & 1)){   //利用 & 来判断 val的值
        ++ even_count;
    }
});
std::cout << "The number of even is " << even_count << std::endl;

 

【实例 2:
// 指明返回类型
auto add = [](int a, int b) -> int { return a + b; };

// 自动推断返回类型
auto multiply = [](int a, int b) { return a * b; };
int sum = add(2, 5);   // 输出:7
int product = multiply(2, 5);  // 输出:10

 

 

5.  递归函数:

函数直接或间接调用函数本身。

【实例:求n的阶乘。

#include <iostream>

using namespace std;

// 本程序用递归算法求n的阶乘
int counter = 1;

int fac(int n)
{
    cout << "" << counter << "次调用:" << n << " * " << "fac(" << n - 1 << ")" << endl;
    if (n == 1) {
        return 1;
    }
    else
    {
        counter++;
        return n * fac(n - 1); // 断点1
    }
}

int main()
{
    int n;
    cout << "请输入求n的阶乘的n值:";
    cin >> n;
    cout << "结果:fac(" << n << ")=" << fac(n) << endl;
}

 



 





3.2 Cplus/C++ 数学运算

 

1.  内置数学函数:

常用的内置数学函数,包含在<cmath>头文件中。

序号函数 & 描述
1 double cos(double);
该函数返回弧度角(double 型)的余弦。
2 double sin(double);
该函数返回弧度角(double 型)的正弦。
3 double tan(double);
该函数返回弧度角(double 型)的正切。
4 double log(double);
该函数返回参数的自然对数。
5 double pow(double, double);
假设第一个参数为 x,第二个参数为 y,则该函数返回 x 的 y 次方。
6 double hypot(double, double);
该函数返回两个参数的平方总和的平方根,也就是说,参数为一个直角三角形的两个直角边,函数会返回斜边的长度。
7 double sqrt(double);
该函数返回参数的平方根。
8 int abs(int);
该函数返回整数的绝对值。
9 double fabs(double);
该函数返回任意一个浮点数的绝对值。
10 double floor(double);
该函数返回一个小于或等于传入参数的最大整数。

 

 

2.  随机数:

随机数生成器有两个相关的函数:

rang():

返回一个伪随机数,生成随机数之前必须先调用 srand() 函数。

Windows 下 RAND_MAX 为 0x7fff=2^15-1=32767;linxu下的RAND_MAX为:2^31-1=2147483647。

 

srand() 函数

//原型
void srand(unsigned seed);

 

用法:需要提供一个种子,这个种子会对应一个随机数,如果使用相同的种子,其后 rand 会出现一样的随机数(多此执行的结果一样)。

为了防止随机数每次重复,常常使用系统时间来初始化,即使用 time 函数来获得系统时间,它的返回值为从 00:00:00 GMT, January 1, 1970 到现在所持续的秒数,然后将 time_t 型数据转化为(unsigned)型再传给 srand 函数,即: srand((unsigned) time(&t));

还有一个经常用法,不需要定义time_t型t变量,即: srand((unsigned) time(NULL)); 直接传入一个空指针,因为你的程序中往往并不需要经过参数获得的t数据。

 

【实例 1:使用 time() 函数来获取系统时间的秒数,通过调用 rand() 函数来生成随机数:

#include <iostream>
#include <ctime>   //time函数也可以通过<time.h> (更多在C语言中使用)定义
#include <cstdlib>
 
using namespace std;
 
int main ()
{
   int i,j;
 
   // 设置种子
   srand( (unsigned)time( NULL ) );
 
   /* 生成 10 个随机数 */
   for( i = 0; i < 10; i++ )
   {
      // 生成实际的随机数
      j= rand();
      cout <<"随机数: " << j << endl;
   }
 
   return 0;
}

 

【实例 2:”模除+加法“的方式取 0 到指定区间的(伪)随机数,但0-1000内每个数的出现概率不同。

//取0-1000内的随机数:
srand((unsigned)time(NULL));
int i = rand()%1000;

 

【实例 2扩展:产生 [range_min/n, range_max/m] 范围内的随机数 

int num = rand()%(n-m+1)+m;    //区间内数的个数 + 区间起点值

 

int u = (double)rand() / (RAND_MAX + 1) * (range_max - range_min)+ range_min   //RAND_MAX是C++内有的字。

 

【实例 3:使用随机数模拟一个抢红包的过程。

 1 #include<iostream>
 2 #include<ctime>
 3 using namespace std;
 4 
 5 int main()
 6 {
 7     int money = 0;
 8     int member = 0;
 9 
10     cout << "请输入红包金额:" << endl;
11     cin >> money;
12 
13     cout << "请输入红包个数(小于100):" << endl;
14     cin >> member;
15 
16 
17     //随机数种子
18     srand((unsigned)time(NULL));
19     float a[100] = { 0 };  //最多分给100个人
20     float dismoney[100] = { 0 }; 
21     int best;  //手气最佳
22     int max = 0;
23     float suma = 0; //随机数总和
24     float sumb = 0; //红包总和
25 
26     for (int i = 0; i < member; i++)
27     {
28         a[i] = rand()%100;
29 
30         if (a[i] == 0)
31         {
32             a[i] = rand() % 100;
33         }
34 
35         if (a[i]>max)
36         {
37             max = a[i];
38             best = i;
39         }
40 
41         suma += a[i];
42     }
43 
44     for (int i = 0; i < member-1; i++)
45     {
46         dismoney[i] = a[i] / suma * money;  //按随机数百分比计算每个人获得的实际金额。
47         sumb += round(dismoney[i] * 100) / 100.0;
48 
49         cout << "" << i + 1 << "个人的红包是:" << round(dismoney[i] * 100) / 100.0;
50 
51         if (best == i)
52         {
53             cout << "(手气最佳)" << endl;
54         }
55         else
56         {
57             cout << endl;
58         }
59     }
60 
61     //最后一人的红包金额等于总金额减去前面的金额总和
62     cout << "" << member << "个人的红包是:" << round((money - sumb) * 100) / 100.0;
63     if (best == member-1)
64     {
65         cout << "手气最佳" << endl;
66     }
67     else
68     {
69         cout << endl;
70     }
71 
72     return 0;
73 }

 

 实例输出结果:

请输入红包金额:
100
请输入红包个数(小于100):
10
第1个人的红包是:8.96
第2个人的红包是:17.35(手气最佳)
第3个人的红包是:1.31
第4个人的红包是:14.93
第5个人的红包是:7.09
第6个人的红包是:13.81
第7个人的红包是:15.86
第8个人的红包是:7.84
第9个人的红包是:7.84
第10个人的红包是:5.01

 





3.3 Cplus/C++ 数组

 

1.  概念:

数组数据结构是一个 可以存储一个固定大小的相同类型元素的顺序集合,所有的数组都是由连续的内存位置组成,最低的地址对应第一个元素,最高的地址对应最后一个元素。

声明数组是声明一个数组变量,数组中的特定元素可以通过索引访问。

 

2.  声明数组

type arrayName [ arraySize ];

 

其中,arraySize 必须是一个大于0的整数常量。

 

3.  初始化数组

double balance[5] = { 1000.0, 2.0, 3.4, 7.0, 50.0 };
double balance[]={ 1000.0, 2.0, 3.4, 7.0, 50.0 };       //省略数组大小,数组大小将默认与后面数字的个数相同。
double balance[5] = { 1000.02.0 };     //数组中[0]为1000.0,[1]为2.0,[2][3][4]均为0。

 

 

【实例

#include <iostream>
using namespace std;
 
#include <iomanip>
using std::setw;
 
int main ()
{
   int n[ 10 ]; // n 是一个包含 10 个整数的数组
 
   // 初始化数组元素          
   for ( int i = 0; i < 10; i++ )
   {
      n[ i ] = i + 100; // 设置元素 i 为 i + 100
   }
   cout << "Element" << setw( 13 ) << "Value" << endl;
 
   // 输出数组中每个元素的值                     
   for ( int j = 0; j < 10; j++ )
   {
      cout << setw( 7 )<< j << setw( 13 ) << n[ j ] << endl;
   }
 
   return 0;
}

 

其中,setw(int n) 函数的作用是格式化输出(只对紧随其后的输出有效),n为设置的输出域宽度,当后面的输出字段长度小于n时,在该字段前面用空格补齐;当输出字段长度大于n时,全部整体输出,其头文件为#include<iomanip>。

执行上述代码时,会产生下列结果。

Element        Value  //宽度分别为 7 和 5
      0          100
      1          101
      2          102
      3          103
      4          104
      5          105
      6          106
      7          107
      8          108
      9          109

 

 

【实例:获取数组长度

#include<iostream>
using namespace std;

template<class T>

int length(T& arr)
{
    //cout << sizeof(arr[0]) << endl;
    //cout << sizeof(arr) << endl;
    return sizeof(arr) / sizeof(arr[0]);
}

int main()
{
    int arr[] = { 1,5,9,10,9,2 };
    // 方法一
    cout << "数组的长度为:" << length(arr) << endl;
    // 方法二
    //cout << end(arr) << endl;
    //cout << begin(arr) << endl;
    cout << "数组的长度为:" << end(arr)-begin(arr) << endl;
    system("pause");
    return 0;
}

 

 

4.  多维数组:

1)二维数组:

数组的声明及排列方式

type arrayName [x][y];   //x行 y列

 

 

 

 数组的初始化:

int a[3][4] = {
    {0, 1, 2, 3},    //初始化索引号为0的行
    {4, 5, 6, 7},    //初始化索引号为1的行
    {8, 9, 10, 11}  //初始化索引号为2的行
};

 

上述方法也等同于:

int a[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};

 

二维数组一般使用嵌套循环进行处理:

#include <iostream>
using namespace std;
 
int main ()
{
   // 一个带有 5 行 2 列的数组
   int a[5][2] = { {0,0}, {1,2}, {2,4}, {3,6},{4,8}};
 
   // 输出数组中每个元素的值                      
   for ( int i = 0; i < 5; i++ )
      for ( int j = 0; j < 2; j++ )
      {
         cout << "a[" << i << "][" << j << "]: ";
         cout << a[i][j]<< endl;
      }
 
   return 0;
}

 

 

 

 


3.4 Cplus/C++ 字符串

 

1.  C风格字符串:

该字符串实际时使用 null 字符 '\0' 终止的一维字符数组。

该字符串的声明和初始化如下所示,两种方式得到的数组相同:

char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};  //由于在数组的末尾存储了空字符,所以字符数组的大小比单词 "Hello" 的字符数多一个。
char greeting[] = "Hello";

 

处理以 null 字符 '\0' 结尾的字符串常用函数:

序号函数 & 目的
1 strcpy(s1, s2);
复制字符串 s2 到字符串 s1。
2 strcat(s1, s2);
连接字符串 s2 到字符串 s1 的末尾。
3 strlen(s1);
返回字符串 s1 的长度。
4 strcmp(s1, s2);
如果 s1 和 s2 是相同的,则返回 0;如果 s1<s2 则返回值小于 0;如果 s1>s2 则返回值大于 0。
5 strchr(s1, ch);
返回一个指针,指向字符串 s1 中字符 ch 的第一次出现的位置。
6 strstr(s1, s2);
返回一个指针,指向字符串 s1 中字符串 s2 的第一次出现的位置。

 

2.  C++标准库中的String类型

 

posted @ 2020-06-21 22:42  伏延  阅读(306)  评论(0编辑  收藏  举报