c++基础

C++基础

一、课程介绍

1. c++介绍

C++ 由 Bjarne Stroustrup 于 1979 年在贝尔实验室开始设计开发的,由于C++ 进一步扩充和完善了 C 语言,是一种面向对象的程序设计语言 ,所以最初命名为带类的C 。C++ 是 C 的一个超集,事实上,任何合法的 C 程序都是合法的 C++ 程序。C++ 也是目前嵌入式 ( 无人驾驶 ) 的首选语言。

在这里插入图片描述

2. python 和 c++对比

程序有两种执行方式,解释执行和编译执行。

python是一种解释语言,不需要经过编译,是一边解释一边执行,由于底层封装了很多库供程序员使用,所以开发起来方便快捷,且能够很好地跨平台,写一些小工具小程序特别合适。

c++ 则属于编译语言,是一种需要编译后运行语言,编译后通过链接,整合其他依赖库,然后生成机器码(可执行文件),以后再运行,无需编译。在指定环境下编译运行,运行效率高

在这里插入图片描述

二、环境准备

1. 安装环境

C++ 是一种编译语言,需要安装编译环境。 此类环境有: mingw | cygwin

官网: http://www.mingw.org

2. 安装开发工具

开发工具种类繁多,有VS | Dev-C++ | code lite | clion

三、Hello World

1. 入门程序

#include<iostream>

int main (){

	std::cout<<"hello world !"<<std::endl;
	return 0 ;
}
  • 解释:

    • include : 引入输入输出库

    • int main(){} : 主函数入口

    • std:: … 输出打印

    • return 0 : 函数返回值,一般0 表示正常执行返回。

2. main方法

  1. main函数是C++程序的入口函数,C++标准要求main()函数的返回值类型为int。 0 表示正常退出。
  2. 当main()函数的返回值为int,而函数内并没有出现return语句时,同样可以通过编译并正常运行。这是因为编译器在main()函数的末尾自动添加了return 0;的语句。所以,main()函数是C++程序经过特殊处理的函数。其他的返回值类型不是void的函数,如果没有使用return语句,编译器将报错。
  3. main函数也可以携带参数如:
int mian(){
    
    return 0;
}

int main(int argc){
 
 	return 0 ;
}

3. 使用命令行编译C++代码

  • Windows下编译
// 显示所有警告,使用c++14版本编译, 默认生成a.exe文件 ,linux 下生成的是a.o文件
g++ -Wall -std=c++14 main.cpp

g++ -Wall -std=c++14 main.cpp -o ab.exe

#include<iostream>

int main (){
	std::cout<<"hello world !"<<std::endl;
	reurn 0 ;
}

4. 在线编辑器

如果没有安装编译环境、也没有开发工具,也可以使用网页版的在线编辑器: http://cpp.sh

5. 注释

  • 单行注释

python的单行注释 使用 # , c++的单行注释使用 //

  • 多行注释

python的多行注释 使用''' ''' , c++的多行注释 使用 /* */

四、基本数据类型

数据类型声明
integerint
floating pointfloat
double floating pointdouble
characterchar
booleanbool 0表示假, 非0表示真
valuelessvoid

void 只会在一些场合下出现,我们几乎不会定义void类型的变量。一般会出现在方法的返回值,用于表示方法没有返回值。

1. 声明变量和初始化

整型和浮点数类型统称为算术类型.

变量类型 变量名字 = 变量值 ;

//先声明
int age ;
double price;
...
//后初始化
age = 10 ;
price = 20.3;

//声明及初始化
int age = 20 ;

在C++中,对于变量的初始化有好几种方式,如下:

int age ; //未初始化

int age = 21 ; // C 方式初始化

int age  (21); //构造方法初始化

int age {21} ; //c++ 11标准开始的方式

2. 变量命名规则

  1. 可以包含字母 、 数字 和下划线
  2. 必须以字母或者下划线开始

注意:在C++中,大写字母和小写字母被认为是两个不同的字符。因此,sum和SUM是两个不同的变量名。一般地,变量名用小写字母表示,与人们日常习惯一致,以增加可读性。应注意变量名不能与C++的关键字、系统函数名和类名相同。

