C++学习笔记 (三)

文章目录

第一章 什么是C++

1.1 C++之父

1979 年,美国 AT&T 公司贝尔实验室的 Bjarne Stroustrup 博士在 C语言的基础上引 入并扩充了面向对象的概念,发明了一种新的程序语言。为了表达该语言与C语言的渊源 关系,它被命名为C++。而Bjarne Stroustrup(本贾尼·斯特劳斯特卢普)博士被尊称为C++ 语言之父。
在这里插入图片描述

1.2 历史背景

C语言作为结构化和模块化的语言,在处理较小规模的程序时,比较得心应手。但是 当问题比较复杂,程序的规模较大的时,需要高度的抽象和建模时,C语言显得力不从心。

1.3 应 “运” 而生,运为何

说这个之前,什么是面向过程编程,什么是面向对象编程,这两个东西呢。只是一种思想而已,就像二级指针和一级指针,只是对格式化内存空间不同逻辑思想而已,简单概括以下就是如下区别:

  • 面向过程:编写函数
  • 面向对象:编写类

为了解决软件危机,20 世纪 80 年代,计算机界提出了 OOP(Object Oriented Programming)思想,这需要设计出支持面向对象的程序设计语言。Smalltalk 就是当时问 世的一种面向对象的语言。而在实践中,人们发现C语言是如此深入人心,使用如此之广 泛,以至于最好的办法,不是发明一种新的语言去取代它,而是在原有的基础上发展它。 在这种情况下 C++应运而生,在C的基础之上添加面向对象的功能,最初这门语言并 不叫 C++而是 Cwith class (带类的C)。

1.4 发展计事

1.4.1 现代 C++

  • 1979 April :Work on C withClasses began
  • 1979 October:First C with Classes(Cpre)running
  • 1984: C++ named
  • 1985 October: Cfront Release 1.0 (firstcommercialrelease) The C++ Programming Language
  • 1987 December: First GNU C++ release(1.13)
  • 1989:The Annotated C++ Reference Manual; ANSI C++ committee (J16) founded (Washington,DC)
  • 1994 string:(templatized by character type) (San Diego, California); the STL accepted(SanDiego,CAandWaterloo,Canada)
  • 1998:ISO C++ standard ratified
  • 2003:Technical Corrigendum; workon C++0x started

1.5 语言地位

在这里插入图片描述

1.6 应用领域

效率重要,且同时需要好的抽象机制的领域。几乎涵盖了,底层的操作系统层,主流 服务器层和主流开发框架层。
在这里插入图片描述

1.6.1 系统层软件开发

C++的语言本身的高效和面向对象,使其成为系统层开发的不二之选。比如我们现在用 的window 桌面,GNOME 桌面系统,KDE 桌面系统。

1.6.2 服务器程序开发

面向对像,具有较强的抽像和建模能力。使其在电信,金融,电商,通信,媒体,交 换路由等方面中不可或缺。

1.6.3 游戏网络分布式云计算

在这里插入图片描述

1.6.4 丰富的库类

MFC/QT/ACE/Boost/Cocos/CrossApp/Unreal

1.7 开发环境

1.7.1 QT/VS

VS更为强大,QT更为小清新

第二章 C++类型增强

曾有人戏谑的说,C++作为一种面向对象的语言,名字起的不好,为什么呢?用 c 的 语法来看,++ 操作符是 post++,即后++。 post++,即意味着,对C语言的扩展和兼容。扩展即面向对象的扩充,兼容能否作到 百分之百呢?

2.1 Type enhance 类型增强

2.1.1 更严格的类型检查

C语言中 const * ->non-const* / void* ->sometype * / type *-> type * 均是可以的, ->的方向代表转化方向。
最直接的证明就是,c++ 里的const就是一个名副其实的const了。

2.1.2 bool类型

C 语言中没有逻辑类型,C中的逻辑的真假,用 0 表示逻辑真,而非 0 来表示逻辑的假。
而 C++中有了具体的类型,即 bool 类型,有两个值可供选择,true 和 false。但其本 质,仍是一个 char类型的变量,可被 0和非 0的数据赋值。
bool类型的值,除了true 和false以后,还可以被其它类型赋值的。当用sizeof来求 bool类型的大小的时候,发现其大小是1,即一个字节,也就是 char类型的大小。

2.1.3 真正的枚举

C语言中枚举元素类型本质就是整型,枚举变量可以用任意整型赋值。而C++中枚举 变量,只能用被枚举出来的元素赋值。

