1 Star 1 Fork 0

菠萝吹雪/c++学习笔记

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
MIT

cpp

1. 介绍

c++学习记录


2. 指针

2.1 定义指针

定义一个指针变量p

int* p;
2.2 使用指针

定义一个变量 c ,把c的地址赋值给p指针,&是取地址符号

int c = 10;

//a的地址赋值给p指针
p = &c;

// *p解引用 即取出p内存地址对应的值
*p = 1000;
2.3 指针占用的内存

c++ 中规定在32位系统中指针占用4个字节的空间,在64位系统中占用8个字节的空间

cout << "指针p占用的空间大小为" << sizeof(p) << endl;

测试了下我的电脑是64位输出占用大小为8

2.4 空指针

定义: 指针变量指向内存中编号位0的空间,16进制表示为0x00

用途: 初始化指针变量

注意: 空指针指向的内存是不能访问的(0-255之间的内存编号是系统占用的不能访问)

初始化p为空指针

int* p = NULL;
2.5 野指针

指针指向了未申请的内存空间即为野指针,试图操作野指针编译可以通过但程序运行将会报错“读取访问权限冲突”

int* p = (int*)0x1100;
cout << *p << endl;
2.6 常量指针

特点:指针的指向可以修改但是指针指向的值不能修改

下面代码是可以运行的

int a1 = 4;
int a2 = 4;
int a3 = 3;
//常量指针
const int* p = &a1;
p = &a2;
p = &a3;

如果这样写则无法编译,因为修改了指针指向的值

*p = 10;
2.7 指针常量

特点: 指针的指向不可以改,指针指向的值可以改

int* const p;
2.8 数组和指针

示例:

// 定义一个数组
int arr[5] = { 1,2,4,5,7 };
//定义一个指针, arr赋值给p指针是吧首地址赋值给p指针
int* p = arr;
//使用指针访问数组
cout << *(p + 1);
//指针遍历数组
for (int i = 0; i < 5; i++)
{
	cout << *(p + i);
}
//使用p[0] 也可以访问数组第一个元素等价于*(p+1)

示例2:

//定义一个存int变量地址的指针
int* pArray;

//给pArray 赋值数组的首地址 
pArray = new int[100];

//打印的结果是一样的
cout << pArray << endl;
cout << &pArray[0]  << endl;

//*(pArray + 1) 等价于 pArray[1]
cout << *(pArray + 1) << endl;
cout << pArray[1] << endl;

3.结构体

3.1 结构体的定义和使用
struct Student
{
	int age;
	string name;
}s2;

Student s1;

//方式一
s1.age = 28;
s1.name = "张山";
cout << s1.age << s1.name << endl;

//方式二
s2.age = 34;
s2.name = "李四";
cout << s2.age << s2.name << endl;

//方式三
Student s3 = { 56,"王五" };
cout << s3.age << s3.name << endl;
3.2 结构体数组
struct Student
{
	int age;
	string name;
};

Student  sarr[10] =
{
	{19,"关羽"},
	{20,"张飞"},
};

sarr[1].name = "刘备";

for (int i = 0; i < 2; i++)
{
	cout << sarr[i].age << sarr[i].name << endl;
}
3.3 结构体指针
struct Student
{
	int age;
	string name;
};

Student s1 = { 16,"赵云" };

Student* p = &s1;
cout << p->name << p->age << endl;
3.4 结构体中值传递和地址传递

值传递修改形参后实参不会改变,引用传递修改形参后实参也会改变

struct Student
{
	int age;
	string name;
};

void  Print1(Student s) {
	s.age = 100;
	cout << s.age;
}

void  Print2(Student* p) {
	p->age = 200;
	cout << p->age;
}
3.5 结构体中使用const

使用 const修饰形参防止函数内部数据被修改

void  Print3(const Student* p) {
	p->age = 200;(报错)
	cout << p->age;
}

4.c++ 核心编程

4.1 内存分区模型

c++程序在执行时,将内存大方向划为四个区域

  • 代码区: 存放函数体的二进制代码,由操作系统进行管理的
  • 全局区: 存放全部变量和静态变量及常量
  • 栈区: 由编译器自动分配释放,存放函数的参数值,局部变量等
  • 堆区: 由程序员分配是释放,若程序员不释放,程序结束时由操作系统回收
4.1.1 代码区
4.1.2 全局区
4.1.3 栈区

局部变量,形参都存放在栈区,栈区的数据在函数执行完后自动释放

int* Print4() {
	int a = 10;
	return &a;
}

int* c = Print4();
cout << *c << endl;
cout << *c << endl;

上面函数返回了局部变量的地址这种做法不建议,在vs2022-x86环境下编译第二次打印 *c无法获取到10, 在x64中两次都可以获取10值