有效命名无效命名
Age2019_Age
ageAge+1
_age$age
My_AgeMy Age
Intreturn
2.1变量的最大取值
#include <climits>                //导入头文件
cout << "int类型最大的取值为:" <<INT_MAX<< endl;     //2147483647
cout << "int类型最大的取值为:" <<INT_MIN<< endl;    //-2147483648
2.2控制输出数值的进制(二进制,八进制,十进制)
int a = 100;
    cout << "a=" << a << endl;//十进制输出
    cout << hex;
    cout << "a=" << a << endl;   //十六制输出
    cout << oct;
    cout << "a=" << a << endl;   //八进制输出
2.3输入输出的方式(cin和getline(),get())
//cin通过空格,制表符和换行来确定字符串(输入)的结束位置.
//测试输入:空格,换行,制表符
    cout << "请输入你的名字" << endl;
    string name;
    cin >> name;
    cout << "请输入你的年龄" << endl;
    int age;
    cin >> age;
    cout << "我的名字是:" << name << "   我的年龄是:" << age << endl;

//控制台输出:
//请输入你的名字
//fuhong 24
//请输入你的年龄
//我的名字是:fuhong  
 //测试输入:cin.getline(),传入两个参数:1,保存的变量名称.2.输入的最大长度,3.停止符,到这个字符时停止读取
    cout << "请输入你的名字" << endl;
    string name;
    cin.getline(name,20);
    cout << "请输入你的年龄" << endl;
    int age;
    cout << "我的名字是:" << name << "   我的年龄是:" << age << endl;
    return 0;

cin.getline()会丢弃换行符,cin.get()不会丢弃换行符.

//测试输入:cin.get(),传入两个参数:1,保存的变量名称.2.输入的最大长度,3.停止符,到这个字符时停止读取
    cout << "请输入你的名字" << endl;
    char name1[20];
    cin.get(name1, 20).get();    //这里可以用.get()来处理换行符
    cout << "请输入你的名字" << endl;
    char name2[20];
    cin.get(name2, 20);
    cout << "我的名字是:" << name1 << "   他的年龄是:" << name2 << endl;

3. 常量

常量其实和变量没有多大区别, 有名字, 占据存储空间,可以是任何的基本类型,但只有一点不同,常量的值不允许变更。C++中的常量的声明需要使用 const 关键字,通常首首字母大写.而python中的常量默认约定是全大写表示。

const double Pi {3.1415926};
const int Months_in_year{12};

pi = 2.5 ; //将会出现编译错误

4. 变量的长度大小

我们可以使用sizeof 来获取某个变量的长度大小

例如:

double a = 20.0;
sizeof(a); //8
 
sizeof(int); //4

五、常见编码错误

  • 忘记分号结尾
#include <iostream>
int main (){
    int x
    x = 5;
    return 0;
}
  • 声明和定义错误

忘记声明变量类型

#include <iostream>
int main (){
    x = 5;
    std::cout << x;
    return 0;
}
  • 命名空间错误

没有引入命名空间

#include <iostream>
int main (){
    int x;
    x = 5;
    cout << x;
    return 0;
}
  • 库包含错误

一般出现这种情况都是因为上面忘记引入了库

int main (){
    int x;
    x = 5;
    std::cout << x;
    return 0;
}

六、逻辑控制

1. 条件控制

  • python 和 c++ 对比 , 在C++ 中,数字也可以作为判断的条件,0 表示为假, 非0即为真

在这里插入图片描述

  • c++ if语句语法
if (条件1) {
   语句1;
   语句2;
   ...
}else if (条件2) {
   语句1;
   语句2;
   ...
}else {
   语句1;
   语句2;
   ...
}
a. 关系运算符

python和c++完全一样

OperatorPythonC++
equal====
not equal!=!=
greater than>>
less than<<
greater than or equal>=>=
less than or equal<=<=
b. 逻辑运算符
OperatorPythonC++
andand&&
oror||
notnot!
  • python
height = 220
weight = 250

if height > 190 and weight > 200:
  print('可以成为篮球运动员')

  • c++
double height = 220
double weight = 250
    
if(height > 190 && weight > 200){
    std::cout << "可以成为篮球运动员" << std::endl;
}
c. 三元运算符

一般来说,非真即假的情况下,如果表达式比较简单,通常会采用三元运算符来实现。在相比之下,c++的三元运算符比python的要简单些。

