[学习笔记-C++篇]day2 函数-字符串

好消息好消息,今天起得挺早,早起冲刺(?)
坏消息,2天计划有点紧,but可以再狗一狗(?)
感谢大佬几款优秀的支持C、C++在线编译器


stage1——2天入门阶段

教程网站:C++ 教程
在线编译器:compile c++ gcc online
刷题网站:阶段1第一关:基本数据类型

day2 planA
教程9+4,刷题3(10)
plan B
教程(15-23)+7,刷题1+2
教程完成度25%,刷题完成度40%
主要原因:从15开始内容指数递增,细节比较多,需要实操复习,博客长度就是证明>>


1.函数

子函数如果在主函数后面定义,就要在main()前声明
声明主要要说明形参类型,比如int compare(int,int);
当您在一个源文件中定义函数且在另一个文件中调用函数时(跨文件调用),函数声明是必需的。
在这种情况下,您应该在调用函数的文件顶部声明函数。
调用函数的3种传递参数方式:

在这里插入图片描述

---------------------------------------------------------------------------------------------------


引用调用:
在声明和定义函数的时候,输入参数部分要带上&;
调用的时候直接用变量名;
在定义函数的时候,形参改变,调用的时候变量也会改变,因为隐含了带地址。

引用调用
主要是在声明和定义函数的时候,输入参数部分要带上&,比如int swap(int &a,int &b);
但其实这里的&说是取地址,在实际操作的时候感觉和直接传值是一样的
但是在定义函数的时候,形参改变,调用的时候变量也会改变,因为隐含了带地址
测试实例
#include <iostream>

using namespace std;

void swap(int &a,int &b);//声明需要带&

int main()
{
    int a=1,b=2;
    cout << "the origin answer is\t"<<  a << "\tand\t" << b << endl;
    cout << "the origin address is\t"<<  &a << "\tand\t" << &b << endl;
    
    swap(a,b);//调用的时候,因为形参不是指针,所以直接调用变量,或者说带地址的变量
    
    cout << "the answer 1 is\t"<<  a << "\tand\t" << b << endl;
    cout << "the address 1 is\t"<<  &a << "\tand\t" << &b << endl;
    
    return 0;
}

void swap(int &a, int &b)//定义一样的格式
{
    #if 1
    int m;
    m=a;
    a=b;
    b=m;
    #endif
}
-------------------------------------------------------------------------------------------------


指针调用:
a为整型变量,取地址(获得指针)为&a
a为指针(即地址),指向int类型变量,取地址中的数(获得指针指向的数)为*a

指针说明:
int a;//a为整数变量
则取地址(获得指针)为&a
int *a;//a为指针(即地址),指向int类型变量
则取地址中的数(获得指针指向的数)为*a
指针调用测试实例
#include <iostream>

using namespace std;

void swap1(int *a,int *b);//指针调用,交换地址里的参数
void swap2(int *a,int *b);//指针调用,交换地址,隐含同时换地址里的参数,等于没换

int main()
{
    int a=1,b=2;
    cout << "the origin answer is\t"<<  a << "\tand\t" << b << endl;
    cout << "the origin address is\t"<<  &a << "\tand\t" << &b << endl;
    
    swap1(&a,&b);
    
    cout << "the answer 1 is\t"<<  a << "\tand\t" << b << endl;
    cout << "the address 1 is\t"<<  &a << "\tand\t" << &b << endl;
    
    a=1,b=2;
    swap2(&a,&b);
    
    cout << "the answer 2 is\t"<<  a << "\tand\t" << b << endl;
    cout << "the address 2 is\t"<<  &a << "\tand\t" << &b << endl;
    
    return 0;
}

void swap1(int *a, int *b)
{
    #if 1
    int m;
    m=*a;
    *a=*b;
    *b=m;
    #endif
}

void swap2(int *a, int *b)
{
    #if 1
    int *t;
    t=a;
    a=b;
    b=t;
    #endif
}
输出---------------------------------
the origin answer is	1	and	2
the origin address is	0x7fff6e41dda0	and	0x7fff6e41dda4
the answer 1 is	2	and	1
the address 1 is	0x7fff6e41dda0	and	0x7fff6e41dda4
the answer 2 is	1	and	2
the address 2 is	0x7fff6e41dda0	and	0x7fff6e41dda4
-------------------------------------------------------------------------------------------------

2.设置参数默认值


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


子函数定义带赋值一定要在main()前面,不能用声明int sum(int a, int b=20);

