在现实应用问题中,总会使用到大批量的数据,这样的数据用变量 来处理效率是低下的。 数组用来表示一组数据的集合。使用数组,可以方便地定义一个名 字(数组名)来表示大批量数据,并能够通过循环批处理大量数据。
一维数组的定义: 数组就是一组相同类型数据的集合 一维数组的定义形式为:
元素类型 数组名[常量表达式]; int A[10]; int B[10], C[15]; //多个数组定义 int E[10], m, n, F[15]; //数组和变量混合在一起定义(1)一维数组是由元素类型、数组名和长度组成的构造类型。例 如:
int A[10], B[20]; // 元素是整型 double F1[8], F2[10]; //元素是双精度浮点型 char S1[80], S2[80]; //元素是字符型(2)数组名必须符合C++标识符规则。
(3)常量表达式表示数组中元素的个数,称为数组长度。常量表达式的值必须为正整数且大于等于1。
(4)数组一经定义,数组长度就始终不变。 如:int n; cin>>n; int a[n]; 错误!
一维数组的内存形式: C++规定数组元素是连续存放的,即在内存中一个元素紧跟着一个元素线性排列。
一维数组的初始化 可以在一维数组定义时对它进行初始化,初始化的语法形式如下:
元素类型 数组名[常量表达式]={初值列表}; int A[5]={1,2,3,4,5} , B[3]={7,8,9}; //一维数组初始化(1)初值列表提供的元素个数不能超过数组长度,但可以小于数 组长度。如果初值个数小于数组长度,则只初始化前面的数组元素, 剩余元素初始化为0。例如:
int A[5]={1,8,9};(2)在提供了初值列表的前提下,数组定义时可以不用指定数组 长度,编译器会根据初值个数自动确定数组的长度。例如:
int A[]={1,8,9};可以用下面的表达式计算出数组A的长度:
sizeof(A) / sizeof(int)(3)若数组未进行初始化,静态数组的元素均初始化为0;在函数 体内定义的动态数组,其元素没有初始化,为一个随机值。 如:
static int A[10]; //默认各元素的值为0 int A[10]; //各元素的值为随机数数组必须先定义后使用,且只能逐个引用数组元素的值而不能一次引用整个数组全部元素的值。
数组元素引用是通过下标得到的,一般形式为:
数组名[下标表达式](1)注意下标的表示形式 下标表达式可以是常量、变量、表达式,但必须是正整数,不允许为负。
数组元素下标总是从0开始。
int A[5]={1,2,3,4,5}, x,i=3; x = A[2] ; A[1+2]=10; A[i]++;(2)下标值不能超过数组长度,否则导致数组下标越界的严重错误。例如:
int A[5]={1,2,3,4,5}; A[5]=10; //错误,没有A[5]元素(3)整个数组不允许进行赋值运算、算术运算等操作,只有元素才可以,例如:
int A[10], B[10], C[10]; A = B; //错误 A = B + C; //错误 A[0] = B[0]; //正确,数组元素赋值 A[2] = B[2]+C[2]; //正确,数组元素赋值从数组的内存形式来看,数组元素的下标是有序递增的,这个特点 使得可以利用循环来批量处理数组元素。
多维数组的定义 C++允许定义多维数组,其定义形式为:
元素类型 数组名[常量表达式1][常量表达式2]; 元素类型 数组名[常量表达式1][常量表达式2] …[常量表达式n] ; int A[3][4]; //定义二维数组 int B[3][4][5]; //定义三维数组 int C[3,4,5,6]; //错误!多维定义实际上是反复递归一维定义:即一维数组的每一个元素又是一个一维数组,就构成了二维数组。
本质上,C++的多维数组都是一维数组,这是由内存形式的线性排 列决定的。因此,不能按几何中的概念来理解多维,多维数组不过是借用“维”的数学说法表示连续内存单元。
多维数组的初始化 可以在多维数组定义时对它进行初始化,这里以二维数组来说明, 初始化有两种形式。 (1)初值按多维形式给出:
元素类型 数组名[常量表达式1][常量表达式2] ={{初值列表1},{初值列表2},...}; int A[2][3]={ {1,2,3},{4,5,6}};//初值按二维形式(2)初值按一维形式给出:
元素类型 数组名[常量表达式1][常量表达式2] ={初值列表}; int A[2][3]={ 1,2,3,4,5,6 };//初值按一维形式初值列表提供的元素个数不能超过数组长度,但可以小于数组长度。 如果初值个数小于数组长度,则只初始化前面的数组元素;剩余元素初始化为0。这个规则两种初始化形式都适用,例如:
//只对每行的前若干个元素赋初值 int A[3][4]={{1},{1,2},{1,2,3}}; //一维形式部分元素赋初值 int A[3][4]={1,2,3,4,5};在提供了初值列表的前提下,多维数组定义时可以不用指定第1维 的数组长度,但其余维的长度必须指定,编译器会根据列出的元素 个数自动确定第1维的长度。例如:
int A[][2][3]={1,2,3,4,5,6,7,8,9,10,11,12}; //正确 int B[2][][3]={1,2,3,4,5,6,7,8,9,10,11,12}; //错误,只能省略第1维 int C[2][2][]={1,2,3,4,5,6,7,8,9,10,11,12}; //错误,只能省略第1维多维数组元素的引用与一维类似,也只能逐个引用数组元素的值而 不能一次引用整个数组,引用的一般形式为:
数组名[下标表达式1][下标表达式2] …[下标表达式n] int b[3][4], i, j, sum=0; b[0][0]=10; b[1][2]=b[0][0]+10; b[2-1][2*2-1]= 5; int A[3][4]={1,2,3},x; x = A[0][1]; //x=2 A[2][2] = 50; //则数组A变为
数组元素作为函数的参数 一维数组元素可以直接作为函数实参使用,其用法与变量相同。
int max(int a,int b); int A[5]={1,2,3,4,5} , c=2, x; x=max(c,-10); //使用变量作为函数实参 x=max(A[2],-10); //使用数组元素作为函数实参整个数组作为函数的参数 数组作为函数的形参,基本形式为:
返回类型 函数名(类型 数组名[常量表达式],...) { 函数体 } double average(double A[100],int n) { … //函数体 }数组参数的传递机制
void fun(int A[10],int n) { …… A[0]=10; } int main() { int a[10]={1,2,3,4,5} , x=5; fun(a,x); //实参分别是数组和整型变量 }如果实参使用数组名调用,本质上是将这个数组的首地址传递到形参中。
尽管数组数据很多,但它们均从一个首地址连续存放,这个首地址对应的正是数组名。
数组实参a传的是数组首地址,形参A定义为数组形式,它现在的地址与实参数组a一样,则本质上形参数组A就是实参数组a(内存中两个对象所处位置相同,则它们实为同一个对象)。
结果: a[0]=x; a[1]=y
数组作为函数的参数,传递的是数组的地址。
这样的传递机制使得当数组作为函数参数时,有下面的特殊性 (1)由于形参数组就是实参数组,所以在被调函数中使用形参就 是在间接使用实参,这点与变量作为函数参数的情况是不同的。
(2)既然形参数组就是实参数组,所以函数调用时不会为形参数组分配存储空间。 形参数组不过是用数组定义这样的形式来表明它是个数组,能够接收实参传来的地址,形参数组的长度说明也无实际作用。因此形参数组甚至可以不用给出长度。
(3)虽然实参数组将地址传到了被调函数中,但被调函数并不知道实参数组的具体长度,那么假定的大小对于实参数组来说容易数组越界。
实际编程中可以采用以下方法来解决: 函数调用时再给出一个参数来表示实参数组的长度
(4)多维数组作为函数的参数,形参数组第1维可以与实参相同, 也可以不相同;可以是任意长度,也可以不写长度;但其他维的长度需要相同。
字符数组 用来存放字符型数据的数组称为字符数组,其元素是一个个的字符。 字符数组的定义形式为:
char 字符数组名[常量表达式], ......;例如:
char s[20]; //定义字符数组 char s[4]={'J','a','v','a'}; //字符数组初始化字符串的概念
C++语言规定字符串是以’\0’(ASCII值为0)字符作为结束符的字符 数组。
在程序中可以通过判断数组元素是否为空字符来判断字符串是否结 束,换言之,只要遇到数组元素是空字符,就表示字符串在此位置上结束。
由于字符串实际存放在字符数组中,所以定义字符数组时数组的长度至少为字符串长度加1(空字符也要占位)。
字符串常量是字符串的常量形式,它是以一对双引号括起来的字符 序列。
C++总是在编译时为字符串常量自动在其后增加一个空字符。
区分“a”和‘a’和a :"a"有两个字节
C++语言总是在编译时为字符串常量自动在其后增加一个空字符, 例如"Hello"的存储形式为: 如果在字符串常量中插入空字符,则字符串常量的长度会比看到的字符数目少,例如"ABC\0DEF"的存储形式为:(检测得到长度为"ABC\p"的长度)字符的输入和输出
(1)使用标准输入输出流,将整个字符串一次输入或输出。
char str[80]; cin >> str; //输入字符串 cout << str; //输出字符串(2)使用字符串输入输出函数
gets函数 char *gets(char *s);gets函数输入一个字符串到字符数组s中。s是字符数组或指向字符 数组的指针,其长度应该足够大,以便能容纳输入的字符串。
char str[80]; gets(str); //输入字符串(2)puts函数
int puts(char *s);puts函数输出s字符串,遇到空字符结束,输完后再输出一个换行 ('\n')。s是字符数组或指向字符数组的指针,返回值表示输出字符的个数。
puts输出的字符不包含空字符。
char str[80]="Programming"; puts(str); //输出字符串C++标准库提供了兼容C语言的字符串处理函数,其头文件为 string.h。
(1)字符串复制函数strcpy char str1[10],str2[]="Computer"; strcpy(str1,str2); //复制str2到str1 (2)字符串复制函数strncpy char str1[10], str2[]="Computer"; strncpy(str1,str2,4);//复制str2的前4个字符到str1 (3)字符串连接函数strcat char str1[10]="ABC", str2[]="123"; strcat(str1,str2);//在str1后面连接str2,str2未变化 (4)字符串连接函数strncat char str1[10]="ABC",str2[]="123456"; strncat(str1,str2,4);//将str2前4个字符连接到str1后面(5)字符串比较函数strcmp
if (strcmp(str1,str2)==0)...... //比较字符串相等 if (strcmp(str1,str2)>0)......//比较str1大于str2(6)计算字符串长度函数
n=strlen("Language"); //n=8 char str[20]="Visual Basic"; n=strlen(str); //n=12(7)字符串转换成数值函数
f=atof("123.456"); //f=123.456 i=atoi("-456"); //i=-456C++为字符串提供了一种新的自定义类型:字符串类string。 采用类来实现字符串,具有如下特点:
采用动态内存管理,不必担心存储空间是否足够,甚至都不用有字符数组的概念;能够检测和控制诸如越界之类的异常,提高使用的安全性;封装字符串多种处理操作,功能增强;可以按运算符形式操作字符串,使用简单。C++程序中使用string类型,比使用C风格字符串更方便、更安全。使用string类需要将其头文件包含到程序中,预处理命令为:
#include <string> //不能写为string.h字符串对象的定义和初始化
定义和初始化字符串对象,与变量的方法类似。如果string对象没有初始化则一律是空字符串。需要注意的是C++字符串对象不需要 NULL字符结尾。
char S1[20]; //C风格字符串 string str1; //定义string对象 string sx , sy , sz; //定义多个string对象 char S2[20]="Java"; //C风格字符串初始化 string str2="Java"; //string对象复制初始化 string str3("C++"); //string对象直接初始化字符串对象的引用 与变量类似,直接使用string对象名就表示它的引用
str1 = "Pascal"; //使用string对象字符串对象的输入和输出 可以在输入输出语句中直接使用string对象来输入输出字符串
cin >> str1; //输入字符串到str1对象中存放 cout << str2; //输出str2对象中的字符串 gets(S1); //输入C风格字符串到字符数组中存放 puts(S2); //输出C风格字符串字符串对象与C风格字符串的转换
str1="Java"; //C风格字符串可以直接赋给string str1.c_str(); //string转换为C风格字符串,返回char指针 str1.copy(S1,n,pos); //把str1中从pos开始的n个字符复制到S1字符数组string对象允许使用运算符进行操作,实现类似C风格字符串的处理。 如复制(strcpy)、连接(strcat)、比较(strcmp)等。
字符串赋值 string对象可以使用赋值运算,其功能是字符串复制。可以将字符串常量赋给string对象
str1 = "Pascal"; //字符串常量复制到string对象中 strcpy(S1,"Pascal"); //C风格字符串复制到字符数组中 str1.assign(S1,n); //将C风格字符串S1开始的n个字符赋值给str1**字符串连接运算 ** string对象允许使用加号(+)和复合赋值(+=)运算符来实现两个字符串连接操作。
str1="12" , str2="AB" , str3="CD"; str1 = str2 + str3; //str1结果为ABCD str1 = str1 + "PHP"; //str1结果为12PHP str1 += str3; //str1结果为12CD字符串关系运算 string对象可以使用关系运算符来对字符串进行比较
str1="ABC" , str1="XYZ"; str1 > str2; //结果为假 str1 == str2; //结果为假 str1 == "ABC"; //结果为真其他操作 string对象可以调用其成员函数来实现字符串处理,这里列举一些 重要的操作,更详细的内容可以查阅C++标准库手册。
str1="ABCDEFGHIJK"; //获取字符串的长度 n = str1.size(); //n为11 n = str1.length(); //n为11 //检查字符串是否为空字符串 b = str1.empty(); //b为假 //得到子字符串 str2 = str1.substr(2,4); //从下标2开始的4个字符,str2为CDEF //查找子字符串 n = str1.find("DEF",pos); //从pos开始查找字符串"DEF"在str1中的位置,n为 3 //删除字符 str1.erase(3,5); //从下标3开始往后删5个字符,str1变为ABCIJK //增加字符 str1.append("12345",1,3); //在str1末尾增加"12345"下标从1开始的3个字符, 即"234" //字符串替换和插入操作 str1.replace(p0,n0,S1,n); //删除从p0开始的n0个字符,然后在p0处插入字符串 S1前n个字符 str1.replace(p0,n0,str2,pos,n); //删除从p0开始的n0个字符,然后在p0处插 入字符串str2中pos开始的前n个字符 str1.insert(p0,S1,n); //在p0位置插入字符串S1前n个字符 str1.insert(p0,str2,pos,n); //在p0位置插入字符串str2中pos开始的 前n个字符字符串对象数组 可以定义字符串对象数组,即数组元素是字符串对象,定义形式与 数组类似,例如:
string SY[5]={"Jiang","Cao","Zou","Liu","Wei"}; //定义字符串对象数组且初始化 string SY[5]={"123","12","1234","1","12345"}; //长度 3,2,4,1,5 char SA[5][20]={"123","12","1234","1","12345"}; //长度均是20