上篇文章说了C与C++区别中的 头文件命名空间 、 using语法 、 引用类型(常引用 右值引用) 、 基本的输入输出 、 函数思想。
这次我们再来看看C++ 中结构体 动态内存申请 内存池 string类型 这四种内容的区别
1.结构体
与C语言不同的是 C++能在结构体中定义或者申明函数 在结构体中申明的函数可以通过结构体名+作用域标识符(结构体限定名) 来在结构体外定义函数 (结构体中定义的函数叫做成员函数,也叫做行为(方法))
#include <iostream>
using namespace std;
struct A{
int a;
float b;
void print(); //结构体中的函数申明
};
//通过作用域标识符在结构体外定义
void A::print(){
cout<<a<<b<<endl;
}
C++中通过结构体定义对象(结构体变量)时可以省略 struct 关键字 直接通过结构体名来定义。
简化了定义的步骤 ,当然也可以通过 struct 关键字来定义 ,不做硬性规定
struct student std; //定义一个std对象(结构体变量)
student std; //定义一个std对象
这两行代码本质是一样的。
对于结构体变量成员的访问 C和C++中的区别不大,主要有以下三种
-
对象(结构体变量).成员
-
对象指针->成员
-
(*对象指针).成员
以下是关于结构体的一些测试代码
#include <iostream>
#include <string>
using namespace std;
struct MM
{
//protected: 不需要深究后续会讲
//MM() {} 不需要深究后续会讲
//属性,特征
//数据成员
char name[20];
int age;
//.....
//行为(方法)
//成员函数
void print()
{
cout << name << "\t" << age << endl;
}
void printData(); //在结构体中声明,在外面实现
//通过外部函数修改数据
int& getAge()
{
return age;
}
};
//结构体名限定,就是告诉别人这个函数来自哪里
void MM::printData()
{
cout << name << "\t" << age << endl;
}
//结构体中的变量必须要通过结构体变量(结构体指针)访问
//C++结构体中的函数访问属性,可以直接访问
int main()
{
struct MM girl = { "小芳",28 };
MM mm = {"小丽",24};
girl.print();
(&mm)->printData();
MM* p = &mm;
p->printData();
p->getAge() = 84;
p->printData();
p->age = 1991;
p->printData();
MM array[3];
return 0;
}
2.动态内存申请
首先回忆一下C语言中一些动态内存申请的操作:
1.malloc 申请动态内存 (不带初始化)
2.calloc 申请动态内存 (带初始化)
· 3.realloc 申请动态内存 (重新申请内存)
4.free 释放动态申请的内存
C++中不再使用C语言的动态内存申请函数 而是采用 new 来动态申请(当然 C语言的动态内存申请函数加上对应的头文件 在C++中任然有效)
注意:new 和 malloc 的一个区别,malloc申请的内存在堆区 而new申请的内存在自由存储区
-
C++的动态申请
-
new(申请)和delete(释放)
-
单个变量内存申请 : 例如申请一个int数据类型的指针 int* pa=new int; int* pb=new int(10); //括号用来初始化(可以不加)
-
-
#include<iostream> using namespace std; int main(){ //给单个变量申请内存 int* a=new int; char* b=new char; double* c=new double; //申请的时候初始化 ()给单个数据初始化 int* aa=new int(2); //动态申请一个int大小的内存并初始化为2 赋值给指针aa //delete释放内存 delete a; a=nullptr; delete b; b=nullptr; delete c; c=nullptr; delete aa; d=nullptr return 0; }
-
数组的动态申请 : 申请一个长度为3的 int类型的数组 :int *parr=new int[3]; 申请一个长度为4的 int类型的数组并初始化:int *parr=new int[4]{1,2,3,4}
-
#include<iostream> uisng namespace std; int main(){ //一维数组的动态内存申请 并初始化 []表明数组长度(可以填变量也可以填常量) {}对数组元素初始化 int *parr=new int[4]{1,2,3,4}; char *pchar=new char[4]{'a','b','c','d'}; delete []parr; parr=nullptr; delete []pchar; pchar=nullptr; return 0; }
需要注意的是:在释放动态申请的数组时 ,我们为了代码的可读性 ,一般会在delete 后面加上 [ ] ,以此来表示释放的是一段内存 。当然不加 [] ,释放的也是一段内存,只是为了提高可读性。 [ ]本身没什么实际作用。
-
结构体内存申请
-
对于结构体内存的申请,还是按部就班
#include<iostream>
using namespace std;
struct studentA{
int age;
char[name];
};
struct studentB{
int age;
char* name;
};
int main(){
//动态内存申请一个结构体对象 并初始化
studentA* stdA=new student{20,"xiao bai"};
//动态内存申请一个结构体对象
//注意这里不能再初始化 这里name 是一个指针类型
studentB* stdB=new student;
//需要再次对name动态申请内存
stdB->name=new char[20];
strcpy(stdB->name,"xiao hei");
stdB->age=21;
//释放
delete stdA;
stdA=nullptr;
delete stdB;
stdB=nullptr;
return 0;
}
上述代码中有一个需要注意的地方 对结构体成员中的指针变量初始化操作 必须要给他申请内存 才能赋值成功 。
下面是一些动态内存申请的测试代码
#include <iostream>
using namespace std;
//允许大家申请一段内存,共给程序使用,综合管理内存
//malloc 内存是在堆区
//new 内存是自由存储区
void testMemory()
{
char* memorySum = new char[1024];
//.......事情的处理,需要内存,所有内存源自于memorySum
//int* pNum = new(申请内存的开始位置) int[3]
int* pNum = new(memorySum) int[3]{ 1,2,3 };
//char* pstr = new(pNum + 3) char[20]{ "ILoveyou" };
//和下面这句话是等效的
char* pstr = new(memorySum + 12) char[20]{ "ILoveyou" };
for (int i = 0; i < 3; i++)
{
cout << pNum[i] << " ";
}
cout << endl;
for (int i = 0; i < 3; i++)
{
cout << ((int *)memorySum)[i] << " ";
}
cout << endl << pstr << endl;
cout << (memorySum + 12) << endl;
delete[] memorySum;
memorySum = nullptr;
}
int main()
{
testMemory();
return 0;
}
3.内存池
-
允许大家申请一段内存,共给程序使用,综合管理内存(即申请一段内存,给多个不同的程序分配不同的内存段)
-
#include<iostream> uisng namespace std; int main(){ //申请1024个字节的空间 1k大小 char *memorySum=new char[1024]; //从memorySum开始 分配10个char类型内存给str --- 10字节 //char* str = new(申请内存的开始位置) int[3] char* str = new(memorySum) char[10]; //申请10个int类型内存给arr --- 40字节 int* arr=new(memorySum+10) int[10]; //等效于下面这行 //int *arr=new(str + 10) int[10]; delete []str; str=nullptr; delete []arr; arr=nullptr delete memorySum; memorySum=nullptr; return 0;
给一个程序分配号内存后,再次分配需要在上个程序结束的内存开始分配 :new(内存开始分配的地方)
4.string类型
string类型本身就是一个类
-
string创建(3种方式)
1.带初始化
2.通过另一个字符串创建
3.不带初始化
#include<iostream>
#include<string>
using namespace std; //没有这行的话 使用string要加std::string
int main(){
//定义一个不赋值
string str1;
str1="iLoveYou";
//定义初始化
string str2="hello"
string str3("hello");
//通过另一个string类型的值来定义
string str4=str3;
return 0;
}
-
string基本操作
-
拷贝: 直接用等号就行 str1=str2;
-
赋值:str1="hello";
-
连接:两个字符串相连接直接用加号: str3=str1+str2;
-
比较: str1>str2 str1==str2 (依旧按照c中strcmp的比较方式去比较 只不过直接通过运 算符比)
-
#include<iostream> #include <string> using namespace std; int main(){ string str1 = "hello"; string str2 = "world"; //字符串拷贝 str1 = str2; cout << str1 << endl; //字符串连接 string str3 = str1 + " " + str2; cout << str3 << endl; //字符串比较 if (str1 < str2){ cout << "str1小" << endl; } else{ cout << "str2小" << endl; } return 0; }
-
-
C++string与C语言string.h
C++中string没有'\0'
string 类型可以通过.c_str()来转换成c中的char* 类型 然后就可以用%s来输出
string str1 = "ILoveyou";
printf("%s\n", str1.c_str());
-
string 其他函数
//empty(); //判断string是否为空
//size(); // 返回string长度 (由于string没有‘\0’,所以是多长就返回多长) //to_string(); //将括号里的数字直接转化为string类型的字符串//empty()判断是否为空 string strEmpty; if (strEmpty.empty()) //return length==0; { cout << "string为空" << endl; } //直接把数字转换为相应的字符串 string str2 = to_string(1234); //size()返回string长度 int lenth=str2.size();
注意:string类型的长度并不等于string类型所占的内存大小,string类型初始所占的内存大小为28 。当长度大于28时 ,string类型会自动扩充string的内存大小。
下面是有关于string类型的一些测试代码
#include <string> //注意和string.h区别
#include <iostream>
#include <cstring> //string.h和cstring是一样
#include <stdio.h>
using namespace std;
void createString()
{
//std::string str;
string str1;
str1 = "ILoveyou"; //所以一般用string不会加const
cout << "First:" << str1 << endl;
const string cstr;
//cstr = "IMissyou"; 错误,常属性不能修改
string str2("ILoveyou");
cout << str2 << endl;
string str3 = "IMissyou"; //喜欢这种方式
cout << str3 << endl;
string str4(str3);
cout << str4 << endl;
string str5 = str4;
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* 去比较
{
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());
//outtextxy(int x,int y,char* str);
//直接把数字转换为相应的字符串
string str2 = to_string(1234);
//atoi
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
//cout <<"容量:" <<mystring.capacity() << endl;
cout <<"mystring:"<< mystring.size() << endl;
string strEmpty;
if (strEmpty.empty()) //return length==0;
{
cout << "string为空" << endl;
}
}
void initString()
{
char* str = new char[15];
//做了自动扩增处理
}
int main()
{
//createString();
//operatorString();
//compareCAndCpp();
exOperator();
return 0;
}
作业
使用动态内存申请创建一个二维数组
#include<iostream>
#include<string>
using namespace std;
//返回二级指针方式
int** fun(int rows, int cols){
int** pArray = new int*[rows];
for (int i = 0; i < rows; i++){
pArray[i] = new int[cols];
}
return pArray;
}
//二级指针引用改变指向
void function(int** &pArray, int rows, int cols){
pArray = new int*[rows];
for (int i = 0; i < rows; i++){
pArray[i] = new int[cols];
}
}
int main(){
int rows = 4;
int cols = 3;
//接受函数返回值(二级指针)
int** pArray = fun(rows,cols);
for (int i = 0; i < rows; i++){
for (int j = 0; j < cols; j++){
pArray[i][j] = 1;
}
}
for (int i = 0; i < rows; i++){
for (int j = 0; j < cols; j++){
cout << pArray[i][j] << "\t";
}
cout << endl;
}
cout << endl;
delete []pArray;
pArray = nullptr;
//引用传入二级指针修改指向
int **pp = nullptr;
function(pp, rows, cols);
for (int i = 0; i < rows; i++){
for (int j = 0; j < cols; j++){
pArray[i][j] = 2;
}
}
for (int i = 0; i < rows; i++){
for (int j = 0; j < cols; j++){
cout << pArray[i][j] << "\t";
}
cout << endl;
}
delete []pp;
pArray = nullptr;
return 0;
}