在函数定义的时候直接赋值,就会作为默认值
注意:子函数定义带赋值一定要在main()前面,不能用声明int sum(int a, int b=20);这样!!!!,不然调用的时候summ=sum(a);就会报错
#include <iostream>

using namespace std;

int sum(int a, int b=20)
{
    int m;
    m=a+b;
    return m;
}

int main()
{
    int a=1,b=2;
    cout << "the origin answer is\t"<<  a << "\tand\t" << b << endl;
    //cout << "the origin address is\t"<<  &a << "\tand\t" << &b << endl;
    
    int summ;
    summ=sum(a,b);
    
    cout << "the answer 1 is\t"<<  summ << endl;
    
    summ=sum(a);
    cout << "the address 2 is\t"<<  summ << endl;
    
    return 0;
}

3.Lambda函数

Lambda 表达式把函数看作对象。

Lambda 表达式可以像对象一样使用,比如可以将它们赋给变量和作为参数传递,还可以像函数一样对其求值。

Lambda 表达式本质上与函数声明非常类似。


[]没有内容的话,可以省略后面的()参数列表,但如果有内容,尤其是this,就需要(),即使不说形参,且在{}中需要表示为this->xxx;
lambda函数本身在{}后是不用加;的,如果使用lambda函数赋变量,通常结合auto类型,且lambda结束在{}后加;,在{}中指令结束也要加;

目前看下来感觉就是一个小型简易函数,整体可以用做一个指令结构,也可以用于快速定义一个操作(也就是作为函数快速赋给一个变量)
!!!!>>> 注意 >>>
>>> 注意:[]没有内容的话,可以省略后面的()参数列表,但如果有内容,尤其是this,就需要(),即使不说形参,且在{}中需要表示为this->xxx;
>>> 注意:lambda函数本身在{}后是不用加;的,如果使用lambda函数赋变量,通常结合auto类型,且lambda结束在{}后加;,在{}中指令结束也要加;

Lambda 表达式具体形式如下

[capture](parameters) mutable ->return-type{body}

>>> 详细说明 >>>
· [capture]:捕捉列表。捕捉列表总是出现在 lambda 表达式的开始处。
事实上,[] 是 lambda 引出符。
编译器根据该引出符判断接下来的代码是否是 lambda 函数。捕捉列表能够捕捉上下文中的变量供 lambda 函数使用。
在Lambda表达式内可以访问当前作用域的变量,这是Lambda表达式的闭包(Closure)行为。 
与JavaScript闭包不同,C++变量传递有传值和传引用的区别。可以通过前面的[]来指定:
常用符号示例:
[]      // 沒有定义任何变量。使用未定义变量会引发错误。
[x, &y] // x以传值方式传入(默认),y以引用方式传入。
[&]     // 任何被使用到的外部变量都隐式地以引用方式加以引用。
[=]     // 任何被使用到的外部变量都隐式地以传值方式加以引用。
[&, x]  // x显式地以传值方式加以引用。其余变量以引用方式加以引用。
[=, &z] // z显式地以引用方式加以引用。其余变量以传值方式加以引用。
另外有一点需要注意。对于[=][&]的形式,lambda 表达式可以直接使用 this 指针。
但是,对于[]的形式,如果要使用 this 指针,必须显式传入:
[this]() { this->someFunc(); }();

· (parameters):参数列表。与普通函数的参数列表一致。如果不需要参数传递,则可以连同括号 () 一起省略。

· mutablemutable 修饰符。默认情况下,lambda 函数总是一个 const 函数,mutable 可以取消其常量性。
在使用该修饰符时,参数列表不可省略(即使参数为空)。

· ->return_type:返回类型。用追踪返回类型形式声明函数的返回类型。
出于方便,不需要返回值的时候也可以连同符号 -> 一起省略。
此外,在返回类型明确的情况下,也可以省略该部分,让编译器对返回类型进行推导。

· {statement}:函数体。内容与普通函数一样,不过除了可以使用参数之外,还可以使用所有捕获的变量。

//eg.
[](int x, int y){ return x < y ; }

如果 lambda 函数没有传回值(例如 void),其返回类型可被完全忽略。

[capture](parameters){body}
//eg.
[]{ ++global_x; } 
//复杂例子
[](int x, int y) -> int { int z = x + y; return z + x; }
//测试实例1
/*
判断偶数-->通过和1按位与操作!!!!!!!!!!!!!!!!!!!!
*/
//输出1-10中的偶数个数
#include <iostream>
//vector库
#include <vector>
//for_each的库
#include<algorithm> 

