首页 > 编程语言 >C++语言常见知识点

C++语言常见知识点

时间:2023-08-15 15:55:43浏览次数:27  
标签:知识点 arr const 函数 int 常见 cout C++ 指针

C++基础

变量存在的意义是什么?

作用:给一段指定的内存空间起名,方便我们管理操作这块内存。

int a=10;

常量的两种定义方式

1、#define PI 3.14 2、const int a=10;

用于记录程序中不可更改的数据。

标识符的命名规则

1、不能是关键字

2、只能由字母、下划线、数字构成

3、不能数字开头

4、区分大小写

为什么要有数据类型?

C++规定在一个变量或者常量时,必须要指出相应的数据类型,否则无法给变量分配内存。

存在的意义:给变量分配合适的内存空间,不要造成浪费。

sizeof关键字有什么用?

利用sizeof关键字可以统计数据类型所占用内存大小(字节大小)。

sizeof( 数据类型/变量 )

科学计数法表示

float f=3e2;// 3* (10^2)

float f2=3e-2;// 3* (0.1^2)

C++中的字符变量

char a='a';

  • C/C++中字符型变量只占用1个字节。
  • 字符型变量并不是把字符本身放到内存中存储,而是将对应的ASCII码放入到存储单元。
    • cout<<(int)a<<endl; a=>97;A=>65

转义字符:用于表示一些不能显示出来的ASCII字符。 \n \\ \t

C++生成随机数

int num = rand() % 100; // 0~99

goto语句

不推荐用,知道就好。

cout << "a" << endl;
cout << "b" << endl;

goto FLAG;
cout << "c" << endl;

FLAG:
cout << "d" << endl;

/*
    a
    b
    d
*/

数组

所谓数组,就是一个集合,里面存放了相同类型的数据元素。

特点:1、每个数据元素都是相同的数据类型2、数组由连续的内存地址组成

一维数组名的用途

int arr[5]={1,2,3,4,5};

1、可以统计整个数组在内存中的长度

sizeof(arr)、sizeof(arr[0])

2、获取数组在内存中的首地址。

cout<<arr<<endl;

cout<<&arr[0]<<endl; // 获取数组中第一个元素地址。与数组首地址一样

二维数组名的用途

int arr[2] [3]={{1,2,3},{4,5,6}};

1、可以统计整个数组在内存中的长度

sizeof(arr)、sizeof(arr[0]) 第一行所占用的内存空间大小、sizeof(arr[0] [0]) 第一个元素所占内存空间大小

sizeof(arr)/sizeof(arr[0]) 获取行数、sizeof(arr[0])/sizeof(arr[0] [0]) 获取列数

2、获取数组在内存中的首地址。

cout<<arr<<endl;

cout<<arr[0]<<endl; 获取第一行数据首地址

cout<<arr[1]<<endl;

函数有什么用?

作用:将一段经常使用的代码封装起来,减少重复代码。

一个较大的程序,一般分为若干个程序块,每个模块实现特定的功能。

什么是函数值传递?

所谓值传递,就是函数调用时实参将数传入给形参。

值传递时,如果形参发生改变,并不影响实参。

void swap(int a, int b)
{
	cout << "2:a= " << a << endl;
	cout << "2:b= " << b << endl;

	int temp = a;
	a = b;
	b = temp;

	cout << "2:a= " << a << endl;
	cout << "2:b= " << b << endl;
}

int main()
{
	int a = 10;
	int b = 20;

	cout << "1:a= " << a << endl;
	cout << "1:b= " << b << endl;

	swap(a, b);

	cout << "1:a= " << a << endl;
	cout << "1:b= " << b << endl;

	system("pause");

	return 0;
}

/*
1:a= 10
1:b= 20
2:a= 10
2:b= 20
2:a= 20
2:b= 10
1:a= 10
1:b= 20
*/

指针有什么用?

作用:可以通过指针间接访问内存。

  • 内存编号是从0开始记录的,一般用十六进制数字表示
  • 可以利用指针变量来保存地址
int a = 10;
int* p = &a;// 让指针p记录a的地址

cout << "a= " << a << endl;
cout << "*p= " << *p << endl;// 解引用

cout << "&a= " << &a << endl;// &取地址
cout << "p= " << p << endl;

