C++进阶学习总结-(1.3)范围for语句、动态分配、nullptr

For循环新特性:

  • 可以使用for语句进行遍历数组(c++11新特性)

  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15

    using namespace std;

    int (){
    int nums[] = {1,2,5,6,8,21};
    int nums2[]{33,1,75,45};

    for(auto x:nums){
    cout << x << " ";
    }
    cout << endl << endl;//auto自动判断数组类型。
    for(auto x:nums2){
    cout << x << " ";
    }
    }
  • 运行效果:

优化:
  • 很显然通过这个for循环遍历数组是用过把数组内的每一个元素复制进x里面进行输出的。这里的复制操作将消耗一部分的效率。为提高程序运行效率这里可以采用引用来进行遍历。

  • 1
    2
    3
    for(auto&x : nums){
    cout << x << " ";
    }

动态分配内存基本概念:

  1. 简述c语言与c++语言的内存分配不同:

    • C语言 C++语言
      程序区、静态存储区、动态存储区 堆、栈、全局/静态区、常量存储区、程序代码区
  2. 其中C++语言:

    • 栈:一般函数内的局部变量都会存在这。例如 int a = 4 此时这个a就是存储在栈区的(由编译器自动完成分配和释放,速度快有限)。

    • 堆:由程序员自己分配和释放。用new/malloc分配,delete/free释放。忘记释放后,当程序结束后才会被系统收回

    • 全局/静态存储区:存储全局变量和static变量,程序结束后被回收。

    • 常量存储区: const定义的和一些字符串。

    • 程序代码区

      堆和栈的不同用途和区别

    空间有限,分配速度快,程序员控制不了 只要不超出时间拥有的物理内存,也在操作系统运行你嫩功能分配最大内存大小之内,都可以分配。分配速度慢,好处是灵活。随时分配随时释放。

  3. malloc和free

    • 这两个是c语言中对内存动态处理的函数(c++中的new和delete是关键字)
    • void *malloc(int Numbytes):
      • Numbytes:要分配的字节数。分配成功返回被分配内存的指针,分配失败则返回NULL;
    1
    int* p  = malloc()
    • void free (void *FirstByte):

      • 将之前malloc分配的内存空间还给程序。
      1
      2
      3
      4
      5
      6
      7
      8
      int* p = NULL;
      p = (int*)malloc(4*sizeof(int));
      if(p!=NULL){
      //分配成功
      *p = 5;
      cout << *p << endl;
      free(p);
      }

补充:字符串拷贝函数
  • strcpy(char*p,char*s)strcpy_s(char*p,int size,char*s)
  • strcpy()函数不安全:当指针s的字符串的长度大于指针p分配的内存时仍然继续往里进行拷贝字符串且不报错,使程序变的不再稳定。
  • strcpy_s()函数给定了一个size来限定指针s的长度,如果实际指针s的字符串长度大于size那么程序就会弹窗报错。

使用strcpy函数

1
2
3
4
5
6
7
8
9
10
11
12


using namespace std;

int () {

char* p = NULL;
p = (char*) malloc(20 * sizeof(char));
strcpy(p, "Hello ShuHaoHwang");
cout << p << endl;

}

结果编译不通过并报错

使用strcpy_s函数

  • 情况1:源字符串实际长度小于size值。
1
2
3
4
5
6
7
8
9
10
11
12


using namespace std;

int () {

char* p = NULL;
p = (char*) malloc(20 * sizeof(char));
strcpy_s(p, 2,"Hello ShuHaoHwang");
cout << p << endl;

}

结果运行报错

  • 情况2:正常情况。
1
2
3
4
5
6
7
8
9
10
11
12


using namespace std;

int () {

char* p = NULL;
p = (char*) malloc(20 * sizeof(char));
strcpy_s(p, 20,"Hello ShuHaoHwang");
cout << p << endl;

}

正常运行


new和delete
  • new/delete和malloc/free一样干了同样的事——分配和释放空间,同时new,delete还干了更多事情。
  • new与delete配对使用。malloc与free配对使用
  • 不要重复释放指针
  • new的一般使用格式:
    • 指针变量名 = new 类型;
      • int* p = new int;
    • 指针类型名 = new 类型(初始值);
      • int* p= new int(2);//给初始值
    • 指针类型名 = new 类型[内存单元个数] (数组);
      • int* p = new int[10];

注意:当用指针分配一个数组的时候用 delete[] 指针名

mallo/free与new/delete的区别:
malloc/free new/delete
只做了分配和释放内存工作 除了分配和释放内存,还进行了初始化工作(new),和清理工作(delete)等

nullptr:

  • nullptr是意为指针。先看一段代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14


using namespace std;

int () {
int* a = 0;
int* b = NULL;
int* c = nullptr;
cout << "0 == NULL? " << (a == b) << endl
<< "0 == nullptr? " << (a == c) << endl
<< "NULL == nullptr? " << (b == c) << endl;


}

实验结果:

从实验结果发现对于指针来说他们三者并没有不同,都代表这空指针指向0x000000,但实质上nullptr是一个指针。NULL是一个数字它等于0;即:

1
2
int p = NULL;//成立!p的值为0。
int a = nullptr;//报错:数据类型不一致。

  • 根据下面的代码探索nullptr和NULL:
1
2
3
4
5
6
7
8
9
10
#include<iostream>

using namespace std;

int main() {

cout << typeid(NULL).name() << endl;
cout << typeid(nullptr).name() << endl;

}

提示:typeid(数据名).name():返回的是该数据的数据类型

实验结果:

  • nullptr与NULL数据类型不同。nullptr本质上是一个指针,引入这个关键字的目的是区别代表数字时的NULL和代表指针空地址时的NULL防止混淆。
  • 实际用法:在重载函数时nullptr会被识别成指针从而调用指针类型的重载

结论:

对于指针的初始化,以往用到和指针有关的NULL的场合,能用nullptr的大家全部用nullptr取代NULL。

–(本文完)<原创>