括号里面的表达式得出一个bool类型的值,若为true ,则执行expr1表达式 ; 如果是false,那么执行expr2表达式。
(cond_expr) ? expr1 : expr2 ;
int score = 100;

//python
result = 'A' if 100 > 90  else 'B'
print(result)


//c++
char result = score > 90 ? 'A' : 'B';
std::cout << result <<std::endl;

2. 循环控制

a. while 循环操作

除了大括号外,写法和操作几乎一样 , 休眠操作,使用Sleep()函数 , 不过要记得引入 <windows.h>

在这里插入图片描述

b. do-while循环

do-while循环和while循环都差不多,区别只是先执行后判断的顺序不同而已。

 //一上来,先判断,再执行
 while(cout < 15){

        std::cout << "红灯还在亮着..." << std::endl;

        //单位是毫秒
        //_sleep(1000);
        Sleep(1000);
        cout++;
    }


//先执行一次,然后在判断。
    do{
        std::cout << "红灯还在亮着..." << std::endl;
        //cout++;
    }while(cout > 5);
c. for 循环操作

在这里插入图片描述

3. switch 语句

许多语言中都包含switch,比如:java 、javascript 、php 等,而python是个例外,python没有switch。,实际上switchif 语句块很相似, 它是完全的等价条件判断,但是一旦满足某个case的条件,那么其他case 就不会再进行判断。

在这里插入图片描述

  • 示例
int age = 11 ;
switch (age){
    case 10:
        cout <<"10岁" << endl;
        break;
    case 20:
        cout <<"20岁" << endl;
        break;
    default:
        cout <<"其他年龄" << endl;
        break;
}
  • 注意:
  1. swtich只能做等价条件判断,并且判断的只能是字符或者整型数字
  2. 一次只会执行一个case,如果没有匹配,会执行默认的default分支
  3. 如果某个case缺失break语句,那么会连带执行下一个case分支。

七、命名空间 namespace

假设这样一种情况,当一个班上有两个名叫 张三的学生时,为了明确区分它们,我们在使用名字之外,不得不使用一些额外的信息,比如他们的家庭住址,或者他们父母的名字等等。

同样的情况也出现在 C++ 应用程序中。例如,您可能会写一个名为 a 的变量,在另一个可用的库中也存在一个相同的变量 a。这样,编译器就无法判断您所使用的是哪一个。

因此,引入了命名空间这个概念,专门用于解决上面的问题,它可作为附加信息来区分不同库中相同名称的函数、类、变量等。使用了命名空间即定义了上下文。本质上,命名空间就是定义了一个范围。

1. 自定义命名空间

使用命名空间范围内的成员(变量、函数、类),需要使用 域操作符*(scope operator) ::

//深圳的张三
namespace shenzhen{
    string name = "张三";
}

//武汉的张三
namespace wuhan{
    string name = "张三";
}

int main() {
    cout << shenzhen::name << endl;
    return 0;
}

2. 使用using 指令

可以使用 using namespace 指令,这样在使用命名空间时就可以不用在前面加上命名空间的名称。这个指令会告诉编译器,后续的代码将使用指定的命名空间中的名称。

#include <iostream>
using namespace std;

int main(){
    count<<"hi c++" << endl;
    return 0 ;
}

八、数组

1. python 和c++ 对比

c++的数组实际上和pythonlist 差不多,都是具有下标(索引) , 稍有不同的是,pythonlist不区分类型,而c++的数组必须是同一类型。

在这里插入图片描述

2. 声明和初始化

数组是一系列相同类型的元素,放置在连续的内存位置,数组中的元素都可以通过索引来单独操作它们。查看某个变量存储地址可以使用 取地址符 &

a, 声明数组

仅仅声明,而没有初始化的数组,内部的元素无法得到保证,系统会随机进行赋值。

数组类型 数组名称  [元素个数];

int scores [5]; //表示5个元素的数组

在这里插入图片描述

b. 初始化
数组类型 数组名称  [元素个数]{初始化列表}

声明后再初始化
int scores [5];
scores[0] = 11;
scores[1] = 22;
scores[2] = 33;
scores[3] = 44;
scores[4] = 55;


声明并初始化
int scores [5]{100,89,95,70,80};

int socres [10]{88,75}; //剩下的都会以0占位,只初始化了前两位

