第八章 数组
重复是最好的老师Repetition is the best teacher
C语言提供一种可以由用户来设计一组相同数据类型的功能,这种数据类型就称之为数组。很多书中数组和指针是分开讲授的,我认为值得将这两个问题放在一起讨论,这是因为指针和数组的关系是很密切的,如果只讨论数组而不讨论指针将会使得学习不完整,感觉有所欠缺。事实上,所有的数组本质上都使用了指针。
8.1 ●一个数组是相同元素的集合。
●数组中第一个元素的编号是0。
●数组也可称为下标变量。
●使用数组前必须声明数组的类型和大小。
●不论数组有多大,它的元素总是存储在相邻的内存位置。
8.2 声明数组的时候对其进行初始化。
int num[6]={2,4,12,5,45,5};
int n[]={2,4,12,5,45,5};
float press[]={12.3,34,2,-23.4,-11.3};
说明:如果在声明数组的时候就进行了初始化,则数组的大小可以缺省。
8.3 将数组元素传递给函数的两种方法。
传值调用:将数组元素的值传给函数。
传引用调用:将数组元素的地址传给函数。
传值调用:
#include <stdio.h>
void display(int);
int main(void)
{
int i;
int marks[]={55,65,75,56,78,78,90};
for(i=0;i<=6;i++)
{
display(marks[i]);
}
}
void display(int m)
{
printf("%d",m);
}
传引用调用:
#include <stdio.h>
void display(int *);
int main(void)
{
int i;
int marks[]={55,65,75,56,78,78,90};
for(i=0;i<=6;i++)
{
display(&marks[i]);
}
}
void display(int *n)
{
printf("%d",*n);
}
8.4 指针可以进行下面的操作:
●指针值加上一个整数。
●指针值减去一个整数。
●指针值减去另一个指针值。
指针不可以进行下面的操作:
●将两个指针相加。
●将常数和指针相乘。
●将常数和指针相除。
8.5 j=&arr[4]
k=(arr+4)
j和k为数组中同一元素的地址。、
8.6 访问数组元素的两种方式:
●利用下标变量来访问数组元素:
#include <stdio.h>
int main(void)
{
int i;
int num[]={24,34,12,44,56,17};
for(i=0;i<=5;i++)
{
printf("address=%u",&num[i]);
printf("element=%d",num[i]);
}
}
●利用指针来访问数组元素:
#include <stdio.h>
int main(void)
{
int i,*j;
int num[]={24,34,12,44,56,17};
j=&num[0];
for(i=0;i<=5;i++)
{
printf("address=%u",j);
printf("element=%d",*j);
j++;
}
}
注意:利用指针来访问数组元素要比用下标来访问数组元素来得快。但是应注意以下几点:
①如果以固定的顺序来访问数组元素,就应该用指针来访问。例如,从开始到最后,或者从最后到开始,或者每隔一个元素,或者其它固定形式的访问。
②如果没以固定的顺序来访问数组元素,则使用下标来访问会更容易一些。
8.7 将整个数组传递给函数
#include <stdio.h>
void display(int *,int);
int main()
{
int num[]={24,34,12,44,56,17};
display(&num[0],6);
}
void display(int *j,int n)
{
int i;
for(i=0;i<=n-1;i++)
{
printf("element=%d",*j);
j++;
}
}
注意:
0元素的地址(常称为首地址)也可以通过数组来传递。因此,下面两个函数调用是相同的:
display(&num[0],6);
display(num,6);
由此可得,以下含义也是相同的:
num[i];
*(num+i);
*(i+num);
i[num];
思考:数组名a和变量名道理上是一样的,在编译时就和数组的首地址绑定上了,a就是数组的首地址,变量名和数组名其实都是方便人们记忆而取的代号,它在代码反汇 编后,其实不存在变量名的,回想下,访问数据有两种方式,既然反汇编后的代码不存在变量名,只能通过那种方式访问数据了,那就是地址。
8.8 二维数组stud[4][2]有4行2列
一般来说,数组元素是逐行存储和逐行访问的,因此,我们也会遵守这个约定。
8.9 一般来说,数组元素是逐行存储和逐行访问的。
8.10 初始化二维数组的两种方法
方法一:
int stud[4][2]={
{1234,56},
{1212,33},
{1434,80},
{1312,78}
};
方法二:
int stud[4][2]={1234,56,1212,33,1434,80,1312,78};
显然,方法一的可读性强。
注意:初始化一个二维数组时,必须给出列(第2维)的大小,而行(第1维)的大小可以缺省。
例:int arr[][3]={12,34,23,45,56,45};是正确的。
而 int [2][]={12,34,23,45,56,45};
int [][]={12,34,23,45,56,45};是错误的。
8.11 学习一维数组时,我们知道了num[i]与*(num+i)是相同的。由此推理可得,我们现在学习二维数组时要知道以下几个也是相同的:
s[2][1]
*(s[2]+1)
*(*(s+2)+1)
8.12 C语言具有独特而强大的功能——可以将数组的一部分作为数组来处理。更具体的说,就是二维数组的每一行都可以看成一维数组。如果想用指针来访问二维数组中的数组元素,这一点非常重要。
例如:int s[5][2],可以认为创建一个具有5个元素的数组,每个元素是包含2个整型数的一维数组。如果把s想象成是一个一维数组,那么它的第0个元素是s[0],下一个元素是s[1]。更确切的说,s[0]给出了第0个一维数组第0个元素的地址,s[1]给出了第一个一维数组第0个元素的地址。
举例如下:
#include <stdio.h>
int main(void)
{
int s[4][2]={
{1234,56},
{1212,33},
{1434,80},
{1312,78}
};
int i;
for(i=0;i<=3;i++)
{
printf("address of %d =%u",i,s[i]);
}
}
输出结果如下:
address of 0=65508
address of 1=65512
address of 2=65516
address of 3=65520
8.13 将二维数组传递给函数有三种方法,下面只介绍一种简单的方法,详情参考《let us c》第八版171页。
#include <stdio.h>
void print(int q[][4],int,int);
int main(void)
{
int a[3][4]={
1,2,3,4,
5,6,7,8,
9,0,1,6
};
print(a,3,4);
}
void print(int q[][4],int row,int col)
{
int i,j;
for(i=0;i<row;i++)
{
for(j=0;j<col;j++)
{
printf("%d",q[i][j]);
}
printf("\n");
}
}
数组指针也请参考《let us c》第八版,170页。