C++笔记-5-数组与指针

目录标题

  • 1 数组
    • 1-1 数组的声明与使用
      • 1-1-1 数组的声明
      • 1-1-2 数组的使用
    • 1-2 数组的存储与初始化
      • 1-2-1 数组的存储
      • 1-2-2 数组的初始化
    • 1-3 数组作为函数参数
    • 1-4 对象数组
  • 2 指针
    • 2-1 指针变量的声明
    • 2-2 与地址相关的运算“ * ”和“&”
    • 2-3 指针的赋值
    • 2-4 各种指针
      • 2-4-1 指向常量的指针
      • 2-4-2 指针类型的常量
      • 2-4-3 指针数组
      • 2-4-4 指针型函数
      • 2-4-5 函数返回数组指针
      • 2-4-6 指向函数的指针
      • 2-4-6 与对象有关的指针
    • 3 动态内存分配

1 数组

数组是具有一定顺序关系的若干对象的集合体,组成数组的对象称为该数组的元素。

1-1 数组的声明与使用

1-1-1 数组的声明

声明一个数组类型,应该包括以下几方面:

  • 确定数组的名称
  • 确定数组元素的类型
  • 确定数组的结构(包括数组维数,每一维的大小等)

数组类型声明的一般形式为:
数据类型 标识符[常量表达式][常量表达式]...;

1-1-2 数组的使用

数组的元素是由下标来区分的,对于一个已经声明过的数组,其元素的使用形式为:
数组名[下标表达式][下标表达式]...
在使用过程中需要注意如下两点:

  • 数组元素的下标表达式可以是任意合法的算术表达式,其结果必须为整数
  • 数组元素的下标值不得超过声明时所确定的上下界,否则运行时将出现数组越界错误

1-2 数组的存储与初始化

1-2-1 数组的存储

数组元素在内存中是顺序、连续存储的。

1-2-2 数组的初始化

数组的初始化就是在声明数组时给部分或全部元素赋初值。
声明数组时可以给出数组元素的初值,例如:
float fa[5]={1.0,2.0,3.0};
当指定的初值个数小于数组大小时,剩下的数组元素会被赋0。若定义数组时没有指定任何一个元素的初值,对于静态生存期的数组,每个元素会被赋0,对于动态生存期的数组,每个元素的初值是不确定的。
声明为常量的数组,必须给定初值,数组中每个元素都被当作常量对待,例如:
const float fa[5]={1.0,2.0,3.0};

1-3 数组作为函数参数

使用数组名传递数据时,传递的是地址。
把数组作为参数时,一般不指定数组第一维的大小,即使指定也会被忽略。例如:

void rowSum(int a[][4],int nRow){
	for(int i=0;i<nRow;i++){
		for(int j=1;j<4;j++)
			a[i][0]+=a[i][j];
	}
}
int main(){
	int table[3][4]={{1,2,3,4},{2,3,4,5},{3,4,5,6}};
	rowSum(table,3);
	return 0;
}

1-4 对象数组

声明一个一维对象数组的语句形式是:
类名 数组名[常量表达式];
通过数组元素的公有成员的语句形式是:
数组名[下标表达式].成员名
对象数组的初始化过程,实际上就是调用构造函数对每一个元素对象进行初始化的过程。例如:
Location a[2]={Location(1,2)};
在执行时首先调用带形参的构造函数初始化a[0],然后调用默认构造函数初始化a[1]。

2 指针

2-1 指针变量的声明

指针变量是用于存放内存变量单元地址的。
声明指针的语法形式是:
数据类型 *标识符;

2-2 与地址相关的运算“ * ”和“&”

“ * ”和“&”出现在声明语句中和执行语句中其含义是不同的,它们作为一元运算符和作为二元运算符时含义也是不同的。
“ * ”出现在声明语句中,在被声明的变量名之前时,表示声明的是指针。
“ * ”出现在执行语句或声明语句的初值表达式中作为一元运算符时,表示访问指针所指对象的内容。
“ * ”作为二元运算符时,表示乘。
“&”出现在变量声明语句中位于被声明的变量左边时,表示声明的是引用。
“&”在给变量赋初值时出现在等号右边或在执行语句中作为一元运算符出现时,表示取对象的地址。
“&”作为二元运算符时,表示与。

2-3 指针的赋值

初始化指针的语法形式为:
存储类型 数据类型 *指针名=初始地址;
在定义之后,单独使用赋值语句,语法形式为:
指针名=地址;
注意:

  • 对于基本类型的变量、数组元素、结构成员、类的对象,我们可以使用取地址运算符&获得它们的地址。
  • 数组名称实际上就是一个不能被赋值的指针,即指针常量。
  • 一般情况下,指针的值只能赋给相同类型的指针。但是有一种特殊的void类型指针,可以存储任何类型的对象指针。任何类型的指针都可以赋值给void类型的指针。经过使用类型显式转换,通过void类型的指针便可以访问任何类型的数据。

2-4 各种指针

2-4-1 指向常量的指针

指向常量的指针:不能通过指针来改变所指对象的值,但指针本身可以改变,可以指向另外的对象。int a;const int *p1=&a;

2-4-2 指针类型的常量