/*
a= 10
*p= 10
&a= 000000A2FEEFF5C4
p= 000000A2FEEFF5C4
*/

指针这种数据类型所占用的内存空间有多大呢?

sizeof(int *)

​ 32位操作系统,占用4个字节

​ 64位操作系统,占用8个字节

什么是空指针?有什么用?什么是野指针?

空指针:指针变量指向内存中编号为0的空间。

​ 用途:初始化指针变量 int * p=NULL;

​ 注意:空指针指向的内存不可以访问(0~255之间的内存编号是系统占用的,因此不可访问)

野指针:指针变量指向非法的内存空间。程序中,避免出现野指针。

const修饰指针有哪些情况?有什么区别?

1、const修饰指针 --- 常量指针

const int * p=&a; 指针指向可以修改,但指针指向的值不可以改。*p=20(X)p=&b(V)

2、const修饰常量 --- 指针常量

int * const p=&a; 指针指向不可以修改,但指针指向的值可以改。*p=20(V)p=&b(X)

【记法:const 和 * 谁在前,对应的就不能变。例如const在前,常量值就不能变;*在前,指针的指向不能变】

3、const既修饰指针又修饰常量

const int * const p=&a; 指针指向不可以修改,但指针指向的值不可以改。*p=20(X)p=&b(X)

int m = 10;
int n = 10;

const int* pt1 = &m;// 常量指针
pt1 = &n;
//*pt1 = 20;// 报错

int* const pt2 = &m;// 指针常量
//pt2 = &n;// 报错
*pt2 = 20;

const int* const pt3 = &m;// const既修饰指针又修饰常量
//pt3 = &n;// 报错
//*pt3 = 20;// 报错

如何利用指针访问数组中的元素?

int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
cout << arr[0] << endl;

int* ptr = arr;// arr就是arr数组的首地址
cout << ptr << endl;
ptr++;// ptr向后偏移4个字节
cout << ptr << endl;

int* ptr2 = arr;
for (int i = 0; i < 10; i++)
{
	cout << *ptr2 << " ";
	ptr2++;
}

指针作为函数参数会发生什么情况?

可以修改实参的值。

// 值传递
void swap(int a, int b)
{
	int temp = b;
	b = a;
	a = temp;

	cout << "内部a= " << a << endl;
	cout << "内部b= " << b << endl;
}

// 引用传递
void swap2(int* a, int* b)
{
	int temp = *b;
	*b = *a;
	*a = temp;

	cout << "内部a= " << *a << endl;
	cout << "内部b= " << *b << endl;
}

int a = 10;
int b = 20;

//swap(a, b); 10	20
swap2(&a, &b);20	10

cout << "a= " << a << endl;
cout << "b= " << b << endl;

示例:指针结合数组和函数

// 数组的冒泡排序
void bubbleSort(int* arr, int len)
{
	for (int i = 0; i < len - 1; i++)
	{
		for (int j = 0; j < len - i - 1; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int temp = arr[j + 1];
				arr[j + 1] = arr[j];
				arr[j] = temp;
			}
		}
	}
}

// 打印数组
void printArray(int* arr, int len) 
{
	for (int i = 0; i < len; i++)
	{
		cout << arr[i] << " ";
	}
}

int main()
{
	int arr[] = { 3,1,7,4,6,9,10,2,5,8 };
	int len = sizeof(arr) / sizeof(arr[0]);// 数组长度

	cout << "排序前:";
	printArray(arr, len);// 打印数组
	cout << endl;

	bubbleSort(arr, len);// 给数组排序

	cout << "排序后:";
	printArray(arr, len);// 打印数组
	cout << endl;

	system("pause");
	return 0;
}

什么是结构体?

结构体属于用户自定义的数据类型,允许用户存储不同的数据类型。

struct Student
{
	string name;
    int age;
    float score;
};

struct Teacher
{
    int id;
    string name;
    int age;
    struct Student stu;// 结构体嵌套
};

// 结构体作值传递
void PrintStudent(struct Student s)
{
	s.age = 100;
	cout << s.name << " " << s.age << " " << s.score << endl;
}

// 结构体作引用传递:可以减少空间,不会复制新的副本出来
void PrintStudent2(struct Student* s)
{
	s->age = 200;
	cout << s->name << " " << s->age << " " << s->score << endl;
}

