● 基本概念
数组:数组是一组在内存中依次连续存放的(数组所有元素在内存中的地址是连续的)、具有同一类型的数据变量所组成的集合体。其中的每个变量称为数组元素,它们属于同一种数据类型,数组元素用数组名与带方括号的数组下标一起标识。数组可以是一维的,也可以是多维的。
数组的定义: 数据类型 数组名[常量表达式1][常量表达式2]; data_type array_name[constant_express_1][constant_expression_2] 数组名的两种含义:
当数组名是一个右值时, 它是一个指针常量; 当数组名在等号左边时, 它代表一个数组所占据的那块内存, 但数组名不可以被整体赋值, 即它不能作为左值, 只有数组的元素才能被分别赋值. 其实, 普通的数据类型也是如此, 如: int i = 6; a=i; i作为右值时, 它代表一个值, i作为右值时, 它代表i占据的内存.
左值和右值的三种解释: 第一种: ●左值: 可以放在赋值符号左边的变量,左值表示可由用户访问的内存单元,用户可以改变存储在其中的值, 左值相当于地址值. 右值:当一个符号或者常量放在操作符右边的时候,计算机就读取他们的"右值",也就是其代表的真实值,右值相当于数据值. 判断一个量是左值还是右值要根据该量赋值之后其本身还有无空间存储来判断。比如一个变量a,它可以作为左值和右值; 再比如一个const int a,它的值是只读的,就不能给它赋值,但并不代表它是个右值,右值是常量还是变量要看变量定义的类型。
第二种: 简单赋值运算符的使用格式: 左表达式 = 右表达式 其功能是将右表达式(右操作数)的值放到左表达式表示的内存单元中,因此左表达式一般是变量或表示某个地址的表达式,称为左值,在运算中作为地址使用。右表达式在赋值运算中是取其值使用,称为右值。所有赋值运算左表达式都要求是左值。
第三种: 简单来说: 左值就是那些能够出现在赋值符号左边的表达式。 右值就是那些可以出现赋值符号右边的表达式。 例如: a就是一个左值,因为它标识了一个可以存储结果值的地点,b + 25是个右值,因为它指定了一个值。但是它们可以互换吗? b + 25 = a; 原先用作左值的a此时也可以当作右值,因为每个位置都包含一个值。然而,b + 25不能作为左值,因为它并未标识一个特定的位置。因此,这条赋值语句是非法的。
L-value中的L指的是Location,表示可寻址-- a value that has an address. R-value中的R指的是Read,表示可读-- a value that does not have an address in a computer language. |
● 数组是一种类型
#include <iostream> using namespace std;
main() { int a[2][3]={1,2,3,4,5,6}; //声明并初始化二维数组 printf("%p ",a); printf("%p ",&a); printf("%p ",&a[0]); int **pp; } 可见a, &a, &a[0]都代表地址, 并且值相同, 但是它们的类型不同:△ pp=a; //错误,因为pp是一个int**型变量,a是一个int[2][3]型的地址 pp=&a; //错误,pp是一个int**型变量,&a是一个(*)int[2][3]型的地址 pp=&a[0]; //错误,pp是一个int**型变量,&a[0]是一个(*)int[3]型的地址 |
#include <iostream> using namespace std;
main() { int a[2][3]={1,2,3,4,5,6}; //声明并初始化二维数组 printf("%p ", a[0]+0); printf("%p ", a[0]+1); printf("%p ", a[0]+2); printf("%p ", a[1]+0); printf("%p ", a[1]+1); printf("%p ", a[1]+2); printf("________________ "); int *p_a[3]; //声明整型指针数组 p_a[0]=a[0]; //初始化指针数组元素, 在二维数组中, a[0]相当于a, 即&a[0][0] p_a[1]=a[1]; //a[1]即a[1]+0, 表第1行第0个元素的地址 p_a[1]=a[2]; //a[2]即a[2]+0, 表第2行第0个元素的地址 printf("%p ", p_a[0]); printf("%p ", p_a[1]); printf("%p ", p_a[1]); printf("________________ "); int **pp; pp=p_a; printf("%p ", &p_a[0]); printf("%p ", p_a); //p_a是一个数组(指针数组)名, 因此, 它的值是其第一个元素(存放着指针), 即p_a[0]的地址 } |
● 一维数组的声明 /引用 / 初始化, 语法
数据类型 数组名 [常量表达式] ={初值1, 初值2,…, 初值n};
例如,定义了一个数组int a[5]; 其内存排列(分配)示意图如下: |
#include <stdio.h>
int main() { int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; int b[] = { 1, 2, 3, 4, 5};//定义一个数组,初始化成员, 编译器能自动获得数组元素的个数 int c[10] = {1, 2, 3, 4, 5};//后面的值初始化为0 int *p=c; //x //int d[10] = { 0 };//将数组中所有的元素初始化为0 //a = 100;//这个语句不合法,因为数组的名字是一个常量,而不是一个变量(数组的名字表示数组首元素的地址) //a[3]//这才是一个变量 //&a[0];//取数组首元素的地址 //"%p" printf("%p ", &a[0]); //相当于printf("%x ", &a[0]);只是如果输出的结果如果左边有0, 会被删除 printf("%p ", a); printf("%d ", b[2]); printf("%d ", sizeof(b)); printf("%d ", sizeof(p)); return 0; } |
sizeof(b)的值为20, 数组b的指针p的大小, 即sizeof(p)为4, 说明数组名并不完全等同于指针, 只是它的值等于地址值 |
● 枚举类型的数组
注意下面这个枚举类型的数组, |
weekday b[10]; //定义了一个10个元素的枚举数组b,weekday为已定义的枚举类型, 数组b的元素的值只能为枚举常量的值. |
● 二维数组的声明 /引用 / 初始化
※ 二维数组是按行存放的, 例如数组int a[3][4]; 其长度是3*4=12: 行下标表达式与列下标表达式的值同样从0开始,a[i][j]表示数组的第i+1行、第j+1列的元素。由于数组元素是变量,可以对其进行各种各种操作。 数组元素如果定义数组a[m][n], 即数组第1维大小为n, 第2维大小为m。a[i][j]的排列位置与在内存中的地址计算公式如下: a[i][j]的排列位置=第1维大小n*i+j+1; a[i][j]的地址=a的起始地址+(第1维大小n*i+j)*sizeof(数据类型) 例如: a, a[0]: 为数组a的起始地址, 即a[0][0]的地址; a[i]+j: 为数组的第i+1行的第j+1元素的地址,即a[i][j]的地址; |
#include <iostream.h>
int main() { int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12}; //使用聚合方式赋值 /* 相当于如下的按元素赋值 a[0][0]=1 ;a[0][1]=2;a[0][2]=3;a[0][3]=4; a[1][0]=5;a[1][1]=6;a[1][2]=7;a[1][3]=8; a[2][0]=9;a[2][1]=1 0;a[2][2]=11 ;a[2][3]=12;*/ int b[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}}; //按行进行赋值 int c[3][4]={1,2,3,4}; //二维数组可以只对前几个元素赋值, 其余值为0 cout<<b[1][2]<<endl; b[1][2]=a[2][1]/2; //数组元素是左值, 可以对其赋值 cout<<b[1][2]<<endl; return 0; } |
● 多维数组
多维数组在内存的排列方式同样是先排低维数组,由低向高依次排列。 |
如:b[2][3][4]的排列顺序为: |
如:下列都是b[2][3][4]的地址表达式。 b[1]; //b[1][0][0]的地址; b[2]; //错误,下标越界; b[0]+1; //与b[0][1]相同,b[0][1][0]的地址。 b[1][2]; //b[1][2][0]的地址 b[1][2]+4; //b[1][2][4]的地址,但数组b中没有b[1][2][4]这个元素,故指向了其它地方。 |
● 数组与函数参数
当数组作函数参数时, 只传递数组的地址(指向该数组的第一个元素的指针), 而不是将整个数组赋值到函数中. 数组名是一个地址,不能当作一个左值,但是可以作为函数的形参,接受实参传送来的地址。 当形参接受实参传送来的地址后,形参数组与实参共享内存中的一块空间。函数体通过形参对数组内容的改变会直接作用到实参上。 注意: (1)使用数组名传递地址时,虽然传递的是地址,但形参与实参的地址 (数组)类型应一致。 (2)形式参数中数组元素个数没有给定,因此,在函数体中,对数组存取的下标可以为任意值而不会出现编译错误。但是,当这个下标超过了实参数组的元素个数范围时,存取的就不是实参数组中的内容了。 |
数组元素作为函数参数 |
#include<stdio.h>
void ShowMember(int iMember); /*声明函数*/
int main() { int count[10]; /*定义一个整型的数组*/ int i; /*定义整型变量,用于循环*/ for(i=0;i<10;i++) /*进行赋值循环*/ { count[i]=i; } for(i=0;i<10;i++) /*循环操作*/ { ShowMember(count[i]); /*执行输出函数操作*/ } return 0; }
void ShowMember(int member) /*函数定义*/ { printf("The member is %d ", member); /*输出数据*/ }
|
数组名作为函数参数 |
#include <stdio.h> #include <stdlib.h>
void test(int Array[], int len) //形参, 数组名[], 也可以这样:void test(int *Array , int len) { int i; for(i=0;i<len;i++) { printf( "num[%d]=%d ", i, i+1); } }
int main() { int MyArray[5]; test(MyArray, 5); //实参:数组名,目的是将数组的首地址传给test函数 system("pause"); return 0; } |
#include<stdio.h>
void Evaluate(int ArrayName[10]); /*声明赋值函数*/ void Display(int ArrayName[10]); /*声明显示函数*/
int main() { int Array[10]; /*定义一个具有10个元素的整型数组*/
Evaluate(Array); /*调用函数进行赋值操作,将数组名作为参数*/ Display(Array); /*调用函数进行赋值操作,将数组名作为参数*/ return 0; }
/* 进行数组元素的赋值 */
void Evaluate(int ArrayName[10]) { int i; for(i=0;i<10;i++) { ArrayName[i]=i; } }
/* 数组元素的显示 */
void Display(int ArrayName[10]) { int i; for(i=0;i<10;i++) { printf("the member is %d ",ArrayName[i]); } } |
可变长度数组作为函数参数 |
#include<stdio.h>
void Evaluate(int ArrayName[]); /*声明函数,参数为可变长度数组*/ void Display(int ArrayName[]); /*声明函数,参数为可变长度数组*/
int main() { int Array[10]; /*定义一个具有10个元素的整型数组*/
Evaluate(Array); /*调用函数进行赋值操作,将数组名作为参数*/ Display(Array); /*调用函数进行赋值操作,将数组名作为参数*/ return 0; }
/* 进行数组元素的赋值 */ void Evaluate(int ArrayName[]) /*定义函数,参数为可变长度数组*/ { int i; /*定义整型变量*/ for(i=0;i<10;i++) /*执行循环语句*/ { /*在循环语句中执行赋值操作*/ ArrayName[i]=i; } }
/* 数组元素的显示 */ void Display(int ArrayName[]) /*定义函数,参数为可变长度数组*/ { int i; /*定义整型变量*/ for(i=0;i<10;i++) /*执行循环的语句*/ { /*在循环语句中执行输出操作*/ printf("the member is %d ", ArrayName[i]); } }
|
使用指针作为函数参数 |
#include<stdio.h>
void Evaluate(int* p); /*声明函数,参数为可变长度数组*/ void Display(int* p); /*声明函数,参数为可变长度数组*/
int main() { int Array[10]; /*定义一个具有10个元素的整型数组*/
Evaluate(Array); /*调用函数进行赋值操作,将数组名作为参数*/ Display(Array); /*调用函数进行赋值操作,将数组名作为参数*/ return 0; }
/* 进行数组元素的赋值 */ void Evaluate(int* p) /*定义函数,参数为可变长度数组*/ { int i; /*定义整型变量*/ for(i=0;i<10;i++) /*执行循环语句*/ { /*在循环语句中执行赋值操作*/ p[i]=i; } }
/* 数组元素的显示 */ void Display(int* p) /*定义函数,参数为可变长度数组*/ { int i; /*定义整型变量*/ for(i=0;i<10;i++) /*执行循环的语句*/ { /*在循环语句中执行输出操作*/ printf("the member is %d ",p[i]); } }
|
● 字符数组和字符串
字符数组: 每个元素是字符的数组; 字符数组也分为一维数组和多维数组。 字符串: C语言将字符串作为字符数组来处理, 以字符' |