using namespace std;

int main()
{
    vector<int> gr = {1,2,3,4,5,6,7,8,9,10};
    int count;
    
    for_each(gr.begin(), gr.end(),[&count](int grr)->int{ if(!(grr & 1)) count++; });
        
    cout << "there are " << count << " even numbers." << endl;
    
    return 0;
}


Tip:
判断偶数–>通过和1按位与操作

//测试实例1
/*
快速定义一个函数
*/
#include <iostream>

using namespace std;

int main()
{
    auto output=[]{cout << "hello world!" << endl;};//需要注意的是,lambda函数结束要加;,同时里面的指令结束也要加;
    
    output();
    
    return 0;
}
//测试实例2 plus
//快速定义求和,求积函数
#include <iostream>

using namespace std;

int main()
{
    auto output=[]{cout << "hello world!" << endl;};
    auto sum=[](int a ,int b)->int{return a+b;};
    auto mul=[](int a ,int b)->int{return a*b;};
    
    int m=1,n=2;
    
    output();
    int x = sum(m,n);
    cout << "the answer of sum() is " << x << endl;
    int y = mul(m,n);
    cout << "the answer of mul() is " << y << endl;
    
    return 0;
}
此外,对于使用this的方式进行赋值,可以结合下面的例子理解一下
#include <iostream>

using namespace std;

class test
{
    public:
    void out()
    {
        cout << "hello world!" << endl;
    }
    
    void use()
    {
        auto v = [this]() {this->out();}; // 这里 this 调用的就是 class test 的对象了。使用this指针指向out()函数
        v();
    }
};

int main()
{
    test t;
    t.use();
    
    return 0;
}

4.数学运算


注意!!! >>> 需要引用数学头文件<cmath>

在这里插入图片描述
有一些注意事项,比如
1)求三角函数的,用的是弧度角,需要换算
2)注意这些函数,大多参数类型为double

5.随机数

有两个相关的函数。一个是rand(),该函数只返回一个伪随机数,范围在0RAND_MAX(32767)之间(整数),也可以用rand(100)生成0-100的随机数。生成随机数之前可以先调用srand()函数设置随机数种子(无符号整数),如果没有设置随机数种子,rand()函数在调用时,自动设计随机数种子为1。随机种子相同,每次产生的随机数也会相同。

注意!!! >>> 使用rand()或者srand()需要头文件cstdlib>

#include <iostream>
#include <ctime>
#include <cstdlib>
 
using namespace std;
 
int main ()
{
   int i,j;
 
   // 设置种子
   srand( (unsigned)time( NULL ) );//这里采用time()函数获取系统时间的秒数
 
   /* 生成 10 个随机数 */
   for( i = 0; i < 10; i++ )
   {
      // 生成实际的随机数
      j= rand();
      cout <<"随机数: " << j << endl;
   }
 
   return 0;
}

为了防止随机数每次重复,常常使用系统时间来初始化,即使用time函数来获得系统时间,它的返回值为从00:00:00 GMT, January 1, 1970到现在所持续的秒数,然后将time_t型数据转化为(unsigned)型再传给srand函数,即srand((unsigned) time(&t));还有一个经常用法,不需要定义time_tt变量,即srand((unsigned) time(NULL)),直接传入一个空指针,因为你的程序中往往并不需要经过参数获得的t数据。

//复习一下
#include <iostream>
#include <ctime>
#include <cstdlib>

using namespace std;

int main()
{
    srand((unsigned) time(NULL));//如果time()参数为空(NULL),函数将只通过返回值返回现在的日历时间,即从1970年1月1日0时0分0秒到此时的秒数。
    int c;
    
    for(int i=0;i<10;i++)
    {
        c = rand();
        cout << c << endl;
    }
    
    return 0;
}

6.数组

数组,存储一个固定大小的相同类型元素的顺序集合。

数组的声明并不是声明一个个单独的变量,比如number0number1、…、number99,而是声明一个数组变量,比如numbers,然后使用numbers[0]numbers[1]、…、numbers[99]来代表一个个单独的变量。数组中的特定元素可以通过索引访问。

所有的数组都是由连续的内存位置组成。最低的地址对应第一个元素,最高的地址对应最后一个元素。

声明数组
type arrayName [ arraySize ];
//eg.
int groupp[10];

初始化
int groupp[10] = {1,2,3,4,5,6,7,8,9,10};
也可以直接初始化而不说明数组长度,直接默认长度
int groupp[] = {1,2,3,4,5,6,7,8,9,10};