int socres [10]{0};; // 表示10个长度的数组,每个元素都是0

//自动推算数组大小
int socres[]{22,33,44,55,66}; //数组长度没有指定,根据后面初始化长度来推断。

3. 访问数组

  • 获取数组中的某个元素

可以使用索引来获取

array_name[element_index]

int scores [5]{100,89,95,70,80};

std::cout<<"数组的第一个元素是: "<< scores[0]<<std::endl;
std::cout<<"数组的第二个元素是: "<< scores[1]<<std::endl;
std::cout<<"数组的第三个元素是: "<< scores[2]<<std::endl;
std::cout<<"数组的第四个元素是: "<< scores[3]<<std::endl;
std::cout<<"数组的第五个元素是: "<< scores[4]<<std::endl;


//越界,不会报错,但是输出内容不是我们想看到的
std::cout<<"数组的第一个元素是: "<< scores[5]<<std::endl; 
           
           
//修改指定位置的元素
scores[0] = 66;
  • 遍历数组

c++的数组,并没有提供获取长度的方法,所以不能直接遍历。一种是直接指定遍历的长度,一种是通过代码计算出数组的长度 ,一种是使用c++11提供的基于范围的for循环

//定义数组
int  scores[]{100,95,97,88,85,80,75};


//直接指定数组
for(int i = 0; i < 7; i++){
    std::cout << scores[i] << std::endl;
}


//手动计算数组长度
int length = sizeof(scores) / sizeof(int);
for(int i = 0 ; i < length; i++){
     std::cout << scores[i] << std::endl;
}

//c++11 提供的for循环 , 基于范围的for循环可以不再关心迭代器的概念,只需要关系容器中的元素类型即可,同时也不必显式的给出容器的开头和结尾。
for(int score : scores){
      std::cout <<cores[i] << std::endl;
}

4. 多维数组

数组里面的元素存储的还是数组,即可称之为多维数组。二维数组是常见的多维数组,再多维度的数组阅读起来就稍微有点复杂了。

  • 声明
数组类型  数组名称[x] [y];  //x可以认为是有多少行 , y可以认为是有多少列

在这里插入图片描述

  • 初始化

在这里插入图片描述

九、字符串

字符串是最常用的一种数据类型了,在python中声明字符串和声明其他类型的数据一样,都非常的简单。但是在c++中,对于字符串的操作,相对来说要稍微复杂一些。

C++ 提供了以下两种类型的字符串表示形式:

  • C 风格字符串
  • C++ 引入的 string 类类型

1. 字符函数

用于操作字符的函数

在这里插入图片描述

在这里插入图片描述

2. C风格的字符串

C 风格的字符串起源于 C 语言,并在 C++ 中继续得到支持。字符串实际上是使用 null 字符 ‘\0’ 终止的一维字符数组。因此,一个以 null 结尾的字符串,包含了组成字符串的字符。

  • 下面的声明和初始化创建了一个 “Hello” 字符串。由于在数组的末尾存储了空字符,所以字符数组的大小比单词 “Hello” 的字符数多一个。
char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};

可以简写成:

char greeting[] = "Hello";

在这里插入图片描述

3. 字符串函数

C语言中提供了针对字符串操作的大量函数,不过在使用之前,需要先引入 #include <cstring>

函数作用
strcpy(s1, s2)复制字符串 s2 到字符串 s1
strncpy( s1, s2 , n )赋值字符串s2 的 n个长度字符到s1 ( 默认从0位置开始 )
strcat(s1, s2)拼接 s2 到 s1 的末尾
strlen(s1)返回字符串s1的长度
strcmp(s1, s2)比较字符串是否一致
strchr(s1, ch)返回一个指针,指向字符串 s1 中字符 ch 的第一次出现的位置。
strstr(s1, s2)返回一个指针,指向字符串 s1 中字符串 s2 的第一次出现的位置。
strrev(s1)反转字符串 , 针对char数组
reverse(s1)反转字符串 ,针对string字符串 ,需导入 #include<algorithm>

4. C++的字符串

C++ 标准库提供了 string 类类型,支持上述所有的操作,另外还增加了其他更多的功能。需要引入 #include <string>

  • 声明和初始化
//引入string库
#include <string>

using namespace std;