2.1.4 可被赋值的表达式

C语言中表达式通常不能作为左值的,即不可被赋值, C++中某些表达式是可以赋值的。

2.1.5 nullptr (C++11)

为了避免引起调用或语义上的混淆,C++11,此入了nullptr 用于区分,NULL 和0

2.2 Input/Output 标准输入与输出

cin 和 cout 是 C++的标准输入和输出流对象。他们在头文件 iostream 中定义,其意 义作用类似于 C语言中的 scanf和printf。
在这里插入图片描述
scanf和printf 的本质是函数, 而cin和cout是类对象。

#include <iostream>

using namespace std;

int main(int argc, char** argv)
{
   
    int a, b, c;
    cin >> a >> b >> c;// 等价于cin>> a; >> b; cin >> c;
    cout << a << endl;
    cout << b << endl;
    cout << c << endl;

    system("pause");
    return 0;
}

但是cin与scanf一样,都是不安全的:

int main(int argc, char** argv)
{
   
    char buf[10];
    cin >> buf;
    cout << buf << endl;

    system("pause");
    return 0;
}

虽然是buf[10], 但是输入大于10个字符的时候,还是大概率行得通。
我们可以使用getline来弥补这一行为:

int main(int argc, char** argv)
{
   
    char buf[10];
    cin.getline(buf, 10);
    cout << buf << endl;

    system("pause");
    return 0;
}

输出如下:
在这里插入图片描述
但是,最保险的,还是使用string类型,只是c++比起c新添加的类型,在c++中会取代字符数组:

int main(int argc, char** argv)
{
   
    string buf;
    cin >> buf;
    cout << buf << endl;

    system("pause");
    return 0;
}

但是,有时候也是不能取代的。这个string到底有多大呢?不妨看一下:

int main(int argc, char** argv)
{
   
    string buf;
    cin >> buf;
    cout << buf.max_size() << endl;

    system("pause");
    return 0;
}

输出是2147483647,也就是有符号int的最大值,超过这个值就是不安全的。所以,别超过这个值。

2.2.1 cout的格式化输出:

既然cout是为了取代printf的,那么总得拿出点实力来说服我们他确实比printf方便。就拿格式化输出来说,用法如下:

int main(int argc, char** argv)
{
   
    int a = 30;
    cout << a << endl;
    cout << hex << a << endl; //16进制
    cout << oct << a << endl;//8进制
    cout << a << endl; //在上一句中已经将默认输出设置为8进制了
    cout << dec << a << endl; //十进制输出

    system("pause");
    return 0;
}

2.2.2 cout的预宽,左右对齐

设置预宽,需要包含头文件 iomanip,然后使用set()来设置。

int main(int argc, char** argv)
{
   
    float ft = 1.234;
    cout << setw(10) << ft << setw(10) << endl;

    system("pause");
    return 0;
}

左右对齐则需要用到setiosflags()来设置:

int main(int argc, char** argv)
{
   
    float ft = 1.234;
    cout << setw(10) << setiosflags(ios::left) << ft << endl;
    cout << setw(10) << setiosflags(ios::right) << ft << endl;

    system("pause");
    return 0;
}

还有一个问题就是填充,现在默认是填充空格。我们能不能用其他字符来填充呢?可以使用setfill()来设置填充比如我们要输出时间12:03:01呢?可以通过以下来设置格式:

int main(int argc, char** argv)
{
   
    int a = 12, b = 3, c = 1;
    cout << setfill('0') << setw(2) << a << ":" << setw(2) << b << ":" << setw(2) << c << endl;

    system("pause");
    return 0;
}

以下是一个练习刷频时间的小练习:

void ShowTime()
{
   
    system("cls");
    time_t lt = time(nullptr);
    time(&lt);

    struct tm time_now;
    localtime_s(&time_now, &lt);

    int hour, min, sec;
    hour = (&time_now)->tm_hour;
    min = (&time_now)->tm_min;
    sec = (&time_now)->tm_sec;
    cout << setfill('0') << setw(2) << hour << ":" << setw(2) << min << ":" 
        << setw(2) << sec << endl;
}

int main(int argc, char** argv)
{
   
    while (1)
    {
   
        ShowTime();
        Sleep(1000);
    }

    system("pause");
    return 0;
}

2.2.3 设置浮点数精度

还有一个点需要讲,就是设置浮点数精度。我们可以使用setprecision()来设置。

