C++学习笔记黑马程序员(有一些自己的思考)

学习目标:

  • 掌握 C++入门知识
  • C++核心编程
  • 掌握 STL
  • 洛谷算法训练题

学习内容:

C++入门知识

一、基本介绍:C++不同于C语言,这是一门面向对象的高级程序设计语言。
二、面向对象与面向过程:什么是面向对象?对象又是什么? 对象是对客观事物的抽象,也就是说,任何事物都可以看做对象。说到面向对象,就不得不提面向过程了。我们可以举个例子来理解他们:
例如:我们要去自动售货机买饮料,如果面向过程:我们需要走到售货机前,投掷硬币,拿到饮料,它所针对的是我买饮料的这个过程。而面向对象则是:自动售货机有哪些功能,收钱、找钱、送出饮料,它面向的是整个过程。
三、C++基本结构
众所周知,每一门语言都有自己的基本结构,下面让我来介绍一下C++的基本结构吧!

#include <iostream>
using namespace std;
 
// main() 是程序开始执行的地方
 
int main()
{
   cout << "Hello World"; // 输出 Hello World
   return 0;
}
  • C++ 语言定义了一些头文件,这些头文件包含了程序中必需的或有用的信息。上面这段程序中,包含了头文件 。
  • 下一行 using namespace std; 告诉编译器使用 std 命名空间。命名空间是 C++ 中一个相对新的概念
  • 下一行 // main() 是程序开始执行的地方 是一个单行注释。单行注释以 // 开头,在行末结束。
  • 下一行 int main() 是主函数,程序从这里开始执行。
  • 下一行 cout << “Hello World”; 会在屏幕上显示消息 “Hello World”。
  • 下一行 return 0; 终止 main( )函数,并向调用进程返回值 0。

四、变量
1、什么是变量:变量名称本身就是一个指针指向你一个空间用来存储你的数据,其作用就是给一段指定的内存起名,方便我们操作这段内存。
2、变量创建语法:数据类型 变量名 = 变量初始值
3、示例

#include <iostream>
using namespace std;
int main() {
    int a=10;
    cout<< a<<endl;
    return 0;
}

规定所有用到的变量要先定义后使用,编译器处理起来比较方便,不会有歧义。因为 C++ 里面,相同名字的变量在不同的作用域里面,是可以重复声明的,而一个{}就是一个作用域。
五、常量
1、作用:用于记录程序中不可更改的数据
2、定义方式:
<1> #define 宏常量 #define 常量名 常量值 通常在文件上方定义
<2> const修饰的变量 const 数据类型 常量名 = 常量值
3、示例

#include <iostream>
#define day 7
using namespace  std;
int main() {
   const int time=24;
cout<<"一周有"<<day<<"天"<<endl;
cout<<"一天有"<<time<<"小时"<<endl;
}

五、关键字
作用:关键字是C++中预先保留的单词,也称标识符。

  • 在定义变量或者常量时,不得使用关键字,否则会产生歧义
    在这里插入图片描述
    六、标识符命名规则
    作用:C++规定标识符(变量、常量)命名时,有一套自己的规则
  • 标识符不能是关键字
  • 标识符只能由字母、数字以及下划线组成
  • 第一个字符必须是字母或下划线
  • 标识符中的字母区分大小写
    给标识符命名时,一定要做到见明知意
    七、数据类型
    存在意义:给变量分配合适的内存空间。
    在这里插入图片描述

1、整型
在这里插入图片描述
2、sizeof关键字
<1>作用:利用sizeof关键字可以统计数据类型所占内存大小
<2>语法:sizeof( 数据类型 / 变量 )
<3>

#include <iostream>
using namespace std;
int main(){

    cout <<"short类型所占空间"<<sizeof(short)<<endl;
    cout <<"int类型所占空间"<<sizeof(int)<<endl;
    cout <<"long类型所占空间"<<sizeof(long)<<endl;
    cout <<"long long类型所占空间"<<sizeof(long long)<<endl;
    cout <<"float类型所占空间"<<sizeof(float)<<endl;
    cout <<"double类型所占空间"<<sizeof(double)<<endl;
    cout <<"long double类型所占空间"<<sizeof(long double)<<endl;
    cout <<"char类型所占空间"<<sizeof(char)<<endl;
    cout <<"unsigned char类型所占空间"<<sizeof(unsigned char)<<endl;
    cout <<"unsigned short类型所占空间"<<sizeof(unsigned short)<<endl;
    cout <<"unsigned int类型所占空间"<<sizeof(unsigned int)<<endl;
    cout <<"unsigned long类型所占空间"<<sizeof(unsigned long)<<endl;
    cout <<"unsigned long long类型所占空间"<<sizeof(unsigned long long)<<endl;
    cout <<"bool类型所占空间"<<sizeof(bool)<<endl;


}