int mian(){
    
    string s1;
    string s2 {"北京"};
    string s3{s2};
    
    s1 = s3;
    
    
    return 0 ;
}

5. 字符串操作

  • 拼接字符串

c++的字符串拼接,使用起来比较方便,直接使用+ 操作即可。

string part1 {"c++"};
string part2 {" is a powerful"};

string sentence ; 
sentence = part1 + part2 ;
  • 获取指定位置的字符

可以使用[]和 at()操作字符串

string s1 {"i love c++"};

cout << s1[3]<<endl;
cout << s1.at(0) << endl;
  • 遍历字符串
string s1 {"abcdef"};

for(char s : s1){
    cout << s << endl;
}

for(int s : s1){
    cout << s <<endl;
}
  • 字符串比较

字符串也是可以比较大小的。

string s1{"Apple"};
string s2{"Banana"};
string s3 {"kiwi"};
string s3 {"apple"};
string s3 {s1};

s1 == s5 // true
s1 == s2 // false
s1 != s2 // true
s1 < s2 // True
s1 > s2 // false
s1 == "Apple" // false
  • 截取字符串
substr(开始索引, 截取长度);

string s1 {"This is a test"};
cout << s1.substr(0 , 4) ; // This
  • 获取字符(字符串)在字符串中的索引
find(搜索的字符)
    
string s1 {"This is a test"};
cout << s1.find("This") ; // 0 
cout << s1.find("is") ; // 2
cout << s1.find("test") ; // 10 
  • 获取字符串长度
length() : 返回字符串长度

一、Vector

Vector其实很大程度上和数组一样,只是,数组是固定长度,而vector是不定长度(动态增长)。 假设我们需要记录明年的测试成绩,但是我们并不知道明年会有多少个学生。那么可以有两种选择,定义一个固定长度的数组,这个长度超过假设的长度, 另一种办法就是使用动态数组,比如是: vector

1. 什么是Vector

在C++STL(标准模板库)中的一个容器,可以看成是对容器的一种扩展。

在运行时可以改变长度

与数组具有相似的语法

相比数组更高效 , 提供越界检查

2. 声明和初始化

  • 声明
#include <vecotr>

vector <char> vowels; 
vector <int> test_score;

// =========================
vector <char> vowels(5);  //声明一个初始大小为5的char类型vector
vector <int> test_score(10);

  • 初始化
//数组定义
int test_score []{100,99,18,81}


vector <char> vowels {'a' , 'e' , 'i' , 'o' ,'u'}; 
vector <int> test_score{ 100 ,98,95,90,80};
vector <double> temperatures{26,20.7};

3. 访问vector

  • 数组的语法
#include <vector>

vector<int> test_score {100,90,85};

cout << "第一个成绩是: " <<test_score[0] << endl;
cout << "第二个成绩是: " <<test_score[1] << endl;
cout << "第三个成绩是: " <<test_score[2] << endl;

cout << "第三个成绩是: " <<test_score[3] << endl;  //不会检查越界

  • vector 的语法
#include <vector>

vector<int> test_score {100,90,85};

cout << "第一个成绩是: " <<test_score.at(0) << endl;
cout << "第二个成绩是: " <<test_score.at(1) << endl;
cout << "第三个成绩是: " <<test_score.at(2) << endl;


cout << "第三个成绩是: " <<test_score.at(3) << endl; //抛出越界异常

  • 修改vector中的元素
vector<int> test_score {100,90,85};

test_score.at(0) = 73;
  • 往vector中追加元素
vector<int> test_score {100,90,85};

test_score.push_back(80); // 100 , 90 , 85 , 80
test_score.push_back(95); // 100 , 90 , 85 , 80 , 95

//vector会自动分配它要求的大小
  • 删除vector中的元素

    vector<int > scores{60,65,50,70,80};
    auto i = scores.begin();
    while(i != scores.end()){
        if(*i.base() == 50){
            scores.erase(i);
        }
        i++;
    }
    
    

  • 越界检查

只要当我们使用了vector的语法去获取超出索引的元素时,就会抛出异常。而使用数组的语法去获取元素,则不会进行越界检查

在这里插入图片描述

  • 遍历vector
//使用下标遍历
vector<int> scores{ 100 ,95 ,88 ,80 ,75};
for (int i = 0; i < scores.size(); ++i) {
    cout << scores[i] << endl;
}