单独初始化或单独赋值
int groupp[2]={3};
>>> !!! 注意 >>>
> 所有的数组都是以 0 作为它们第一个元素的索引,也被称为基索引,数组的最后一个索引是数组的总大小减去 1


只声明,不初始化,那么就要说明长度;要不然就直接初始化,可以不声明

#include <iostream>

using namespace std;

int main()
{
    //1
    int g[10]={1,2,3,4,5,6,7,8,9,10};
    int salary;
    
    salary=g[9];
    
    cout << salary << endl;
    
    //2
    int gg[10];
    int salaryy;
    
    gg[9]=10;
    salaryy=gg[9];
    
    cout << salaryy << endl;
    
    return 0;
}

7.输出格式调节

之前调节格式提到过\t,实际上就是Tab缩进,但是这种调节不能完全保证列对齐,所以可以用setw(),可以设置输出的字段宽度,简单理解就是右对齐

setw(n),当后面紧跟着的输出字段长度小于n的时候,在该字段前面用空格补齐,当输出字段长度大于n时,全部整体输出。

\t,实际上就是Tab缩进;
setw()设置右对齐宽度,setw()的头文件,#include <iomanip>

在这里插入图片描述

#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;
}
输出--------------------------------------
Element        Value
      0          100
      1          101
      2          102
      3          103
      4          104
      5          105
      6          106
      7          107
      8          108
      9          109
//复习一下
#include <iostream>
#include <iomanip>

using namespace std;

int main()
{
    //1
    int g[10]={1,2,3,4,5,6,7,8,9,10};
    
    cout << "first line" << setw(15) << "second line" << endl;
    
    for(int i=0;i<10;i=i+2)
    {
        cout << setw(10) << g[i] << setw(15) << g[i+1] << endl;
    }
    
    return 0;
}

8.多维数组

多维数组声明的一般形式如下:

type name[size1][size2]...[sizeN];
//eg.
int zu[2][3];

数组中的每个元素是使用形式为 a[ i , j ] 的元素名称来标识的,其中 a 是数组名称,i 和 j 是唯一标识 a 中每个元素的下标

初始化
可以通过在括号内为每行指定值来进行初始化。
int zu[2][3] = {{1,2,3},{4,5,6}};
或者
int zu[2][3] = {1,2,3;4,5,6};


注意,如果直接输入所有元素,只用,不要用; ,不然会报错
此外,输入的个数可以小于长度(所有元素个数),没有初始化的部分默认为0

#include <iostream>
#include <iomanip>

using namespace std;

int main()
{
    //1
    int g[2][3]={1,2,3,4,5,6};
    
    for(int i=0;i<2;i++)
    {
        for(int j=0;j<3;j++)
        {
            cout <<  g[i][j] << "\t"; 
        }
        cout << endl;
    }
    
    return 0;
}

二维数组中的元素是通过使用下标(即数组的行索引和列索引)来访问的。

9.指向数组的指针


数组名是指向数组中第一个元素的常量指针。

//eg.
double runoobAarray[50];
runoobAarray 是一个指向 &runoobAarray[0] 的指针,即数组 runoobAarray 的第一个元素的地址。

double *p;
double runoobAarray[10];
p = runoobAarray;//将首个元素的地址赋给p

也可以用地址直接访问数组的元素。

*(runoobAarray + 4) 是一种访问 runoobAarray[4] 数据的合法方式。//此时,runoobAarray就是一个double * 类型的数据,即指向double数据的指针

一旦您把第一个元素的地址存储在p中,您就可以使用*p*(p+1)*(p+2)等来访问数组元素。

#include <iostream>
#include <iomanip>

using namespace std;

int main()
{
    // 带有 5 个元素的双精度浮点型数组
   double runoobAarray[5] = {1000.0, 2.0, 3.4, 17.0, 50.0};
   double *p;
 
   p = runoobAarray;
 
   // 输出数组中每个元素的值
   cout << "使用指针的数组值 " << endl; 
    
    for(int i=0;i<5;i++)
    {
        #if 0
        cout << *p << endl;//2种地址更新方式
        p++;
        #endif
        
        #if 1
        cout << *(p+i) << endl;
        #endif
    }
    
    return 0;
}

输出的时候还是要数组名加索引

10.字符串

字符串实际上是使用null字符\0终止的一维字符数组。
输出的时候可以直接用数组名或者string类型的变量名。

  1. 第1种——字符数组表示
  2. 第2种——string表示