3、浮点型
<1>作用:用于表示小数
<2>分类:浮点型变量分为两种:单精度(float)和双精度(double)

数据类型占用空间有效数字范围
float4字节7位有效数字
double8字节15~16位有效数字

<3>示例

#include<iostream>
using namespace std;
int main(){
    float f1=3.14f;//不加f系统会认为是double类型的
    cout<<"f1="<<f1<<endl;
    double dl=3.14;
    cout<<"dl="<<dl<<endl;
}

4、字符型
<1>作用:字符型变量用于显示单个字符
<2>语法:char ch='a'

注意:在显示字符型变量时,用单引号将字符括起来

  • c/c++中字符型变量只占用一个字节
  • 字符型变量并不是把字符本身到内存中存储,而是将对应的ASCII编码放入存储单元

<3>示例

#include<iostream>
using namespace std;
int main(){
    char ch='a';
    cout <<ch<<endl;
    cout<<sizeof(char)<<endl;
    cout<<(int)ch<<endl;
}

5、字符串型
<1>作用:用于表示一串字符
<2>语法:string 变量名 =“字符串值”
<3>示例:

#include <iostream>
#include <string>
using namespace std;
int main(){
    string str="adfg";
    cout<<str<<endl;
}

6、布尔类型
<1>作用:布尔数据类型代表真或假的值
bool类型只有两个值:

  • true --真(本质是1)
  • false–假(本质是0)

bool类型只占一个字节
<2>示例:

#include<iostream>
using namespace std;
int main(){
    bool flag=true;
    cout<<flag<<endl;
    cout<<sizeof(flag)<<endl;
}

八、运算符
1、算术运算符
<1>作用:用于处理四则运算
<2>分类
在这里插入图片描述

#include<iostream>
using namespace std;
int main(){
    int a1=10;
    int b1=3;
    double d1=3.14;
    double d2=3.1;
    cout<<a1+b1<<endl;
    cout<<a1-b1<<endl;
    cout<<a1*b1<<endl;
    cout<<a1/b1<<endl;
    cout<<a1%b1<<endl;
    //cout<<d1%d2<<endl;  //必须有整数
}

2、逻辑运算符
<1>作用:进行逻辑运算
在这里插入图片描述
<2>示例:

#include <iostream>
using namespace std;
 
int main()
{
   int a = 5;
   int b = 20;
   int c ;
 
   if ( a && b )
   {
      cout << "Line 1 - 条件为真"<< endl ;
   }
   if ( a || b )
   {
      cout << "Line 2 - 条件为真"<< endl ;
   }
   /* 改变 a 和 b 的值 */
   a = 0;
   b = 10;
   if ( a && b )
   {
      cout << "Line 3 - 条件为真"<< endl ;
   }
   else
   {
      cout << "Line 4 - 条件不为真"<< endl ;
   }
   if ( !(a && b) )
   {
      cout << "Line 5 - 条件为真"<< endl ;
   }
   return 0;
}

九、程序流程结构
C/C++支持最基本的三种程序运行结构:顺序结构、选择结构、循环结构

  • 顺序结构:程序按顺序执行,不发生跳转
  • 选择结构:依赖条件是否满足,有选择的执行相应功能
  • 循环结构:依据条件是否满足,循环多次执行某段代码

顺序结构比较简单,在此就不多做赘述
1、选择结构
<1>作用:执行满足条件的语句
<2>格式:

  • 单行格式if语句
  • 多行格式if语句
  • 多条件if语句
    <4>练习题:
    这里推荐大家去练习洛谷的算法题,题目如下:
    输入一个年份(大于 1582 的整数 ),判断这一年是否是闰年,如果是输出 1,否则输出 0。
    解答:
#include <iostream>
using namespace std;
int main() {
int year;
cin>>year;
    if ((year%4==0&&year%100!=0)||year%400==0){
        cout<<"1";
    }
    else cout<<"0";
}