//基于范围for遍历
vector<int> scores{ 100 ,95 ,88 ,80 ,75};
for(int score : scores){
    cout << score << endl;
}

4. 二维Vector

二维vector和二维数组实际上差不太多,二维数组是数组里面装的是数组,二维vector指的是vector里面装的还是vector,在未来碰到矩阵相关的存储操作,多半使用vector来作为媒介。 比如下面的例子,演示了使用vector来存储3个班的考试成绩。每个班的成绩单独使用一个vector来存储。

//声明并初始化vector
vector<vector<int>> scores {
        {95,77,80,85},
        {58,89,93,100},
        {69,73,81,97}
};



for (int i = 0; i < scores.size(); ++i) {
    for (int j = 0; j < scores[i].size(); ++j) {
       cout << scores[i][j] <<"\t" ;
    }
    cout << endl;
}

二、 函数

在大多数地方,c++ 和 python的函数是一样的,都是用来包裹定义好的语句,避免重复拷贝粘贴。不过还是有些许不一样的地方。

  1. python的函数是以回车换行结尾,c++的函数是以 大括号结尾
  2. python的函数通常使用缩进方式来表示函数体, ,c++使用大括号区域来表示
  3. python是动态类型语言,而c++是静态类型语言,所以有时候需要像声明变量一样,声明函数。

在这里插入图片描述

1. 定义函数

函数的定义一般可以包含以下几个部分: 方法名称方法参数返回值方法体

如:
返回值  方法名称(参数){
	方法体
	返回值
}

int function_name(){
    statements(s);
    return 0 ; 
}
  • 调用函数
void say_hello(){ 
    count << "hello" << endl;
}

int main(){
    
    say_hello();
    return 0 ;
}

2. 函数原型

一般来说,c++的函数一般包含声明和定义两个部分。因为c++是静态类型语言,程序属于自上而下编译,所以在使用函数前,必须先表示函数的存在,告诉编译器函数所需要的参数以及函数的返回值是什么。

//函数声明 ,也叫函数原型 并不知道这个函数具体是如何实现的。只是有一些基本架子而已。
int add (int a , int b);

int main(){
    add(1 ,2);
    return 0 ;
}

//函数定义 ,函数的真正实现。
int add(int a , int b){
    return a + b ; 
}
1. 关于函数声明

也并不一定要在main函数前面先声明函数,然后main的后面定义函数 。我们可以把函数直接定义到main函数的前面去,但是还是建议在对函数操作时,声明和定义都带上。

//函数定义 ,函数的真正实现。
int add(int a , int b){
    return a + b ; 
}

int main(){
    add(1 ,2);
}
2. 分离式编译

一般说来,函数的声明 ( 函数原型 )通常都会放到头文件中,之所以称之为头文件是因为它总是在main函数的前面就引入进来。头文件一般以 .h 或者 .hpp 结尾,通常用于 写类的声明(包括类里面的成员和方法的声明)、函数原型、#define常数等,但一般来说不写出具体的实现

  • math.h

为了能够让声明和定义能够快速的被关联上,通常它们的名称会被定义成一样的,这已经成为了一种默认的规定

//函数声明
int add (int a , int b);
  • math.cpp
#include "math.h"

//函数定义 ,函数的真正实现。
int add(int a , int b){
    return a + b ; 
}
  • main.cpp
#include <iostream>  
#include "math.h" //这里使用"" 表示从当前目录查找

int main(){
    add(1 ,2);
    return 0 ;
}

3. 多返回值

与python不同的是,但是在c++ 函数只能有一个返回值,并且在函数声明时必须表明返回值的类型 ,如果函数没有返回值,那么一般使用 void 来表示返回值类型 。 在python中,函数是可以具有多个返回值的,返回值类型无需表示

  • python
def add(a, b): 
    return a + b, a + 10 
  • c++
int add(int a , int b){
    return a + b;
}

4. 函数重载

在许多语言中,经常会见到两个或者两个以上的函数名称是一样的,当然他们的 参数个数 或者 参数类型 或者是 参数的顺序 是不一样的。这种现象有一个学名叫做 重载 overload, 由于python属于动态类型语言,不区分数据类型,参数可以是任意类型,所以它没有重载。