指针类型的常量:这时指针本身的值不能改变。int * const p2=&a;

2-4-3 指针数组

指针数组:数组元素为指针的变量。int *pa[3];

2-4-4 指针型函数

指针型函数:函数的返回值是指针。
指针型函数的一般定义形式:

数据类型 *函数名(参数表)
{
	函数体
}

2-4-5 函数返回数组指针

函数返回数组指针:返回值是一个指针数组的函数。
三种方式实现:

使用类型别名:
typedef int arr[10];//arr是一个类型别名,表示含有10个整数的数组
using arr=int[10];//arr的等价声明
arr* foo(int i);//foo函数返回一个指向含有10个整数的数组的指针
常规方式:
类型说明符 (*函数名(参数表))[数组维度]
例如:int (*foo(int i))[10];
foo(int i)定义一个函数foo,需要一个int类型的参数
(*foo(int i))意味着对函数返回的结果执行解析操作
(*foo(int i))[10]表示解析foo的返回结果得到的是一个大小为10的数组
int (*foo(int i))[10]说明数组元素是int类型
常规方式简化:使用尾置返回类型
尾置返回类型跟在形参列表后面并以->符号开头,/
为了表示函数真正的返回类型跟在形参列表之后,/
在本该出现返回类型的地方放一个autoauto foo(int i) -> int (*)[10];
//foo接受一个int类型的实参,返回一个指向10个int类型的数组指针。

2-4-6 指向函数的指针

指向函数的指针:在程序中可以像使用函数名一样使用指向函数的指针来调用函数。
声明一个函数指针的一般语法:数据类型 (*函数指针名)(形参表);,一次只能声明一个。
为了方便声明多个函数指针,可以使用typedef关键字:typedef 数据类型 (*函数指针类型名)(形参表);函数指针类型名 函数指针名;
使用函数指针时需要先赋值:函数指针名=函数名;

//第一种方法
int (* funcPtr)(double);
//第二种方法
typedef int (* DoubleIntFunction)(double);
DoubleIntFunction funcPtr;
//定义一个相同返回值相同参数表的函数
int function(double a)
{
	return a>0?1:0;
}
//函数指针的使用
funcPtr=function;
cout<<funcPtr(10.0)<<endl;

2-4-6 与对象有关的指针

  1. 对象指针:用于存放对象地址的变量。
    声明对象指针的一般语法形式为:类名 *对象指针名;
    使用对象指针访问成员:对象指针名->成员名;或者(*对象指针名).成员名;
  2. this指针:隐含于每一个类的非静态成员函数中的特殊指针,它用于指向正在被成员函数操作的对象。
    this是一个指针常量,对于常成员函数,this同时又是一个指向常量的指针。在成员函数中,可以使用*this来标识正在调用该函数的对象。
  3. 指向类的非静态成员的指针
声明指向类的非静态成员的指针的一般形式为:
类型说明符 类名::*指针名;//声明指向数据成员的指针
类型说明符 (类名::*指针名)(参数表);//声明指向函数成员的指针
给指向类的非静态成员的指针赋值的一般形式为:
指针名=&类名::数据成员名;//对数据成员指针赋值
指针名=&类名::函数成员名;//对函数成员指针赋值
使用指向类的非静态成员的指针的一般形式为:
对象名.*类成员指针名 或者 对象指针名->*类成员指针名//访问数据成员
(对象名.*类成员指针名)(参数表) 或者 (对象指针名->*类成员指针名)(参数表)//调用成员函数
  1. 指向类的静态成员的指针
    对类的静态成员的访问是不依赖于对象的,因此可以用普通的指针来指向和访问静态成员。
类型说明符 *指针名=类名::静态数据成员;//声明指向数据成员的指针
类型说明符 (*指针名)(参数表)=类名::静态函数成员;//声明指向函数成员的指针

3 动态内存分配

在C++程序中建立和删除堆对象使用两个运算符:new和delete。
运算符new的功能是动态分配内存,或者称为动态创建堆对象,语法形式为:new 数据类型(初始化参数列表);。如果内存申请成功,new运算会返回一个指向新分配内存首地址的类型的指针,可以通过这个指针对堆对象进行访问;如果申请失败会抛出异常。
运算符delete用来删除由new建立的对象,释放指针所指向的内存空间。格式为:delete 指针名;

int *point=new int(2);//动态分配存入int类型的内存空间,并将初值2存入其中
delete point;

使用运算符new也可以创建数组类型的对象,这时,需要给出数组的结构说明。用new运算符动态创建一维数组的语法形式为:new 类型名[数组长度];
如果是用new建立的数组,用delete删除时在指针名前面要加“[]”,格式如下:delete []指针名;

int *p=new int[10]();//括号里不能有值,有括号表示以0赋初值
int *q=new int[10];//没有括号表示不赋初值
delete []p;
delete []q;

用new操作也可以创建多维数组,形式如下:new 类型名 T[第一维长度][第二维长度]...;

//错误
float *fp;
fp=new float[10][25][10];
delete []fp;
//正确
float (*cp)[25][10];
cp=new float[10][25][10];
delete []cp;

你可能感兴趣的:(C++学习笔记,c++,数据结构)