2、循环结构
<1>作用:满足循环条件,执行循环语句
<2>分类:
①while语句:while(循环条件){循环语句}

#include <iostream>
using namespace std;
int main() {
    int n;
    cin>>n;
while(n--){
    cout<<n<<endl;
}

}

②for语句:for(起始表达式;条件表达式;末尾循环体){循环语句;}

#include <iostream>
using namespace std;
int main() {
    int n;
    cin>>n;
    for (int i = 0; i < n; i++) {
        cout<<i<<endl;
    }

}

<3>解释:只要循环条件位置,就执行循环语句。
<4>两大语句break、continue
break
①作用:终止循环
②使用时机:

  • 出现在switch语句中,作用是终止case并跳出switch
  • 出现在循环语句中,作用是跳出当前循环
  • 出现在嵌套循环语句中,跳出最近内层循环语句

continue
①作用:在循环语句中,跳过本次循环中余下的语句,继续执行下一次循环
②示例:

#include <iostream>
using namespace std;
int main() {
    int n;
    cin>>n;
    for (int i = 0; i < n; ++i){
        if(i%2==0){
            continue;
        }
        cout<<i<<endl;
    }
}

十、数组
1、概述:所谓数组,就是一个集合,里面存放了相同类型的数据元素
2、特点:<1>数组中每个数据元素都是相同的数据类型;<2>数组是由连续内存位置组成的
3、语法:数据类型 数组名[]={值1,值2};
4、数组名
<1>用途:①可以统计整个数组在内存中的长度②可以获取数组在内存中的首地址
<2>示例

#include <iostream>
using namespace std;
int main(){
    int arr[10]={1,2,3,4,5,6,7,8,9,10};
    cout<<sizeof(arr)<<endl;//整个数组所占内存空间
    cout<< sizeof(arr[0])<<endl;//每个元素所占内存空间
    cout<<sizeof(arr)/sizeof(arr[0])<<endl;//数组长度
    cout<<(long long)arr<<endl;//数组的首地址

}

十一、函数
1、作用:
<1>将一段经常使用的代码封装起来,减少重复代码
<2>将较大的程序分割成几个较小的代码块,每个代码块实现特定的功能
2、函数的定义
函数的定义一般主要有以下5个步骤:
<1>返回值类型
<2>函数名
<3>参数表列
<4>函数体语句
<5>return语句
3、函数的调用
<1>语法:函数名(参数)
<2>值传递:
函数调用时实参将值传入给形参
重点来啦!
数组在传参会退化成指针
为什么会退化:C语言只会以值拷贝的方式传递参数,参数传递时,如果只拷贝整个数组,效率会大大降低,并且在参数位于栈上,太大的数组拷贝将会导致栈溢出。

示例:

#include <iostream>
using namespace std;
void test(int *a){}//此处传参传的是数组首地址
void test2(int a[]){}//用数组的形式传递参数,不需要指定参数的大小,因为在一维数组传参时,形参不会真实的创建数组,传的只是数组首元素的地址。(如果是变量的值传递,那么形参就是实参的一份拷贝)
void test3(int b[][3]){}//二维数组与此不同,必须要传列数
int main(){
    int a[3]={1,2,3};
    int b[][3]={1,2,3};
    test(a);
    test2(a);
}

十二、指针
指针是C++非常重要的知识,本文会用大量篇幅介绍。

1、指针基本概念
<1>作用:可以通过指针间接访问内存,也就是说可以通过指针来保存地址
<2>定义法则:数据类型 * 变量名;
所有指针的值的实际数据类型,不管是整型、浮点型、字符型,还是其他的数据类型,都是一样的,都是一个代表内存地址的长的十六进制数。不同数据类型的指针之间唯一的不同是,指针所指向的变量或常量的数据类型不同。
<3>示例:

#include<iostream>
using namespace std;
int main(){
    int a=10;
    int *p;   //指针定义
    p=&a;     //让指针记录变量a的地址
    cout<<&a<<endl; //a的地址
    cout<<p<<endl;  //指针p的地址
    cout<<*p;//指针前加*解引用的方式来找到指针指向的内存
}