声明及初始化
char site[7] = {'R', 'U', 'N', 'O', 'O', 'B', '\0'};//一维字符数组的初始化方式
>>> !!! 注意 >>>
> 一定要带 \0 ,用于和数字数组相区分
> 和数字数组相同,定义不初始化就要说长度,如char s[20];

char site[] = "RUNOOB";//隐含 \0

string s1="hello";
string s2;//可以不初始化
内存表示

在这里插入图片描述

常见字符串操作函数
char s1="s1";
char s2="s2";
char s3[10];
string s4="s4";
string s5="s5";
string s6;

strcpy(s1,s2);//把s2复制到s1
s6=s4;

strcat(s1,s2);//s2连接在s1后面
连接string可以用 + 号
string s6=s4+s5;

strlen(s1);//返回字符串长度,不包含\0 ,只输出字符的个数,和定义的长度无关!!!
s4.size();

strcmp(s1,s2);//如果s1和s2是相同的,则返回0;如果s1<s2则返回值小于0;如果s1>s2则返回值大于0。
两个字符串自左向右逐个字符相比(按ASCII值大小相比较),直到出现不同的字符或遇'\0'为止,与长度无关
所以在测试s1="helloworld",s2="world"的时候,s1<s2.

在这里插入图片描述

注意!!!!!,这些函数似乎只能对字符数组操作,不能对string操作。
char数组进行字符串操作的函数,头文件<cstring>
string类型变量,头文件<string>

>>> !!! 注意 >>>
> char数组进行字符串操作的函数,头文件<cstring>
> string类型变量,头文件<string>

对比一下:

#include <iostream>
#include <cstring>//主要是调用str相关函数
 
using namespace std;
 
int main ()
{
   char str1[13] = "runoob";
   char str2[13] = "google";
   char str3[13];
   int  len ;
 
   // 复制 str1 到 str3
   strcpy( str3, str1);
   cout << "strcpy( str3, str1) : " << str3 << endl;
 
   // 连接 str1 和 str2
   strcat( str1, str2);
   cout << "strcat( str1, str2): " << str1 << endl;
 
   // 连接后,str1 的总长度
   len = strlen(str1);
   cout << "strlen(str1) : " << len << endl;
 
   return 0;
}
#include <iostream>
#include <string>
 
using namespace std;
 
int main ()
{
   string str1 = "runoob";
   string str2 = "google";
   string str3;
   int  len ;
 
   // 复制 str1 到 str3
   str3 = str1;
   cout << "str3 : " << str3 << endl;
 
   // 连接 str1 和 str2
   str3 = str1 + str2;
   cout << "str1 + str2 : " << str3 << endl;
 
   // 连接后,str3 的总长度
   len = str3.size();
   cout << "str3.size() :  " << len << endl;
 
   return 0;
}
//复习一下
#include <iostream>
#include <cstring>
#include <string>
 
using namespace std;
 
int main ()
{
    char s1[15]="hello";
    char s2[]="world";
    char s3[10];
    
    #if 1
    cout << "length of s1 is " << strlen(s1) << endl;
    
    strcpy(s3,s1);
    cout << "now s3 is " << s3 << endl;
    #endif
    
    strcat(s1,s2);
    cout << "now s1 is " << s1 << endl;//如果这里是s1长度设置为10,可能会出现缓存越界的问题
    cout << "now s2 is " << s2 << endl;
    
    int c=strcmp(s1,s2);
    cout << c << endl;
    
    #if 1
    if(strcmp(s1,s2)>0)
        cout << "s1 is bigger than s2." << endl;
    else if(strcmp(s1,s2)<0)
        cout << "s1 is smaller than s2." << endl;
        else
        cout << "s1 is the same as s2." << endl;
    #endif
        
    #if 1
    string t1="try";
    string t2="again";
    string t3;
    
    cout << "length of t1 is " << t1.size() << endl;
    
    t3=t1;
    cout << "now t3 is " << t3 << endl;
    
    t3=t1+t2;
    cout << "now t3 is " << t3 << endl;
    #endif
   
    return 0;
}


注意!!!!!
数字数组不可以用数组名直接输出整个数组;
字符数组和字符串可以用数组名或变量名直接输出整个字符串。

>>>!!! 注意 >>>
> 数字数组不可以用数组名直接输出整个数组;
> 字符数组和字符串可以用数组名或变量名直接输出整个字符串

//eg.
#include <iostream>
#include <string>

char s1[]="hi";
std::cout << s1 << std::endl;

string s2="hello";
std::cout << s2 << std::endl;
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值