结构体区别
-
类型上不再需要struct关键字,直接用结构体名即可
-
C++结构体中允许函数存在
-
在结构体中声明,在结构体外实现,当然可以直接在结构体中实现
-
结构体中函数访问数据,是可以直接访问
-
学会调用,和数据成员方式时一样的
-
对象(结构体变量).成员
-
对象指针->成员
-
(*对象指针).成员(装杯用法)
-
-
C++在没有写构造函数和权限限定的时候,用法和C语言的用法是一样
struct MM { //属性,特征 //数据成员 char name[20]; int age; //..... //行为(方法) //成员函数 void print() //这里的print与printData函数效果一样,但是printData函数在结构体外部实现 { cout << name << "\t" << age << endl; } void printData(); //在结构体中声明,在外面实现 //通过外部函数修改数据 int& getAge() { return age; } }; //结构体名限定,就是告诉别人这个函数来自哪里 void MM::printData() { cout << name << "\t" << age << endl; } //结构体中的变量必须要通过结构体变量(结构体指针)访问 //C++结构体中的函数访问属性,可以直接访问
-
动态内存申请
-
C语言的动态内存申请
-
malloc 不带初始化 ,calloc 带初始化,realloc 重新申请
-
free 释放
-
-
C++的动态申请
-
new(申请)和delete(释放)
-
单个变量内存申请
-
数组的动态申请
-
-
-
结构体内存申请
//单个变量申请动态内存 void testOneMemory() { //申请不做初始化 int* pInt = new int; *pInt = 123; cout << *pInt << endl; //输出123 char* pChar = new char; *pChar = 'A'; cout << *pChar << endl; //输出A //申请内存做初始化 ()给单个数据初始化 int* pNum = new int(134); cout << *pNum << endl; //输出134 delete pInt; //释放申请的动态内存(但指针依然存在,即可再次申请动态内存) pInt = nullptr; //释放后的指针建议初始化为空指针 pInt = new int; //还可以再次申请动态内存 *pInt = 332; cout << *pInt << endl; //输出332 delete pInt; pInt = nullptr; delete pChar; pChar = nullptr; delete pNum; pNum = nullptr; }
数组申请动态内存 void testArrayMemory() { //一维数组 //1.不带初始化 //长度可以是变量,只要值就可以 int* pInt = new int[3]; //等效产生了int pInt[3]的数组 //字符串申请动态内存不用以下的赋值方式,因为此赋值只是把指针指向改变成指向常量 //而不是将new char[15]进行初始化,此时动态内存依然是空 //const char* pstr = new char[15]; //你 --->大老婆 //const char* pstr1 = pstr; //朋友--->大老婆 //pstr = "ILoveyou"; //你-->二老婆 char* pstr = new char[15]; strcpy_s(pstr, 15, "ILoveyou"); //可用strcpy函数来赋值,需加入<cstring>头文件 cout << pstr << endl; //带初始化的 一堆数据用 {} int* pNum = new int[3]{ 1,2,3 }; for (int i = 0; i < 3; i++) { cout << pNum[i] << " "; //输出1 2 3 } cout << endl; delete[] pNum; //delete p可释放一个内存,delete []p可释放一段内存(用于数组的释放) char* str = new char[20]{ 'A','B','\0' };//可进行单个字符的赋值 cout << str << endl; //输出AB delete[] str; str = nullptr; str = new char[20]{ "ILoveyou" }; cout << str << endl; delete[] str; str = nullptr; delete [] pInt; //数组的释放 不需要大小 //释放只有两种形式 delete 指针 delete [] 指针 //delete [][] p 没有这种写法!! pInt = nullptr; }
- 结构体申请动态内存在链表和树等等操作中还会更加丰富
//结构体申请动态内存 struct MM { char* name; int age; //成员函数 void printMM() { cout << name << "\t" << age << endl; } }; void testStructMemory() { //new一个对象 int* p = new int(23); //结构体只能用大括号 MM* pMM = new MM; //结构体中指针,要做二次申请,才能strcpy,或者赋值 pMM->name = new char[20]; strcpy_s(pMM->name,20, "丽丝"); pMM->age = 18; pMM->printMM(); //输出 丽丝 18 //申请顺序和释放顺序是相反(若弄反会导致程序运行故障) delete[] pMM->name; delete pMM; }
内存池
-
允许大家申请一段内存,共给程序使用,综合管理内存
-
可以简单理解成你买了一块大蛋糕,然后一口气吃不完,一部分一部分的吃
//允许大家申请一段内存,共给程序使用,综合管理内存
//malloc 内存是在堆区
//new 内存是自由存储区
void testMemory()
{
char* memorySum = new char[1024]; //这里申请了1024字节的内存等待使用
//.......事情的处理,需要内存,所有内存源自于memorySum
//int* pNum = new(申请内存的开始位置) int[3]
int* pNum = new(memorySum) int[3]{ 1,2,3 }; //这里申请了12个字节存储了3个int整型
//char* pstr = new(pNum + 3) char[20]{ "ILoveyou" };
//和下面这句话是等效的,因为一个int占用四个字节,一个char占用一个字节
char* pstr = new(memorySum + 12) char[20]{ "ILoveyou" };
for (int i = 0; i < 3; i++)
{
cout << pNum[i] << " "; //输出1 2 3
}
cout << endl;
for (int i = 0; i < 3; i++)
{
cout << ((int *)memorySum)[i] << " "; //将char类型强制转换为int型 输出1 2 3
}
cout << endl << pstr << endl; //输出ILoveyou
cout << (memorySum + 12) << endl; //输出ILoveyou
//内存池的好处在于只申请了一段内存,就可以多次使用,并且释放内存也只用一次
delete[] memorySum;
memorySum = nullptr;
}
string类型
只需要知道有这种用法即可,不需要深究为什么,因为string本身是一个类,需要知道类的大部分知识,才能追究为什么这样做。自己也可以封装一个string 类型
需要带上头文件<string> 不要写成<string.h>
-
string创建
-
带初始化
-
不带初始化
-
通过另一个字符串创建
-
-
string基本操作
-
拷贝
-
赋值
-
连接
-
比较
-
-
C++string与C语言string.h
-
string 其他函数操作
//所需的头文件
#include <string> //注意和string.h区别
#include <iostream>
#include <cstring> //string.h和cstring是一样
#include <stdio.h>
using namespace std; //使用string类型时需要std
void createString()
{
//std::string str; //不加using namespace std;就需要std::
string str1;
str1 = "ILoveyou";
cout << str1 << endl;
const string cstr;
//cstr = "IMissyou"; //错误,常属性不能修改,所以一般用string不会加const
//string初始化可以用小括号也可以直接用=
string str2("ILoveyou");
cout << str2 << endl;
string str3 = "IMissyou"; //喜欢这种方式
cout << str3 << endl;
string str4(str3);
cout << str4 << endl;
string str5 = str4; //string可以直接使用=来进行赋值
cout << str5 << endl;
//一般没有长度限定,在你使用范围下,如果你头铁给一亿个数据当我没说
string str = "2333333333333333333333333333333333333333333333333333333333333";
}
void operatorString()
{
string str1 = "one";
string str2 = "two";
string str3 = str2;
cout << str3 << endl;
//没有减法!!
string str4 = str1 + str2; //两个字符串的拼接
//等效: string str4=str1.append(str2);
//C++中尽量用string 不要用char* (可以用)
//比较直接比较即可
//> < != ==
//等效于str1.compare(str2) 0 -1 1
if (str1 > str2) //比较依旧按照char* 的strcmp函数去比较
{
cout <<"大的 "<< str1 << endl;
}
else
{
cout << "大的 " << str2 << endl;
}
}
void compareCAndCpp()
{
//C++中是一个自定义类型(类),目前当作结构体即可
//C++string 不能用到C语言的字符串处理函数 !!
//C++如何转换为C语言的char* ,可用c_str() data()函数
string str1 = "ILoveyou";
//printf("%s", str1); //错误
printf("%s\n", str1.c_str());
printf("%s\n", str1.data());
//直接把数字转换为相应的字符串
string str2 = to_string(1234);
cout << str2 << endl;
}
void exOperator()
{
//采用下标法打印string
string str = "IMissyou";
//C++string中没有记录\0 !!
for (int i = 0; i < 8; i++) //循环次数一定要搞清楚
{
cout << str[i];
}
cout << endl;
//其他函数操作
//万金油函数 empty() size();
string mystring = "IMissyou";
//cout << sizeof(mystring) << endl; //28 计算string字符串的长度不要sizeof()
//cout <<"容量:" <<mystring.capacity() << endl;
cout <<"mystring:"<< mystring.size() << endl; //输出mystring的长度为8
string strEmpty; //empty()函数用来判断该string字符串是否为空,若为空则返回真
if (strEmpty.empty()) //return length==0; 可用此来记忆为空的结果是真还是假
{
cout << "string为空" << endl;
}
}
申请内存——二级指针创建二维数组
-
我们知道定义一个一级指针的方式——int* p
p相当于一个一维数组,指针的偏移可对一维数组中的元素进行访问(int* p相当于int p[])
-
但是二级指针——int** p不等效于int p [ ] [ ];
通过一级指针 int* p相当于int p[];我们可以推断二级指针int** p=int *p[ ];
int *p[ ]是一个指针数组,该数组里面有若干个一级指针,它所指的对象是一级指针
-
现在我们用函数的方法,用c与c++的动态内存申请方式来用二级指针创建一个二维数组
#include <iostream> #include <stdio.h> using namespace std; int** create_c(int row, int clos) { //用到c语言malloc函数 int** array = (int**)malloc(sizeof(int*) * row); //此处创建了row个一级指针,也就是行指针 if (array == NULL) //用于判断malloc函数是否申请成功 return NULL; for (int i = 0; i < row; i++) { array[i] = (int*)malloc(sizeof(int) * clos); //*(array+i) = (int*)malloc(sizeof(int) * clos); 也可用指针偏移的方法,但是更多采用数组array[i]的方式 } return array; } int main() { int** array = create_c(4,5);//这里创建了4行5列的二维数组 for (int i = 0; i < 4; i++) for (int j = 0; j < 5; j++) array[i][j] = 5; //这里初始化了数组 //*(*(array + i) + j) = 5; //可以采用二级指针偏移的方式来初始化(装杯专用) for (int i = 0; i < 4; i++) { for (int j = 0; j < 5; j++) cout << array[i][j] << " "; //cout << *(*(array + i) + j) << " "; cout << endl; } free(array); return 0; }
#include <iostream> #include <stdio.h> using namespace std; int** create(int row, int clos) { //用到c++的new来申请内存 int** array = new int*[row]; //此处创建了row个一级指针,也就是行指针 for (int i = 0; i < row; i++) { array[i] = new int[clos]; } return array; } int main() { int** array = create(4,5);//这里创建了4行5列的二维数组 for (int i = 0; i < 4; i++) for (int j = 0; j < 5; j++) array[i][j] = 5; //这里初始化了数组 //*(*(array + i) + j) = 5; //可以采用二级指针偏移的方式来初始化(装杯专用) for (int i = 0; i < 4; i++) { for (int j = 0; j < 5; j++) cout << array[i][j] << " "; //cout << *(*(array + i) + j) << " "; cout << endl; } delete[]array; return 0; }
-
我知道可能有人开始已经搞晕了,这高级指针到底是什么意思,那么接下来我用画图的方式来帮助大家理解
-
既然已经讲了二级指针创建二维数组,那么我们用传参的形式如何来创建呢,这里就可以很直观的看出来引用的强大之处
//这里运用了无返回的函数通过传参来进行创建二维数组 //一下用c++的new来写,用c的malloc也是如此 #include <iostream> using namespace std; void create(int**& array,int row, int clos) { //用到c++的new来申请内存 array = new int*[row]; //此处创建了row个一级指针,也就是行指针 for (int i = 0; i < row; i++) { array[i] = new int[clos]; } } int main() { int** array; //这里运用了二级指针的引用,可以通过传参的方式来改变实参 create(array,4, 5);//这里创建了4行5列的二维数组 for (int i = 0; i < 4; i++) for (int j = 0; j < 5; j++) array[i][j] = 5; //这里初始化了数组 //*(*(array + i) + j) = 5; //可以采用二级指针偏移的方式来初始化(装杯专用) for (int i = 0; i < 4; i++) { for (int j = 0; j < 5; j++) cout << array[i][j] << " "; //cout << *(*(array + i) + j) << " "; cout << endl; } delete[]array; return 0; }
-
如果不用引用怎么来改变呢?那就要用到三级指针来指向二级指针,从而改变实参 。这样的方式很明显比较复杂和不好理解
#include <iostream> using namespace std; void create(int*** array,int row, int clos) { //用到c++的new来申请内存 array[0] = new int* [row]; //这里我们只创建一个二维数组,所以只用array[0]即可 for(int i=0;i<row;i++){ //这个array[0]就是只创建一个二维数组,否则,三级指针应该对应的是三维数组,这里就不深究了。三维数组可以用与多个打表或者做游戏关卡绘制多个地图等等 array[0][i] = new int[clos]; } } int main() { int** array; create(&array,4, 5);//这里要注意,我们需要把二级指针的地址传给三级指针,即用取地址符号& for (int i = 0; i < 4; i++) for (int j = 0; j < 5; j++) array[i][j] = 5; //这里初始化了数组 //*(*(array + i) + j) = 5; //可以采用二级指针偏移的方式来初始化(装杯专用) for (int i = 0; i < 4; i++) { for (int j = 0; j < 5; j++) cout << array[i][j] << " "; //cout << *(*(array + i) + j) << " "; cout << endl; } delete[]array; return 0; }