C/C++基础知识总结——数组、指针域、字符串

1. 数组

1.1 数组作为函数参数

  (1) 如果使用数组作为函数的参数,则实参和形参都是数组名,且类型要相同。数组名做参数时传递的是地址

  (2) 使用方法:

    void rowSum(int a[][4], int n, int m);

    // 不能写成 int a[][];也不能写成int **a;

1.2 对象数组

  (1) 声明语句

    ① 类名 数组名[常量表达式];

  (2) 例子:

    Location a[2] = {Location(1,2), Location(3,4)};

    Location a[2] = {Location(1,2)};//此时,先初始化a[0]。再用默认构造函数初始化

    //a[1]

  (3) 当个元素对象的初值要求相同时,应该在类的默认构造函数里赋初值

2. 指针

2.1 内存空间的访问方式

2.2 指针变量的声明

  (1) 指针是一种数据类型,指针变量是用于存放内存单元地址的

2.3 与地址相关的运算 * 和 &

2.4 指针的赋值

  (1) 定义指针后最好要赋初值,不然可能会修改造成不可预见的错误

  (2) 数组名是个指针常量,不能变

  (3) 注意:

    ① 可以声明指向常量的指针,此时不能通过指针来改变所指对象的值,但指针本身可以改变,可以指向另外的对象。如:

      int a;

      const int *p1 = &a;//声明的是p1指向的内容是常量

      int b;

      p1 = &b; //可以,指针指向内容可以改变

      *p1 = 1; //错误,指针指向内容不可变

    ② 可以声明指针类型的常量,此时指针值不能改变。区别上面的

      int *const p2 = &a;

      p2 = &b;//错误

    ③ 特殊的void*指针

      void *pv;

      int i = 5;

      pv = &i;

2.5 指针运算

  (1) 也就是相同类型地址之间的加减如 p1++;

2.6 用指针处理数组元素

  (1) 把数组作为函数形参,等价于把指向数组元素类型的指针作为形参如:

    void f(int p[]);

    void f(int p[3]);

    void f(int *p);//这三种方法等价

2.7 指针数组

  (1) 首先这是个数组,并且这个数组的元素是指针。

  (2) 声明方法

    数据类型 *数组名[下标表达式];

    int line1[] = {1,0};

    int line2[] = {2,0};

    int line3[] = {3,0};

    int *pline[3] = {line1, line2, line3};

2.8 指针作为函数参数

  (1) 以指针作为函数参数的三个作用

    ① 是形参与实参指向同一内存,达到双向传递的功能。也就是能改变实参的值

    ② 减少传递数据的开销

    ③ 可以通过指向函数的指针传递函数代码的首地址

  (2) 如果在函数中不需要改变指针所指向内容,则应在参数表中将其声明为指向常量的指针。

2.9 指针型函数

  (1) 当一个函数的返回值是指针类型(也就是地址)时,这个函数叫做指针型函数。

  (2) 声明方式:

    数据类型 * 函数名(参数表)

    {...}

2.10 指向函数的指针

  (1) 每个函数也要占用内存空间。而函数名就是这段函数存储的起始地址

  (2) 函数指针就是专门用来存放函数代码首地址的变量。

  (3) 声明方式:

    数据类型 (*函数指针名)(形参表)

    函数指针名 = 函数名;

  (4) 关于typeof简化定义(关于typeof详细请参考互联网)

    typeof int (*DoubleIntFunction)(double);

    //此时DoubleIntFunction即为函数指针类型了

    DoubleIntFunction funcPtr;

2.11 对象指针

  (1) 就是指向对象的指针

    ptr->data;

  (2) this指针

    ① 是个指针常量,具体用法比较简单,不写了

  (3) 指向类的非静态成员的指针(感觉用的不多,略)

  (4) 指向类的静态成员的指针(感觉用的不多,略)

3. 动态内存分配

3.1 new、delete初级

  (1) 语法:

    new 数据类型(初始化参数列表)

    如果成功返回首地址,否则抛出异常

  (2) 如果建立的对象是个基本类型的变量,初始化过程就是赋值如:int *p=new int(2)

    对于基本数据类型,如果不希望在分配内存后设定初值,可以把括号省去,如果保留括号,则用0来初始化如:

    int *point = new int;

    int *point2 = new int();

  (3)  

    ① 如果建立的对象是某个类的实例对象,就是要根据初始化参数列表的参数类型和个数调用构造函数。

    ② 在new一个对象时,如果用户定义了默认构造函数则new T 与 new T() 效果相同;如果未定义,则new T时会调用系统生成的隐含的默认构造函数;new T() 除了执行默认构造函数的那些工作外还会用0赋初值

  (4) delete

    ① 语法:

    delete 指针名;//释放指针指向的内存空间

3.2 new创建数组类型对象;delete

  (1) 语法

    类型名 *数组名 = new 类型名 [数组长度];

  (2) 在new动态创建一维数组时,方括号外可以加(),但不能有参数,此时会用0赋初值

  (3) 删除

    delete[] 指针名;

3.3 assert断言

  在动态数组类中,可以通过类的成员函数访问数组元素,可以在每次访问前测试下标是否越界。这种检查可以通过C++的assert来进行,assert断言是在C++的cassert头文件中定义的红,判断一个条件表达式是否为true,如果不为true则程序会停止,并且报告错误。一般程序会通过两种模式编译——调试(debug)模式和发行(release)模式,assert只在调试模式有效。

3.4 创建多维数组

  (1) 创建三维数组

    int (*p)[10][10];

    p = new int[10][10][10]

    此时p既可以用作指针又可以以三维数组名来用

  (2) 动态创建多为数组(请参考本目录下C++动态创建多维数组)

4. 用vector创建数组对象

4.1 声明方式:

  (1) vector<元素类型> 数组对象名(数组长度, 元素初值);

4.2 与普通数组不同的是,vector声明的对象都需要初始化,普通类型用0,类对象调用默认构造函数。

5. 深复制浅复制

5.1 浅复制

  (1) 比如说一个类中有指针,浅复制的意思是这个类的指针和另外一个类的指针指向同一个内存地址,而不是真正的有个副本。这样的后果就是一个改变之后另外一个也会改变;调用析构函数时会析构两遍会出现错误。

5.2 深复制

  (1) 就是真的有个副本,完全相同copy的副本

6. 指针与引用

6.1 引用的实现机制需要依靠地址。因为只有通过地址才可以精确的指向一个变量。而指针是底层实现,而引用是高层实现,屏蔽了地址。这两者殊途同归。

6.2 两者的差别之一就是指针可以再赋值,而引用初始化后不能再赋值。

 

作者:viczzx 出处:http://www.cnblogs.com/zixuan-zhang 欢迎转载,也请保留这段声明。谢谢!