int main(int argc, char** argv)
{
   
    float ft = 1.23456;
    cout << setprecision(2) << ft << endl;

    system("pause");
    return 0;
}

这个时候,setprecision(2)代表有效数字为2;

    cout << setprecision(2) << setiosflags(ios::fixed) << ft << endl;

这个时候,则表示小数位数为2位。

2.3 函数重载

函数重载会出现重名的函数,重名的函数会根据语境来决定声明。
运算符重载也是函数重载
重载的特点:

  • 函数的函数名相同
  • 函数的参数,类型,个数不同,皆可以构成重载。
  • 函数返回值的类型不能作为函数重载的标志。
int AbsNum(int a)
{
   
    return a > 0 ? a : -a;
}

float AbsNum(float a)
{
   
    return a > 0 ? a : -a;
}

int main(int argc, char** argv)
{
   
    int a = -5;
    float b = -5.12;
    cout << AbsNum(a) << endl;
    cout << AbsNum(b) << endl;

    system("pause");
    return 0;
}

注意:C++允许 int 到 long 和 double, double 到 int 和 float, int 到 short 和 char 等隐式转换,遇到这种情形,则会引起二义性。

2.3.1 重载底层实现

C++利用Name Mangling(命名倾轴)技术,来改变函数名,区分参数不同的函数名。实现原理:vcifld 表示void int float long double 及其引用。在底层实现时,函数名在编译器层面上已经不一样了。

void Foo(double a) // Foo_d
{
   
    cout << "double" << endl;
}

void Foo(long a) //Foo_l
{
   
    cout << "long" << endl;
}

2.3.2 extern “C”

C/C++的编译都是以文件为单位进行编译的。 Name Mangling(命名倾轧) 依据函数声明来进行倾轧的。若声明被倾轧,则调用为倾轧版本,若声明为非倾轧版本,则调用也为非倾轧版本。 C++ 默认所有函数倾轧。若有特殊函数不参与倾轧,则需要使用 extercn “C” 来进行 声明。

2.4 Op Overload 运算符重载

前面用到的运算符<<,本身在C语言中,是位操作中的左移运算符。现在又用作流插入运算符,这种一个运算符多种用处的现像叫作运算符重载。在C语言中本身就有重载的现像,比如 & 既表示取地址,又表示位操作中的与运算。 *既表示;解引用,又表示乘法运算符。只不过此类功能,C语言并没有对开发者开放这类功能。 C++提供了运算符重载机制。可以为自定义数据类型重载运算符。实现构造数据类型也可以像基本数据类型一样的运算特性。比如,我们可以轻松的实现基本数据类型 3+5的运算,确实不能实现两个结构体类型变量相加的运算。
记得之前写的·贪吃蛇游戏的时候,我们需要补比较蛇头与食物的位置是否一样时,我们不能直接在比较 snakeHead.pos == food.pos, 而是分别比较了 x 与 y 的值,这就很不方便:

int IfEatFood(Snake* sh, Food* fd)
{
   
    if (sh->pos_.x_ == fd->pos_.x_ && sh->pos_.y_ == fd->pos_.y_)
        return 1;

    return 0;
}

这样就很繁琐,C++ 对用户开放了这一系列功能:

typedef struct _pos {
   

    int x_;
    int y_;
}Pos;

bool operator ==(Pos one, Pos another)
{
   
    if (one.x_ == another.x_ && one.y_ == another.y_)
    {
   
        return true;
    }
    return false;
}

//运算符重载
int main(int argc, char** argv)
{
   
    Pos ps = {
    1,2 };
    Pos fdPs = {
    1,2 };

    if (ps == fdPs) //本质就是operator ==(ps, fdPs)
        cout << "equl" << endl;
    else
        cout << "not equl" << endl;

    system("pause");
    return 0;
}

2.5 默认参数(Default Arg)

通常情况下,函数在调用时,形参从实参那里取得值。C++给出了可以不用从实参取 值的方法,给形参设置默认值,称为默认参数。默认值,则是一种最为常见的情况,是对真实生活的模似,生活中很难找出没有默认 的东西。(例如,**杀人偿命,欠债还钱 **)故,C++引入默认参数,也是为了方便编程。
默认规则:

  • 从右往左,不能跳跃
void Foo(int a=1, int b, int c = 5)
{
   
    cout << "a = " << a << ", b = " << b << ", c = " << c << endl;
}

这样设计坚决不行的,设置默认值必须从右往左且不能跳跃

  • 实参个数 + 默认个数 >= 形参个数