// 结构体作引用传递:可以减少空间,不会复制新的副本出来。
// 防止误操作,加const,只能读不能写
void PrintStudent2(const struct Student* s)
{
	cout << s->name << " " << s->age << " " << s->score << endl;
}

int main()
{
    struct Student s1;
    s1.name="张三";
    s1.age=21;
    s1.score=100;
    Student s2={"李四",20,80};
    
    cout<<s1.name<<" "<<s1.age<<" "<<s1.score<<endl;
    cout<<s2.name<<" "<<s2.age<<" "<<s2.score<<endl;

    // 结构体数组
    Student stus[2] = { s1,s2 };
    stus[0].name="张飞";
    
    // 结构体指针
    Student * p=&s1;
   	cout<< p->name << " " << p->age << " " << p->score;
    
    // 嵌套结构体
    Teacher t;
    t.id=1;
    t.name="老王";
    t.age=40;
    t.stu=s1;
    
    // 结构体作函数参数
    cout << "------------------" << endl;
    PrintStudent(s2);
    cout << s2.name << " " << s2.age << " " << s2.score << endl;
    PrintStudent2(&s2);
    cout << s2.name << " " << s2.age << " " << s2.score << endl;

  
	system("pause");
	return 0;
}

C++核心

C++的内存分区有哪些?为什么要分区?

程序运行前:

1、代码区(存放函数体的二进制代码【共享、只读】,由操作系统进行管理)

2、全局区(存放全局变量和静态变量以及常量【字符串常量和const修饰的全局常量】,程序结束时由操作系统释放)

程序运行后:

3、栈区(由编译器自动分配释放,存放函数的参数值,局部变量等)

4、堆区(由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收。主要利用new在堆区开辟内存;delete释放)

int * p = new int(10);//*p 存放在栈区,new int(10)存放在堆区
cout<< *P <<endl;//10
delete p;

// new、delete开辟数组
int * arr= new int[10];
for(int i=0;i<10;i++)
{
	arr[i]=i+100;	
}
for(int i=0;i<10;i++)
{
	cout<<arr[i]<<endl;//100~109	
}
delete []arr;

分区存在的意义:不同区域存放的数据,赋予不同的生命周期,给我们更大的灵活编程。

C++中的引用有什么用?

给变量起别名。 数据类型 & 别名 = 原名

注意:1、引用必须初始化 2、一旦初始化之后,就不可以更改了。

使用引用作函数参数的优点是什么?

函数传参时,可以利用引用的技术让形参修饰实参。可以简化指针修改实参。

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

int main()
{
	int m = 10;
	int n = 20;
	cout << m << endl;//10
	cout << n << endl;//20
	swap(m, n);
	cout << m << endl;//20
	cout << n << endl;//10

	system("pause");
	return 0;
}

引用的本质是什么?

引用的本质在c++内部实现是一个指针常量(指针的指向不能改变,值可以改变)。

为什么会有常量引用?

常量引用主要用来修饰形参,防止误操作。 const int& a=10; //(X)a=20;

面向对象的三大特性是什么?什么是类?

封装、继承、多态。

具有相同性质的对象,我们可以抽象为类。

封装有什么意义?

1、将属性和行为作为一个整体,变现生活中的事物。

2、将属性和行为加以权限控制。A. public公共权限 B. protected 保护权限(子可以访问父) C. private 私有权限

结构体和类的区别是什么?

c++中,struct和class唯一的区别就在于 默认的访问权限不同。struct 公共;class private

成员属性设置成私有的好处是什么?

1、可以控制自己读写权限( get,set方法) 2、对于 写,可以检测数据的有效性 (set方法内条件判断)

构造函数和析构函数的作用是什么?

构造函数:对象的初始化,无需手动调用,只会调用一次

析构函数:在对象销毁前系统自动调用,执行一些清理工作,只会调用一次【在堆区开辟的数据释放掉】

构造函数的调用规则

  • 如果用户定义有参构造函数,c++不在提供默认无参构造,但是会提供默认拷贝构造

  • 如果用户定义拷贝构造函数,c++不会再提供其他构造函数

深拷贝和浅拷贝是什么?有什么区别?

浅拷贝:简单的赋值拷贝操作

深拷贝:在堆区重新申请空间,进行拷贝操作