在vs2022 x64环境下,由于x64架构的特点,当函数返回后,局部变量所在的栈空间可能还没有被重用,因此指针c仍然指向之前temp所在的位置。这意味着即使temp已经不再有效,c指向的内存可能还没有被覆盖,因此第一次cout << *c << endl;仍然能够打印出10。对于第二次打印,如果在这之间没有其他代码执行导致栈空间被重用,那么*c可能仍然保持原来的值,因此第二次打印也输出10。

在x86架构下,由于栈空间的管理方式不同,局部变量temp所在的空间可能很快就被重用了。这意味着在Print4()函数返回后,c指向的内存区域可能会被新的数据覆盖,因此第二次尝试访问*c时,你可能得到一个不确定的结果,甚至会导致程序崩溃


4.1.4 堆区

由程序员分配释放,若程序员不释放,程序结束时由操作系统的回收

在c++中主要利用new开辟内存

int* func() {
	//利用new关键字
	//指针的本质是局部变量 ,放在栈上,指针保存的数据放在堆区
	int* p = new int(10);
	return p;
};
int* p = func();
cout << p << endl;

//打印结果:0096F148
int *p p = 0096F148 内存地址 0096F148 值 10

栈上的指针变量保存的是值所在堆的内存地址,值保存在堆上,解引用实际是拿指针对应的内存地址区找堆上的内存地址获取其值

4.1.5 new 操作符

c++ 使用new操作符在堆区开辟内存

堆区开辟的数据由程序员手动开辟,手动释放,释放利用操作符delete

语法:new 数据类型

用new创建的数据会返回对应类型的指针

int* func01() {
	return new int(10);
};

int* p = func01();

cout << *p << endl;
cout << *p << endl;
delete p;
cout << *p << endl;//调用报错内存已被释放

new 数组

int* arr = new int[10];

//释放数组
delete[]  arr;
4.2 引用
4.2.1 引用的基本使用
int q = 100;
//取别名
int& e = q;

cout << q << endl;

cout << e << endl;

e = 40;

cout << q << endl;

cout << e << endl;

输出  100 100 40 40
4.2.2 引用注意事项
  • 引用必须初始化
  • 引用初始化之后就不能改变了
	int q = 100;
	//取别名
	int& e = q;
	//注意事项
	int r = 200;
	e = r;// 赋值操作没有修改引用
	cout << q << endl;
	cout << e << endl;
4.2.3 引用做函数参数
void  func02(int a, int b) {
	int temp;
	temp = a;
	a = b;
	b = temp;
}

void  func03(int* a, int* b) {
	int temp;
	temp = *a;
	*a = *b;
	*b = temp;
}

void  func04(int& a, int& b) {
	int temp;
	temp = a;
	a = b;
	b = temp;
}


int q = 10;
int w = 30;


//值传递
func02(q, w);
cout << q << endl;
cout << w << endl;
//指针传递
func03(&q, &w);
cout << q << endl;
cout << w << endl;
//引用传递
func04(q, w);
cout << q << endl;
cout << w << endl;

输出:
10
30
30
10
10
30
4.2.4 引用做函数的返回值
  1. 不能返回局部变量的引用
//错误的不能返回局部变量的引用
int& func06() {
	int a = 10;
	return a;
}

int& ref = func06();

cout << ref << endl;
cout << ref << endl;

输出:
10
2082318576
  1. 函数做为左值必须返回引用
func06() = 1000;
4.2.5 引用的本质

引用的本质是一个指针常量

指针常量: 指针的指向不可以改,指针指向的值可以改

int a = 10;
//自动转换int* const ref = &a
int& ref = a;
//内部发现ref是引用,自动帮我们转换为:*ref= 20;
ref = 20;
4.2.6 常量引用

主要用来修饰形参,防止误操作

4.3 函数
4.3.1 函数的默认参数

声明和实现只能一个有默认参数

4.3.2 函数占位参数
void func(int a,int)
{
}
4.3.3 函数重载
4.5 运算符重载

运算符重载概念:对已有的运算符重新定义,赋予其另一种功能,以适应不同的数据类型

4.5.1 可重载运算符

双目算数运算符: + ,-,*,/,%(取模)

逻辑运算符:||,&&,!

单目运算符:+,-,&(取地址)

关系运算符:==,!=,<,>,<=,>=

自增自减运算符:++,--

位运算符:|(按位或),&(按位与),~(按位取反),^(按位异或),<<(左移),>>(右移)

赋值运算符:

空间申请与释放:new ,delete,new[ ],delete[ ]

其他运算符:

4.5.2 不可重载运算符

成员访问运算符:.

成员指针访问运算符: .,->

域运算符:::