void Foo(int a, int b = 0, int c = 0)
{
   
    cout << "a = " << a << endl;
    cout << "b = " << b << endl;
    cout << "c = " << c << endl;
}

int main(int argc, char** argv)
{
   
    Foo(5,4); // 2 + 2 = 4
    Foo(1);   // 1 + 2 = 3
    Foo();    // 0 + 2 = 2 < 3 编译不通过
}
  • 声明和实现不在一起的时候,默认参数出现在声明中(可能由于编译器不同而不同)
  • 默认参数可以是一个常量,全局变量,亦或是一个函数。

2.5.1 规则冲突

重载与默认参数的冲突。这是一个无解的冲突。

  • 当实现同一个功能的时候,既可以使用默认参数,也可以使用重载,但是推荐使用默认参数。
void Foo(int a, int b = 0, int c = 0)
{
   
    cout << "a = " << a << endl;
    cout << "b = " << b << endl;
    cout << "c = " << c << endl;
}

void Foo()
{
   
    cout << " NULL " << endl;
}

2.6 & 引用(Reference)

2.6.1 定义

变量名,本身是一段内存的引用,即别名(alias)此处引入的引用,是为已知变量起的一个别名。
声明如下:

int main(int argc, char** argv)
{
   
    int a = 0;
    int& ra = a;
    
    return 0;
}

此处的 ra 与 a 是的等价关系。此处 ra 是一种声明关系,不开辟额外的空空间。且必须初始化,不能单独存在与被别名的变量拥有相同的数据类型。
引用关系一旦确定,便不可变更:

int main(int argc, char** argv)
{
   
    int a = 0;
    int b = 1;

    int& ra = a;
    cout << ra << endl;
    ra = b;
    cout << ra << endl;

    return 0;
}

输出如下:
在这里插入图片描述
可能会误以为引用已经变更到 b 身上了,其实并没有,这里等价于:

int a = 0, b = 1;
int & ra = a;
ra = b // a = b;
cout << ra << endl; // cout << a << endl;

所以是直接更改了a的值,可以通过取地址来证明:
在这里插入图片描述
我们可以对一个变量建立多个引用,此时所有的引用都是一种平行关系。如下:

int main(int argc, char** argv)
{
   
    int a = 0;
    int& ra_1 = a;
    int& ra_2 = a;
    int& ra_3 = ra_2;
    
    return 0;
}

2.6.2 引用的应用

C++很少使用独立变量的引用,如果使用某一个变量,就直接使用它的原名,没有必要使用他的别名。
引用的真正目的,就是取代指针传参。C++引入引用后,可以用引用解决的问题。避免用指针来解决。
还记得怎么交换两个int吗?

void MySwape(int* pa, int* pb)
{
   
    int t = *pa;
    *pa = *pb;
    *pb = t;
}

//引用的应用
int main(int argc, char** argv)
{
   
    int a = 0, b = 5;
    cout << a << "    " << endl;
    cout << b << "    " << endl;

    MySwape(&a, &b);
    cout << a << "    " << endl;
    cout << b << "    " << endl;

    return 0;
}

但是在这里,引用可以完全取代指针,这也正是他的作用所在:

void MySwape(int& ra, int& rb)
{
   
    int t = ra;
    ra = rb;
    rb = t;
}

//引用的应用
int main(int argc, char** argv)
{
   
    int a = 0, b = 5;
    cout << a << "    " << endl;
    cout << b << "    " << endl;

    MySwape(a, b);
    cout << a << "    " << endl;
    cout << b << "    " << endl;

    return 0;
}

效果一模一样。传引用等价于传作用域。把一个变量以引用的方式传到另外一个作用域。等价于扩展了该变量的作用域。

2.6.3 引用的提高

2.6.3.1指针的引用-有, 引用的指针-无

引用的本质是指针,C++对裸露的内存地址(指针)作了一次包装。又取得了指针的优良特性,避免使用裸露的地址。所以再对引用取地址,建立引用的指针没有意义
指针的引用如下:

void MySwape(const char*& p, const char* & q)
{
   
    const char* t = p;
    p = q;
    q = t;

}

//指针的引用
int main(int argc, char ** argv)
{
   
    const char* p = "China";
    const char* q = "Canada";
    
    MySwape(p, q);
    cout << "p = " << p << endl;
    cout << "q = " << q << endl;

    system("pause");
    return 0;
}