区别:

浅拷贝的问题:

image-20230813165438491

深拷贝解决:

image-20230813165616816

image-20230813165821603

B类中有对象A作为成员,A为对象成员。那么创建B对象时,A与B的构造和析构的顺序是谁先谁后?

A的构造——>B的构造——>B的析构——>A的析构

C++静态成员的注意事项

包括:

静态成员变量:1、所有对象共享同一份数据 2、在编译阶段分配内存(全局区)

3、类内声明,类外初始化 (注意访问权限)int Person::m_A=100; 访问:p.m_A; p1.m_A; Person::m_A;

静态成员函数:(注意访问权限)1、所有对象共享同一个函数 2、静态成员函数只能访问静态成员变量

static void func(){} 访问:p.func(); Person::func();

C++的成员变量和成员函数分开存储。

只有非静态成员变量属于类对象上。sizeof(p)

​ 如果类什么都没有,空对象占1个字节;有非静态成员变量,按照对应变量的大小算

每一个非静态成员函数只会诞生一份函数实例,也就是说多个同类型的对象会共用同一份代码。

this指针有什么用?

this指针指向被调用的成员函数所属的对象。本质是指针常量

  • 形参和变量成员同名时,可用this指针来区分
  • 在类的非static成员函数中返回对象本身,可使用return *this;

const修饰成员函数的用途是什么?

常函数:1、常函数内不能修改成员属性 2、成员属性声明时加关键字mutable后,在常函数中依然可以修改。

void showPerson() const { }

常对象:常对象只能调用常函数

友元的目的是什么?

让一个函数或者类 能够访问另一个类中的私有成员。friend

什么是运算符重载?

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

image-20230814105136331

使用继承有什么好处?

减少重复代码 class Java: public BasePage { }

继承方式:1、公共继承 2、保护继承 3、私有继承

image-20230814123623537

父类中所有非静态成员属性都会被子类继承下去。sizeof(son) 包括父类的私有非静态属性

继承中父类和子类的构造和析构顺序谁先谁后?

Base构造——>Son构造——>Son析构——>Base析构

当子类和父类出现同名的成员,如何通过子类对象,访问到子类或父类中同名的数据呢?

  • 访问子类同名成员,直接访问即可。 s.m_A; s.Func();

  • 访问父类同名成员,需要加作用域。 s.Base::m_A; s.Base::Func();

静态成员同名情况下的处理方式一致。

菱形继承问题

image-20230814130141981

使用 虚继承 解决菱形继承的问题。

image-20230814131048843

image-20230814130814708

image-20230814130954053

哪些属于多态?

1、静态多态:函数重载 和 运算符重载属于静态多态,复用函数名。 编译阶段确定函数地址

2、动态多态:派生类和虚函数实现运行时多态。 运行阶段确定函数地址

#include <iostream>
using namespace std;

class Base
{
public:
	virtual void speak()
	{
		cout << "Base" << endl;
	}

};

class Son1 :public Base
{
public:
    //重写Base方法
	void speak()
	{
		cout << "Son1" << endl;
	}

};

class Son2 :public Base
{
public:
    //重写Base方法
	void speak()
	{
		cout << "Son2" << endl;
	}

};

void Speak(Base& base)//Base& base=son1
{
	base.speak();
}

int main()
{
	Son1 son1;
	Speak(son1);//Son1
	Son2 son2;
	Speak(son2);//Son2

	system("pause");
	return 0;
}

image-20230814133605578

多态的优点有哪些?

1、代码组织结构清晰 2、可读性强 3、利于前期和后期的扩展和维护

纯虚函数的由来?什么是抽象类,有什么特点?

在多态中,通常父类中的虚函数的实现是毫无意义的,主要都是调用子类重写的内容。

可将虚函数改成 纯虚函数。【virtual 返回值类型 speak() = 0;】

当类中有了纯虚函数,这个类也称为抽象类

  • 无法实例化对象
  • 子类必须重写抽象类中的纯虚函数,否则也属于抽象类。

虚析构和纯虚析构的用处?

多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码。

——使用虚析构或者纯虚析构

virtual ~Base() { } | virtual ~Base() = 0;Base::~Base() { }

共性:1、可以解决父类指针释放子类对象 2、都需要具体的函数实现