长度运算符: sizeof

条件运算符:?:

预处理运算符:#

4.5.3 加法运算符重载
  1. 成员函数实现运算符重载
class Person {
public:
	Person operator+(Person& p)
	{
		Person temp;
		temp.a = this->a + p.a;
		temp.b = this->b + p.b;

		return temp;
	}

	int a;
	int b;
};

//调用
Person p1;
p1.a = 10;
p1.b = 20;
Person p2;
p2.a = 40;
p2.b = 50;
Person p3 = p1 + p2;

cout << p3.a << p3.b << endl;
  1. 全局函数重载加法运算符
Person operator+(Person& p1,Person& p2)
{
		Person temp;
		temp.a = p1.a + p2.a;
		temp.b = p1.b + p2.b;

		return temp;
}
4.5.4 左移运算符重载
//全局函数重载		
ostream& operator<<(ostream& cout, Person& p) {
	cout << p.a << p.b;
	return cout;
}

//实现直接打印对象
Person p;
p.a = 10;
p.b = 12;
cout << p << endl;
4.6 类和对象
4.6.1 成员变量和成员函数分开存储

成员变量和成员函数分开存储,成员函数和静态变量一样都类的对象上

4.6.2 this指针概念

this指针指向被调用的成员函数所属的对象,存在每个成员函数内部不用被声明

用途:

  1. 解决名称冲突
  2. 返回对象本身
//可以返回引用 MyClass& 也可以返回对象值 MyClass,如果返回对象值则每次创建一个新对象age不会累加
MyClass& MyClass::PersionAddAge(MyClass &p) {
	this->age = this->age + p.age;
    //this是一个指针 *this是this对应的值即对象myclass
	return *this;
}

MyClass myclass;
myclass.age = 10;
myclass.PersionAddAge(myclass).PersionAddAge(myclass);
cout << myclass.age << endl;
4.6.3 空指针调用成员函数

空指针调用成员函数会报错

class Test{
    public:
    void Test1(){
        cout << this-> age << endl;
    }
    int age;
}

Test* test = null;
test->Test1();//报错因为this为null;

4.6.4 const 修饰成员函数

常函数

  • 成员函数后加const我们称这个函数为常函数
  • 常函数内不可以修改成员属性
  • 成员属性申明时关键字mutable之后,在常函数中依然可以修改

常对象

  • 申明对象前加const称为该对象为常对象
  • 常对象只能调用常函数

常函数怎么声明

class Test{
    public:
    //声明常函数
    //this指针的本质是指针常量 指针的指向不可以修改
    //在成员函数后面加const,修饰的是this的指向,让指针指向的值也不能修改
    //const Test* const this;
    void Test1() const{
      age = 10;//报错
    }
    int age;//加上mutable就可以修改了  mutable int age
}

test->Test1();
4.6.5 友元

在程序里,有些私有的属性也想让类外特殊的一些函数或者类访问,就需要用到友元

关键字friend

友元的三种实现

  • 全局函数做友元
  • 类做友元
  • 成员函数做友元
  1. 全部函数做友元

    class Building
    {
        //告诉编译器 全局函数FriendFunc 是building的好友可以访问私有变量
    	friend void  FriendFunc();
    public:
    	Building() {
    		settingRoom = "客厅";
    		bedRoom = "卧室";
    	}
    
    private:
    	string bedRoom;
    public:
    	string settingRoom;
    
    };
    
    //全局函数
    void FriendFunc() {
    	Building build;
    	cout << build.settingRoom << endl;
    	cout << build.bedRoom << endl;
    }
    
    //调用
    FriendFunc();
    
  2. 类做友元

    class Building
    {
    	friend class FriendClass;
    	friend void  FriendFunc();
    public:
    	Building() {
    		settingRoom = "客厅";
    		bedRoom = "卧室";
    	}
    
    private:
    	string bedRoom;
    public:
    	string settingRoom;
    
    };
    
    class FriendClass {
    public:
    	void Visit(Building* build) {
    		cout << build->settingRoom << endl;
    		cout << build->bedRoom << endl;
    	}
    
    };
    
    Building* build = new Building();
    FriendClass firendClass;
    firendClass.Visit(build);
    
  3. 成员函数做友元

//让成员函数visit2也可以访问
friend void FriendClass::visit2();
MIT License Copyright (c) 2024 damibing Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

简介

c++学习笔记 🏷 展开 收起
README
MIT
取消

发行版

暂无发行版

贡献者

全部

语言

近期动态

不能加载更多了
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C++
1
https://gitee.com/toxiaoshitou/cpp.git
git@gitee.com:toxiaoshitou/cpp.git
toxiaoshitou
cpp
c++学习笔记
master

搜索帮助