这告诉我们,原来需要用二级指针解决的事情,现在只需要在平级内解决。这是很棒的东西,不用再指来指去。
对于引用的指针类型,C++避免了对引用再次开放。

	const char*& rp = p;
    const char&* prp = &re;

这样是编译不过去的。

2.6.3.2 指针的指针-有,引用的引用-无

指针的指针,即二级指针。C++为了避免C语言设计指针的"失误",避免了引用的引用这种情况。由此,也避免了引用的引用的引用的…的引用的情况,这种可穷递归的设计本身就是有问题的。
指针的指针如下:

int main(int argc, char** argv)
{
   
    int a = 5;
    int* p = &a;
    int** pp = &p;
    int*** ppp = &pp;

    system("pause");
    return 0;
}

这里所讨论的引用的引用,并非之前讨论的对引用再次引用,如下:

	int a = 5;

    int& ra = a;
    int& raa = ra;
    int& raaa = raa;

这种情况是完全允许的,因为ra,raa,raaa都是a的别名,他们是平级关系。我所说的是下面这个情况:

	int a = 5;

    int& ra = a;
    int&& raa = ra;

这样就叫作对引用再次引用,也就是二级引用,和二级指针的思想一样。但是这种是编译不过的,在C++里不存在这种逻辑。如果放开这个逻辑的话,接下来就会出现三级引用, 四级引用, 五级引用。。。这样就刹不住车了,不也就成为了另外的一个指针吗?平级就能解决的问题,为什么又要去跨层解决?

2.6.3.3 指针的数组-有,引用的数组-无

看下面的几个情况:

int a, b, c;
int *p[] = {
   &a, &b, &c};//指针数组
int & q[] = {
   a, b, c};//引用数组

其中,第二个是铁定编译不过去的。
可以通过反证法来证明。
第一个例子,指针数组的首元素是 int * 型,所以首元素的地址就是 int ** ·型的。
第二个例子, 引用数组的首元素是 int &型,所以首元素的地址就应该是 int & * 的,我们知道,引用的指针是不存在的,所以第二个是编译不过去的。

2.6.3.4 数组的引用

数组是一种构造类型,那么数组可以被引用吗?
答案是可以的。
数组名,本质是一个常量指针,对于指针是可以取引用的,所以数组的引用是存在的, 如下示例。
数组名代表了首元素地址,也是整个数组的唯一标识符。那么就从这个地方出发去研究, 先研究当数组名代表首元素地址时的情况:

int main(int argc, char** argv)
{
   
    int arr[5] = {
    0,1,2,3,4 };
    int* const& parr = arr;
    for (int i = 0; i < 5; i++)
    {
   
        cout << parr[i] << endl;
    }

    system("pause");
    return 0;
}

其次是数组名当作一个整体,代表整个数组的情况。int arr[5] 实际上是 int[5] 类型的,可得:

  • int[5] &parr = arr, 换写成 int &arr[5],由于我们知道,引用的数组是不存在的,那么又可得:
  • int (&arr)[10] = arr

2.7 常引用

2.7.1 Const Semantic

C++中 const 定义的变量称为常变量。const 修饰的变量,有着变量的形式,常量的作用,用作常量,常用于取代#define 定义的宏常量

2.7.1.2 常引用的特性

const的本意,即不可修改。所以,const对象,只能声明为const 引用,使其语义保持一致性。 non-const 对象,既可以声明为 const 引用,也可以声明为 no-const 引用。 声明为const引用,则不可以通过const 引用修改数据。

int main(int argc, char** argv)
{
   
    const int a = 100;
    const int & ra = a;

    int b = 200;
    const int& rb = b;// 只具备读的功能。
    int c = rb + ra;

    system("pause");
    return 0;
}
2.7.1.3 临时对象的常引用

临时对象,通常理解为不可以取地址的对象,比如函数的返回值,即Cpu中计算产生的中间变量通常称为右值。常见临时值有常量,表达式等。
以下办法是行不通的:

int& a = 55;

但是,我们可以用常引用来引用它:

const int& a = 55;

也可以对表达式进行引用:

int b = 5, c = 3;
const int& e = b + c;

再来研究函数的返回值:

int ReturnA()
{
   
    int a = 100;
    return a;
}

int main(int argc, char** argv)
{
   
    int f = ReturnA();
    return 0;
}

我们吧ReturnA的值返回给一个整型 f 当然是可以的,但是返回给一个整型引用就会出问题,正确的做法依旧是通过const来解决:

int ReturnA()
{
   
    int a = 100;
    return a;
}

int main(int argc, char** argv)
{
   
    const int& f = ReturnA();
    return 0;
}

可以理解为,ReturnA在返回时产生了一个中间变量,这个中间变量时在CPU里面的,所以这时候的引用是引用了在CPU中的一个临时变量。
还有一种情况,当引用类型与被引用类型不同的时候,也可以用const来解决:

double p = 3.14;
const int& rp = p;
cout << rp << endl;

此时输出为 3
造成这个的原理是什么呢?其实原理还是中间变量。可以来看一下:

 	double a = 3.14;
    const int& ra = a;

    cout << "a  = " << a << endl;
    cout << "ra = " << ra << endl;

    a = 4.14;
    cout << "a  = " << a << endl;
    cout << "ra = " << ra << endl;

输出如下:
在这里插入图片描述
发现,ra尽管是对a的引用,但是当a发生改变时,ra的值并没有改变。其实本质就是发生了如下的变化:

int & t = a;
const int & ra = t;

常引用申请了新内存以存放初始化的值,并以const修饰,这样就可以实现对引用对象的类型转换,不过这样也等于引用了新的对象,跟最初的引用对象就没关系了。

2.8 引用的本质

之前稍微提到过一点,引用的本质就是指针。但是我们要如何其去验证这一观点呢,原来那套直接 sizeof 的办法肯定行不通的了。可以如下去严重:

struct TypeC {
   
    char c;
};

struct TypeP {
   
    char* pc;
};

struct TypeR {
   
    char& rc;
};

int main(int argc, char** argv)
{
   
    cout << "sizeof(TypeC) = " << sizeof(TypeC) << endl;
    cout << "sizeof(TypeP) = " << sizeof(TypeP) << endl;
    cout << "sizeof(TypeR) = " << sizeof(TypeR) << endl;
    return 0;
}

输出如下:
在这里插入图片描述
这里可以大致推敲出来,引用实际上就是一个指针。但是,引用他必须初始化,什么样的数据类型需要初始化呢?常量就必须初始化。所以,引用就是一个常指针,且一经声明则不可以更改。它的结构形式就应该如下:

int * const p

我们在使用引用的时候,会发现引用和指针使用起来不一样。但是我可以很负责的讲,引用脱去面上的包装,在底层实现上和指针的实现是一模一样的。可以写两个Swape,一个用指针实现,一个用引用实现,在编译器里调试,汇编层面会暴露的一览无余。

2.9 new/delete 堆内存操作

C语言中提供了 malloc 和 free 两个系统函数,完成堆内存的申请和释放。而C++则提供了两个关键字 new 和 delete。此两个关键字是为类对象而设计的。

2.9.1 new/new[]

2.9.1.1 单变量
	int* pt = (int*)malloc(sizeof(int));
    int* p = new int;

以上是C与C++申请堆内存的操作。在C++中可以如下对申请的内存进行初始化:

	int* p = new int(10);
    cout << *p << endl;

此时输出就为10,但是一般不这样初始化,还是老老实实用平常的办法:

	int* pt = (int*)malloc(sizeof(int));
    int* p = new int;
    *p = 10;

那我们要 new 一个指针的话,就得用二级指针咯:

 	int** pp = new int*;
    *pp = p;

结构体一样可以new:

Stu* ps = new Stu;

以上就是单变量,接下来看看申请一堆空间。

2.9.1.2 申请一或多维数组

new 关键字,后面跟上类型和维度,比如申请一个 10个int类型大小的数组,即 new int[10], 后面也可以跟初始化数据。

float* p = new float[10]{
    1.2,1.4,1.6 };

不过我们通常也不会在这里直接初始化。
接下来是指针数组的申请:

	char** pp = new char* [11];
    for (int i = 0; i < 10; i++)
    {
   
        pp[i] = (char*)"China";
    }
    pp[10] = nullptr;
    while (*pp!=nullptr)
    {
   
        cout << *pp++<< endl;
    }

多维数组的申请:

//二维空间-数组指针
    int(*ptr)[5] = new int[3][5];
    for (int i = 0; i < 3; i++)
    {
   
        for (int j = 0; j < 5; j++)
        {
   
            ptr[i][j] = i + j;
        }
    }
    for (int i = 0; i < 3; i++)
    {
   
        for (int j = 0; j < 5; j++)
        {
   
            cout << ptr[i][j]<<" "  
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值