区别:如果是纯虚析构,该类属于抽象类,无法实例化对象。

文件操作

头文件:

ofstream:写操作 ifstream:读操作 fstream:读写操作

image-20230814143737047

标签:知识点,arr,const,函数,int,常见,cout,C++,指针
From: https://www.cnblogs.com/swbna/p/17631491.html

相关文章

  • JavaScript 如何封装一些常见的函数来提高工作效率
    前言为什么要封装函数JavaScript封装函数的主要目的是为了保护代码的安全性和可维护性。封装可以隐藏实现细节:将函数内部的实现细节封装起来,只暴露给外部必要的接口,可以使代码更加安全,防止意外修改或者滥用。封装可以提高代码的可维护性:将功能模块封装成函数,可以使代码更加模......
  • C++黑马程序员——P228. pair对组
    P228.pair使用——pair对组的创建功能描述:  成对出现的数据,利用对组可以返回两个数据两种创建方式:pair<type,type>p(value1,value2);pair<type,type>p=make_pair(value1,value2);#include<iostream>#include<string>usingnamespacestd;//pair对组创建v......
  • nginx 常见参数以及重定向参数配置(摘抄)
    1、参考nginx常见参数以及重定向参数配置2、nginx各参数翻译,作用$arg_PARAMETER#这个变量包含GET请求中,如果有变量PARAMETER时的值。$args#这个变量等于请求行中(GET请求)的参数,例如foo=123&bar=blahblah;$binary_remote_addr#二进制的客户地址。$body_bytes_sent......
  • c++初始化方式
    对类型进行初始化时,语法是相当的多,为什么要这么多初始化方法呢?主要是以前各种类型的初始化方式不同,现在演变成如此多的方式就是为了使初始化常规变量的方式与初始化类变量的方式更像。大括号初始化器是后来扩展出的用于任何类型,所以尽量使用大括号初始化语法。1、基本类型初始化......
  • 【C++STL基础入门】string类的基础使用
    @TOC前言本系列文章使用VS2022,C++20版本STL(StandardTemplateLibrary)是C++的一个强大工具集,其中的string类是STL中一个常用的容器。本文将介绍string类的基本使用方法。一、STL使用概述在STL中,我们的每一个容器/string字符串等都是使用面向对象技术来实现的,我们只需要调用里面的函......
  • C++ 调用 Python 接口 Mat转Numpy
    参考网站:https://blog.csdn.net/qq7835144/article/details/106073110?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-1&spm=1001.2101.3001.4242https://blog.csdn.net/weixin_46400740/article/details/116711323?spm=1001.2014.3001.5501 1、配......
  • C/C++基础知识点——设计原则及设计模式
    如何实现模块间高内聚、低耦合?封装与抽象;添加中间层;模块化;设计思想与原则单一职责;接口隔离原则;依赖倒置;迪米特原则;多用组合少用继承;设计模式:观察者模式设计原则及设计模式六大设计原则:单一职责原则;里氏替换原则;开闭原则;依赖倒置原则;接口隔离原则;最少知识原则。......
  • 7.1 C/C++ 实现动态数组
    动态数组相比于静态数组具有更大的灵活性,因为其大小可以在运行时根据程序的需要动态地进行分配和调整,而不需要在编译时就确定数组的大小。这使得动态数组非常适合于需要动态添加或删除元素的情况,因为它们可以在不浪费空间的情况下根据需要动态增加或减少存储空间。动态数组的内存......
  • 7.2 C/C++ 实现动态链表
    动态链表是一种常用的动态数据结构,可以在运行时动态地申请内存空间来存储数据,相比于静态数组和静态链表,更加灵活和高效。在动态链表中,数据元素被组织成一条链表,每个元素包含了指向下一个元素的指针,这样就可以通过指针将所有元素串联起来。使用动态链表存储数据时,不需要预先申请内......
  • 7.3 C/C++ 实现顺序栈
    顺序栈是一种基于数组实现的栈结构,它的数据元素存储在一段连续的内存空间中。在顺序栈中,栈顶元素的下标是固定的,而栈底元素的下标则随着入栈和出栈操作的进行而变化。通常,我们把栈底位置设置在数组空间的起始处,这样在进行入栈和出栈操作时,只需要维护栈顶指针即可。顺序栈的实现比......