目录
一.C++与C语言结构体的区别
1.struct关键字
定义时不需要 “struct” 关键字,直接用结构体名即可。
struct A
{
char name[20];
int age;
//.....
};
int main()
{
struct A a; //C语言需要加struct
A aa; //C++可以省略
}
2.C++结构体中允许函数存在
在C++中,我们可以把整个结构体看作是一个对象,这个对象里面的数据成员叫做这个对象的属性,而在这个对象里声明的成员函数叫做这个对象的行为或者方法。
成员函数的实现可以是在结构体内,也可以在结构体外。在结构体外实现成员函数,需要用结构体名对函数加以限定。
struct A
{
char name[20];
int age;
void Fun();
};
void A::Fun()
{
//...
}
在C++的结构体中,其成员函数是可以直接访问结构体内其他成员的。
void A::Fun()
{
cout << age << endl;
}
在调用方面,C++跟C语言基本一致,一般有这三种调用方式:
struct A
{
char name[20];
int age;
void Fun();
};
void A::Fun()
{
cout << age << endl;
}
int main()
{
A a = {"小蓝",18};
A* p = &a;
a.age = 19; //对象.成员
p->age = 20; //对象指针->成员
(*p).age = 21; //(*对象指针).成员
}
此外,根据上次学的引用类型的知识,通过把引用充当返回值,我们可以在结构体中创建一个能让外部改变结构体内部属性的接口,具体实现如下:
struct A
{
char name[20];
int age;
int& getAge();
};
int& A::getAge()
{
return age;
}
int main()
{
A a = {"小蓝",18};
a.getAge() = 19;
//其实就等价于:a.age = 19;
cout << a.age << endl;
//打印结果为19
}
在结构体中这种方法看起来有点傻哈哈,但是在类中就有访问权限的问题,这种方法就方便起来了,有关类的介绍会在接下来的文章中更新的,这里先按下不表。
二.C语言和C++的动态内存申请
1.C语言的malloc,calloc,realloc。
简单来说,malloc是不带初始化的动态内存申请。
int main()
{
int* pMNum = (int*)malloc(sizeof(int) * 3);
for (int i = 0; i < 3; i++)
{
cout << pMNum[i] << " ";
}
cout << endl;
}
可以看到,打印出来的是未被初始化的垃圾值,再来看看有进行初始化的calloc:
int main()
{
int* pCNum = (int*)calloc(3,sizeof(int));
for (int i = 0; i < 3; i++)
{
cout << pCNum[i] << " ";
}
cout << endl;
}
可以看到,申请的内存变量都被初始化为了0。
而 realloc 函数的作用是在原来申请过的动态内存的基础上进行扩充,注意,扩充之后的空间一定要比原来的大。
int main()
{
int* p = (int*)calloc(1, sizeof(int));
if (!p) return 0;
(*p) = 1999;
p = (int*)realloc(p, sizeof(int)*3);
if (!p) return 0;
p[1] = 1;
p[2] = 2;
for (int i = 0; i < 3; i++)
{
cout << p[i] << " ";
}
free(p);
return 0;
}
可以看到,原有的数据仍然储存在堆区中,没有消失,只是对它进行了扩充。
2.C++的动态内存申请
(1)单个变量的内存申请
单个变量动态内存申请时用小括号。
int main()
{
//申请时不做初始化
int* pInt = new int;
*pInt = 123;
delete pInt;
pInt = nullptr;
//申请时初始化
int* pNum = new int(123);
delete pNum;
pNum = nullptr;
}
(2)数组的动态内存申请
数组的动态内存申请用大括号。下面是一维数组的动态内存申请:
int main()
{
//不初始化
int* pInt = new int[3];
delete[] pInt;
pInt = nullptr;
//初始化
int* pNum = new int[3]{ 1,2,3 };
delete[] pNum;
pNum = nullptr;
}
要特别注意,不管是C语言还是C++,涉及到堆区字符串的初始化时,不能直接赋值,否则会出现意想不到的效果,下面用代码来展示一下:
int main()
{
const char* pstr1 = new char[15];
const char* pstr2 = pstr1;
pstr1 = "I Love C++";
cout << pstr1 << "\t" << pstr2 << endl;
}
可以看到,这里动态申请的空间里的东西并没有发生变化,这里所谓的赋值只是改变了pstr1指针的指向。想要赋值可以用strcpy函数。
二维数组的动态内存申请其实跟C语言的差不多,都是先申请完二级指针的空间,再分别给数组里面的指针申请动态内存,具体如下:
int**& NewArr2D(int row,int col)
{
int** arr = new int* [row];
for (int i = 0; i < row; i++)
{
arr[i] = new int[col];
}
return arr;
}
int main()
{
int** arr = NewArr2D(2, 3);
int cnt = 0;
//初始化
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 3; j++)
{
arr[i][j] = cnt++;
}
}
//打印
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 3; j++)
{
cout << arr[i][j] << " ";
}
cout << endl;
}
delete[] arr;
}
可以看到打印成功啦!
(3)结构体动态内存申请
大体跟数组的动态内存申请一样。
struct A
{
char* name;
int age;
void print();
};
void A::print()
{
cout << name << " " << age << endl;
}
int main()
{
A* pA1 = new A;
pA1->name = new char[18];
strcpy_s(pA1->name, 18,"小蓝");
pA1->age = 18;
pA1->print();
delete pA1->name;
delete[] pA1;
}
我们可以看到,申请的结构体中如果有指针,需要二次申请,才能使用,且申请跟释放的顺序是相反的,即申请内存时是 “从大到小” ,而释放内存时是 “从小到大” ,如果顺序颠倒,会发生重复释放。
三.内存池
这里要介绍的是如何进行内存的综合管理。
我们知道,C语言中动态申请的内存统一存储在堆区,而C++中 “new” 出来的内存是在 “自由存储区” 中。如何理解 “自由” 二字?
new(申请内存开始的位置)
可以看到,所谓的自由,就是可以自由选择动态申请的内存从哪里开始储存,来分析以下代码:
void textMemory()
{
char* memorySum = new char[1024];
int* pSum = new(memorySum) int[3]{ 1,2,3 };
char* pChar = new(memorySum + sizeof(int) * 3) char[20]{ "I Love C++" };
delete[] memorySum;
}
首先我们申请了一块很大的缓冲区 “memorySum” ,然后在这块尚未被使用的内存上,我们将从 “memorySum” 的首地址出发,后面的12个字节的空间拿给pSum数组使用,再把 “pSum” 后面的20个字节的空间拿给 “pChar” 使用,然后只需要释放这块缓冲区空间即可,这就是内存的综合管理。
四.string类型
1.创建string
这里需要包含头文件 <string> ,注意这里跟C语言中的 <string.h> 是不一样的。
int main()
{
//如果没有using namespace std,那么就需要如下表示:
std::string str;
//不初始化
string str1;
str1 = "I Love C++";
//初始化
string str2 = "I Love C++";
//通过另一个字符串创建
string str3 = str1;
string str4(str2);
}
2.string基本操作
(1)赋值拷贝
直接使用等号,十分方便!
int main()
{
string str1 = "one";
string str2 = "two";
string str3 = str1;
}
(2)连接
有两种方法,一种是直接用 “+” ,一种是调用函数。
int main()
{
string str1 = "one";
string str2 = "two";
string str3 = str1 + str2;
string str4 = str1.append(str2);
}
(3)比较
还是有两种方式,一种是直接比,一种是使用函数。
int main()
{
string str1 = "one";
string str2 = "two";
if (str1 > str2)
{
cout << "str1比较大"<<endl;
}
else if (str1 < str2)
{
cout << "str2比较大"<<endl;
}
else
{
cout << "一样大"<<endl;
}
if (str1.compare(str2) == 1)
{
cout << "str1比较大" << endl;
}
else if (str1.compare(str2) == -1)
{
cout << "str2比较大" << endl;
}
else
{
cout << "一样大" << endl;
}
}
3.C语言的字符串跟C++的string有何区别
string实际上是C++里的自定义类型,而且string是没有记录‘\0’的,字符则以其作为字符串的结尾。C++的string不是我们所理解的char*类型,因此不能使用C语言里的字符处理函数,想要使用,必须先把string转化为char*类型,下面两种方法都能实现:
int main()
{
string str1 = "one";
const char* str = str1.c_str();
const char* strr = str1.data();
}
这种方式在用C++封装图形界面时挺常见的。
4.其他有意思的操作
这里就贴代码啦,自己瞎玩哈哈哈。
int main()
{
string str1 = "one";
//empty,size 万金油函数
if (str1.empty()) cout << "为空";
else cout << "不为空";
cout << endl << str1.size();
//to_string函数,跟c#里面的ToString有点像
string str2 = to_string(123);
//C语言可以用atoi函数,刷题有碰到
}
最后再附上查找这些函数的链接,方便查找~
basic_string 类https://docs.microsoft.com/zh-cn/cpp/standard-library/basic-string-class?view=msvc-170今天的整理就到这里了,继续努力!!!