2、空指针与野指针
<1>空指针基本概念:指针变量指向内存中编号为0的空间,用于初始化指针。
注意:空指针指向的内存是不可访问的。因为0~255之间的内存编号是系统占用。
<2>野指针基本概念:指针变量指向非法的内存空间。野指针编译器检测不出来错误但无法运行,在程序中应该避免野指针。
3、const修饰指针
<1>分类
①const修饰指针 – 常量指针,即指针的指向可以修改,但指针指向的值不能修改。
②const修饰常量-- 指针常量,指针的指向不可以改,指针指向的值可以改
③const即修饰指针,又修饰常量,指针的指向以及指针指向的值均不能修改
<2>区分方法:可以根据它们定义的方法进行区分,const修饰谁,谁就不能改变。例如

const int *p;

它修饰的是值,是常量指针,所以值不能变。

int const *p;

它修饰的是指针,是指针常量,所以指向不能改变。
4、指针和数组
<1>作用:利用指针访问数组中的元素
<2>指针与数组的关系:一个指向数组开头的指针,可以通过使用指针的算术运算或数组索引来访问数组。 众所周知,数组名可以获取数组的首地址,那么它就可以算作一个指针常量,可以使用*
示例:

#include <iostream>
using namespace std;
int main(){
    int arr[]={1,2,3,4,5};
    cout<<*arr<<endl;
}

<3>值传递与地址传递
①概念:上文中写到在值传递过程中形参无法改变实参。
②示例:

#include <iostream>
using namespace std;
void swap(int a,int b){
    int temp=a;
    a=b;
    b=temp;
}
int main(){
    int a=10;
    int b=20;
    swap(a,b);
    cout<<a<<endl;
    cout<<b<<endl;
}

在这里插入图片描述
由此可见值传递过程中形参无法改变实参,那如果我想改变呢?这里就要用到地址传递了。

#include <iostream>
using namespace std;
void swap(int *p1,int *p2){
    int temp=*p1;
    *p1=*p2;
    *p2=temp;
}
int main(){
    int a=10;
    int b=20;
    swap(&a,&b);
    cout<<a<<endl;
    cout<<b<<endl;
}

在这里插入图片描述
③原理:地址传递之所以能够改变实参的值,是利用了指针指向地址的特性,间接修改了实参的值。
十三、结构体
结构体在数据结构中有重要的应用,是非常重要的知识。
1、结构体基本概念:结构体用于用户自定义的数据类型,允许用户存储不同的数据类型。
2、语法:struct 结构体名{结构体成员列表};
通过结构体创建变量的方式有三种:

  • struct结构体名 变量名
  • struct结构体名 变量名 ={成员1值,成员2值…}
  • 定义结构体时创建变量
#include<iostream>
using namespace std;
struct Student{
    string name;
    int  age;
    double  score;
};
int main(){
    //struct结构体名 变量名
    struct Student s1;
    s1.age=12;
    //struct结构体名 变量名 ={成员1值,成员2值...}
    Student s2={"hj",12,80};
}

3、结构体数组
<1>将自定义的结构体放在数组中便于维护
<2>示例

#include<iostream>
using namespace std;
struct Student{
    string name;
    int  age;
    double  score;
};
int main(){
   struct Student array[3]{
           {"张三",12,100},
           {"李四",12,80},
           {"王五",12,60}

   };
   array[1].age=13;
}

4、结构体指针
<1>作用:通过指针访问结构体中的成员
<2>使用方法:利用->访问结构体中的成员
<3>示例:

#include<iostream>
using namespace std;
struct Student{
    string name;
    int  age;
    double  score;
};
int main(){
    Student stu={"hjh",12,100};
    struct Student *p=&stu;
    cout<<p->age<<endl;

}

在这里插入图片描述
至此,基础语法介绍完毕。

C++核心编程

一、内存分区模型
1、大致分类
C++程序执行时,将内存大方向划分为4个区域

代码区:存放函数体的二进制代码
全局区:存放全局变量和静态变量以及常量
栈区:由编译器自动分配释放,存放函数的参数值,局部变量等
堆区:由程序员分配和释放,若程序员不释放,程序结束由操作系统回收
不同区域存放的数据,赋予不同的生命周期,给我们更大的灵活编程

2、详细解读
程序运行前
<1>代码区:
①存放CPU执行机器指令
②代码区是共享的,共享的目的是对于频繁被执行的程序,只需在内存中有一份代码即可
③代码区是只读的,使其只读的原因是防止程序意外地修改指令
<2>全局区
①存放全局变量以及静态变量
②全局区还包括常量区、字符区以及其他常量
③该区域的数据在程序结束后由操作系统释放
程序运行后
<1>栈区
①由编译器自动分配释放,存放函数的参数值、局部变量等
②不得返回局部变量的地址,栈区开辟的数据由编译器自动释放
③代码示例:

#include <iostream>
using namespace std;
int* func(){
    int a=2;
    return &a;
}
int main() {
    int *p=func();
    cout<<*p<<endl;
}

结果是无法输出
在这里插入图片描述
<2>堆区
①用于存放地址
②由程序员分配释放,若程序员不释放,由操作系统回收
③在C++中主要利用new在堆区开辟内存
④示例

#include <iostream>
using namespace std;
int* func(){
    int *a=new int(10);//指针本身是局部变量。放在栈上,指针保存的数据放在堆区
    return a;
}
int main() {
 int *p;
 p=func();
 cout<<*p<<endl;
}


在这里插入图片描述

二、引用
1、基本使用
<1>作用:给变量起别名
<2>语法:数据类型 &别名 = 原名
<3>示例:

#include <iostream>
using namespace std;
int main(){
    int a=10;
    int &b=a;
    b=20;
    cout<<a<<endl;
    cout<<b;
}

在这里插入图片描述

修改b的值的同时a的值也被修改,可见a和b用的是同一快内存。
<4>注意事项

  • 引用必须初始化
  • 引用在初始化后,不得改变。注意赋值并不是改变。
    三、函数的高级使用
    1、函数默认参数
    <1>介绍:在C++中,函数的形参列表中的形参是可以有默认值的。
    <2>语法:返回值类型 函数名 (参数 = 默认值){}
    <3>示例:
#include <iostream>
using namespace std;
int func(int a=10,int b=20){
    return a+b;
}
int main(){
    cout<<func()<<endl;
}

在这里插入图片描述
2、函数占位参数
<1>介绍:C++中函数形参列表里可以有占位参数,用来做占位,调用函数时必须填补该位置。
<2>语法:返回值类型 函数名 (数据类型)
<3>示例:

#include<iostream>
using namespace std;
int func(int a,int){
    
}
int main(){
    func(10,10);//必须填补该位置
}

3、函数重载
<1>作用:函数名可以相同,提高复用性。
<2> 应满足的条件:

  • 同一作用域
  • 函数名称相同
  • 函数参数类型不同或者个数不同或者顺序不同
    <3>示例:
#include<iostream>
using namespace std;
int func(int a,int b){
    return a+b;
}
void func(){}
int main(){
    func(10,10);
}

在以代码中有两个函数,他们的函数名都是func,但是参数不同,这就是函数重载。
<4>注意事项

#include<iostream>
using namespace std;
int func(int a,int b){
    return a+b;
}

void func(){
    cout<<"func()调用"<<endl;
}
//引用的函数重载
void fun(int &a){}
void fun(const int  &a){}      //const int 与 int 类型不同 可以进行函数重载
//函数默认参数的重载
void func2(int a,int b=10){}
void func2(int a){}            //这样重载是可以的,但是在调用的时候可能出现问题
int main(){
    func(10,10);
    func2(10);//这里报错,出现了二义性,程序不知道该调用哪个
}

三、类和对象
1、C++面向对象三大特性:封装、继承、多态。C++认为万事万物皆可为对象,对象上有其属性和行为。
2、封装
<1>封装的意义:

  • 将属性和行为作为一个整体,表现生活中的事物,例如计算圆的周长
#include<iostream>
using namespace std;
const double PI=3.14;
class Circle{
public:
   //属性
   int m_r;
   //行为
   double calculateZC(){
       return 2*PI*m_r;
   }
};
int main(){
   Circle c1;
   c1.m_r=10;
   cout<<c1.calculateZC();
}
  • 将属性和行为加以权限控制
#include<iostream>
#include<String>
using namespace std;
//公共权限 public 成员、类内、类外都可访问
//保护权限 protected 成员、类内可以访问 类外不可访问
//私有权限 private 成员 类内可以访问 类外不可访问
class Person{
public:
   string name;
protected:
   string m_Car;
private:
   string password;
   //类内均可访问
public:
   void init(){
       name="张三";
       m_Car="汽车";
       password="xxxxx";
   }
};
int main(){
   Person p1;
   p1.name="李四";//可以访问修改
   p1.m_car;//无法访问
   p1.password;//无法访问
}
  • 34
    点赞
  • 118
    收藏
    觉得还不错? 一键收藏
  • 12
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值