在这里插入图片描述

  • c++
int add(int a , int b){
    return a + b ;
}

int add(int a , int b , int c){
    return a + b + c;
}


int add(double a , double b){
    return a + b ;
}

int main(){
    add(3, 3);
    add(3, 3, 3);
    add(2.5 , 2.5);
        
    return 0 ;
}

5. 函数参数

python的函数,在传递参数的时候,有可变对象和不可变对象的现象,那么在C++里面也有类似的说法。只不过是另一种说辞罢了。

python中传递不可变对象,在C++中,对应的是值的拷贝,也就是传递的只是数据的一份拷贝而已。在函数内部修改数据,并不会改变外部数据

python中传递可变对象,在c++中,对应的是引用传递,也就是传递的是对象的引用,而不是拷贝。在函数内部修改数据,会导致外部数据也发生改变。

1. 值拷贝传递

C++默认情况下,处理函数参数传递时,多数使用的是值的拷贝,少数部分除外。

void  scale_number(int num);

int main(){
    int number{1000};
    scale_number(number);
    
    //打印number 1000
    cout << number << endl;
    return 0 ;
}

void scale_number(int num){    
    if(num > 100)
        num = 100;
}


2. 传递数组

函数的参数除了能传递普通简单的数据之外,数组也是可以传递的。但是数组稍微有点特殊,这里多做讲解。

  1. 前面提过,形参实际上就是实参的一份拷贝,就是一个局部变量。
  2. 数组的数据太大,如果都进行拷贝,那么比较麻烦,也造成了浪费
  3. 所以实际上传递数组的时候,并不会进行整个数组的拷贝,而只是传递数组的第一个元素内存地址 (指针 ) 进来。
  4. 数组的数据还是在内存中,只是把第一个元素(也就是数组的起始)内存地址传进来而已。
  5. 这就造成了函数的内部根本无法知道这个数组的元素有多少个。
using namespace std;
//传递数组长度
void 	print_array(int number[] , 5 );

int main(){
    //声明数组
    int array []{1,2,3,4,5};
    
    //打印数组
    print_array(array , 5);
    
    return 0 ;
    
}

//传递数组,打印数组
void print_array(int array[] , int size){
    for (int i {0} ; i < size ; i++){
        count << array[i] << endl;
    }
}
3. 传递引用

目前为止,我们所有函数的参数传递,都是对数据进行了一份拷贝(数组除外)。那么在函数的内部是不能修改值的,因为这仅仅是一份值得拷贝而已(函数外部的值并不会受到影响)。如果真的想在函数内部修改值,那么除了数组之外,还有一种方式就是传递引用

void  scale_number(int &num);

int main(){
    int number{1000};
    scale_number(number);
    
    //打印number100
    count << number <endl;
    return 0 ;
}

void scale_number(int &num){
    if(num > 100)
        num = 100;
}
4. 练习: 传递vector

既然掌握了使用传递引用,以便修改外部数据,那么来修改下传递vector吧。vector和普通的数据一样,传递的时候,做的是值得拷贝。数据有点浪费,只想传递引用,怎么办呢?

void chage_data(vector<int> &v);

int main(){
    vector<int> scores {95,79,53,85,95,90};
    chage_data(scores);

    for(int s : scores){
        cout << s << endl;
    }
    return 0 ;
}
void chage_data(vector<int> &v){
    for(int i = 0 ; i<v.size() ; i++){
        if(v[i] < 60 ){
            v[i] = 60;
        }
    }
}

6. 函数是如何被调用工作的

  1. 函数是使用函数调用栈来管理函数调用工作的。
    1. 类似盒子的栈
    2. 遵循后进先出
    3. 可以往里面执行压栈和出栈动作(push 和 pop)
  2. 栈的结构和激活记录
    1. 函数必须把它的返回值返回给调用它的函数(A —> B)
    2. 每次函数的调用都需要创建一次激活记录,然后把它压入栈中(push)
    3. 当一个函数被调用完毕的时候,就需要从栈中弹出(pop)
    4. 函数的参数以及内部的局部变量都是存储在栈中。
  3. 函数栈有可能抛出栈溢出异常(Stack Overflow)
    1. 一旦函数调用栈中被push进来的函数记录过多,就有可能出现。(例如:无限循环调用)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eBRGeX51-1581313773494)(img/18.png)]

