c与c++的区别(二)结构体区别、new与delete、内存池、string类型

结构体区别

  • 类型上不再需要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;
    }

  • 7
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值