void func2(int &x , int y , int z){
    x +=y+z;
}

int func1(int a , int b){
    int result{};
    result += a + b;
    func2(result , a , b );
    return result ; 
}

int main (){
    int x{10};
    int y{20};
    int z{};
    
    z = func1(x , y );
 //打印值为60;   
    cout << z << endl;
    return 0 ;
}

7 . 内联函数

函数可以使我们复用代码,但是一个函数的执行,需要开辟空间、形参和实参进行值得拷贝,还要指明函数返回、以及最后回收释放资源的动作,这个过程是要消耗时间的。

  • 作为特别注重程序执行效率,适合编写底层系统软件的高级程序设计语言,如果函数中只有简单的几行代码,那么可以使用inline 关键字来解决了函数调用开销的问题
inline int calc_Max (int a, int b)
{
    if(a >b)
        return a;
    return b;
}

增加了 inline 关键字的函数称为“内联函数”。内联函数和普通函数的区别在于:当编译器处理调用内联函数的语句时,不会将该语句编译成函数调用的指令,而是直接将整个函数体的代码插人调用语句处,就像整个函数体在调用处被重写了一遍一样。

有了内联函数,就能像调用一个函数那样方便地重复使用一段代码,而不需要付出执行函数调用的额外开销。很显然,使用内联函数会使最终可执行程序的体积增加。以时间换取空间,或增加空间消耗来节省时间,这是计算机学科中常用的方法。

8. 范围规则

在学习过程,我们会定义很多变量或者引用、这些变量由于定义的位置不同,所以它们的作用域范围也不同。

  1. c++的的变量作用规则是:从它开始定义的地方起作用。
  2. 使用static关键字会让它变得不一样
  3. 本地或者块范围
  4. 全局范围
  • 本地或者代码块的作用域
  1. 通常定义在 {} 中
  2. 函数参数具有本地变量作用域
  3. 在{}中声明的,只能在{}中有效
  4. 函数的局部变量只有在函数执行的时候才会有效
  • 单独代码块
int main(){
    
    int  num{10};
    int  num1{20};
    
    cout << num << num1 << endl;
    
    {
        int num{100};
        count << "num = "<< num << endl;
         count << "num1 = "<< num1 << endl;
    }
    
}


  • 函数中局部变量
int num{300};
void local_example(int x){
    
    
    int num{1000};
    count << "num =" << num << endl;
    
    num = x ;
    count << "num =" << num << endl;
 
    
}
  • 静态本地变量
static int value{10};
  1. 只会初始化一次
  2. 重复调用函数也只会初始化一次。
void static_local_example(){
    
    static int num{100};
    cout << "num ="<< num << endl;
    num+=100;
    cout << "num ="<< num << endl;
}

int main(){
    static_local_example();
    static_local_example();
    return 0 ;
}

  • 全局变量

通常声明在所有函数和类的外部 ,若存在局部变量和全局变量同名情况下,可以使用 域操作符 :: 来访问全局变量

using namespace std;

int age = 99;
int main(){
    
    int age =18 ;
    cout << ::age << endl;
    return 0 ;
}

三、 结构体

结构体是一个由程序员定义的数据类型,可以容纳许多不同的数据值。在过去,面向对象编程的应用尚未普及之前,程序员通常使用这些从逻辑上连接在一起的数据组合到一个单元中。一旦结构体类型被声明并且其数据成员被标识,即可创建该类型的多个变量,就像可以为同一个类创建多个对象一样。 结构体是由C语言发明出来的,它和类其实没有差多少,只是它的所有成员默认都是public公开。

1. 定义结构体

声明结构体的方式和声明类的方式大致相同,其区别如下:

  • 使用关键字 struct 而不是关键字 class。
  • 尽管结构体可以包含成员函数,但它们很少这样做。所以,通常情况下结构体声明只会声明成员变量。
  • 结构体声明通常不包括 public 或 private 的访问修饰符。
  • 类成员默认情况是私有的,而结构体的成员则默认为 public。程序员通常希望它们保持公开,只需使用默认值即可。
struct Student{
    
    string name;
    int age;
}

Student s1 ;
s1.name = "zhangsan";
s1.age = 18 ;
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值