一.数组
数组由一系列类型相同的元素构成。可以使用声明告诉编译器你需要一个数组。
数组的声明中包括数组元素的数目和元素的类型。
1.初始化
含有12个元素的数组可以用来存储12个月的天数。
int days[12]={31,28,31,30,31,30,31,31,30,31,30,31};
数组的第一个元素为days[0],最后一个元素为days[11],没有day[12]这个元素。
如果出现 int days[12]={};这种初始化,代表12个元素的数值都为0.
若是int days[12]={31,28};则表示后面10个元素的数值为0.
#include <stdio.h>
#define MONTHS 12
int main(void)
{
int days[MONTHS] = {31,28,31,30,31,30,31,31,30,31,30,31};
int index;
for (index = 0; index < MONTHS; index++)
printf("Month %d has %2d days.\n", index +1,
days[index]);
return 0;
}
这个例子打印12个月的天数。例子中采用标识符常量来代表数组的大小,这样利
于我们修改程序。
如果我们进行了如下的声明:
const int days[MONTHS]={31,28,31,30,31,30,31,31,30,31,30,31};
这样,程序会把数组中的每个元素当做常量处理,无法改变,不能赋值。
#include <stdio.h>
#define SIZE 4
int main(void)
{
int no_data[SIZE];
int i;
printf("%2s%14s\n",
"i", "no_data[i]");
for (i = 0; i < SIZE; i++)
printf("%2d%14d\n", i, no_data[i]);
return 0;
}
和不同变量相似,在初始化之前数组元素的数值是不定的。
#include <stdio.h>
#define SIZE 4
int main(void)
{
int some_data[SIZE] = {1492, 1066};
int i;
printf("%2s%14s\n",
"i", "some_data[i]");
for (i = 0; i < SIZE; i++)
printf("%2d%14d\n", i, some_data[i]);
return 0;
}
初始化列表中的元素数目应该和数组大小一致。如果不一致,当数值数目少于数
组元素数目时,多余的元素初始化为0,当数值数目多余数组元素数目时,编译器
会认为这是一个错误。我们可以省略括号中的数字,让编译器自动匹配数组大小
和初始化列表中的项目数目。
#include <stdio.h>
#define MONTHS 12
int main(void)
{
int days[MONTHS] = {31,28,31,30,31,30,31,31,30,31,30,31};
int index;
for (index = 0; index < MONTHS; index++)
printf("Month %2d has %d days.\n", index +1,
*(days + index));
return 0;
}
需要注意的两点:
1.使用空括号进行初始化,编译器会根据列表中的数值数目来确定数组的大小。
2.使用for循环控制语句时,由于人工计算容易出错,可以让计算机来计算数组的
大小。
2.指定初始化项目
c99增加了一种新特性:指定初始化项目。此特性允许选择对某些元素进行初始化
。例如:int arr[6]={[5]=212};
#include <stdio.h>
#define MONTHS 12
int main(void)
{
int days[MONTHS] = {31,28, [4] = 31,30,31, [1] = 29};
int i;
for (i = 0; i < MONTHS; i++)
printf("%2d %d\n", i + 1, days[i]);
return 0;
}
从上述例子中可以看出,我们可以指定初始化元素,并且如果一个元素进行多次
初始化,那么最后一次的初始化有效。
3.赋值
c不支持把数组作为一个整体来进行赋值,也不支持用花括号括起来的列表形式进
行赋值,而应该采用循环的方法对元素逐个赋值。
4.边界
使用数组是,需要注意的是数组的索引不能超过数组的边界。
#include <stdio.h>
#define SIZE 4
int main(void)
{
int value1 = 44;
int arr[SIZE];
int value2 = 88;
int i;
printf("value1 = %d, value2 = %d\n", value1, value2);
for (i = -1; i <= SIZE; i++)
arr[i] = 2 * i + 1;
for (i = -1; i < 7; i++)
printf("%2d %d\n", i , arr[i]);
printf("value1 = %d, value2 = %d\n", value1, value2);
return 0;
}
以上程序就使用了错误的索引,如果使用那么程序执行结果将不可知。为了避免
这个问题的出现的比较简单的方法是使用符号常量。
二.多维数组
二位数组的声明方法:
float rain[5][12];
这个数组包含5个元素的数组,每一个元素又是一个包含12个元素的数组。即数组
是一个5行12列的数组。
#include <stdio.h>
#define MONTHS 12
#define YEARS 5
int main(void)
{
const float rain[YEARS][MONTHS] =
{
{4.3,4.3,4.3,3.0,2.0,1.2,0.2,0.2,0.4,2.4,3.5,6.6},
{8.5,8.2,1.2,1.6,2.4,0.0,5.2,0.9,0.3,0.9,1.4,7.3},
{9.1,8.5,6.7,4.3,2.1,0.8,0.2,0.2,1.1,2.3,6.1,8.4},
{7.2,9.9,8.4,3.3,1.2,0.8,0.4,0.0,0.6,1.7,4.3,6.2},
{7.6,5.6,3.8,2.8,3.8,0.2,0.0,0.0,0.0,1.3,2.6,5.2}
};
int year, month;
float subtot, total;
printf(" YEAR RAINFALL (inches)\n");
for (year = 0, total = 0; year < YEARS; year++)
{
for (month = 0, subtot = 0; month < MONTHS; month++)
subtot += rain[year][month];
printf("%5d %15.1f\n", 2000 + year, subtot);
total += subtot;
}
printf("\nThe yearly average is %.1f inches.\n\n",
total/YEARS);
printf("MONTHLY AVERAGES:\n\n");
printf(" Jan Feb Mar Apr May Jun Jul Aug Sep Oct ");
printf(" Nov Dec\n");
for (month = 0; month < MONTHS; month++)
{
for (year = 0, subtot =0; year < YEARS; year++)
subtot += rain[year][month];
printf("%4.1f ", subtot/YEARS);
}
printf("\n");
return 0;
}
这个一个二维数组以及他的应用。
二位数组的初始化:
const int rain [2][2]={
{1,3},
{4,5}
};
初始化使用了2个数组列表,每个数组列表都用花括号括起来。第一个列表被赋值
给数组的第一行,第二个列表被赋值给数组的第二行。初始化的时候也可以省略
内部花括号,只保留最外面的一对花括号,只要保证数值的个数正确即可。
对于更加多维的数组声明方法和二维一样:
int rain[10][20][30]
三.数组和指针
由于指针提供了一种用来使用地址的符号方法,使得指针能够类似计算机底层的
表达方式来表达自己的意愿,使得依赖指针能够更加高效的工作。特别的,指针
能够很有效地处理数组。例如:
flizny==&flizny[0]
数组名同时也是该数组首个元素的地址。
#include <stdio.h>
#define SIZE 4
int main(void)
{
short dates [SIZE];
short * pti;
short index;
double bills[SIZE];
double * ptf;
pti = dates;
ptf = bills;
printf("%23s %10s\n", "short", "double");
for (index = 0; index < SIZE; index ++)
printf("pointers + %d: %10p %10p\n",
index, pti + index, ptf + index);
return 0;
}
在c中对一个指针加1的结果是指对该指针增加一个存储单元。对于数组而言,地
址会增加到下一个元素的地址,而不是下一个字节。
#include <stdio.h>
int main(void)
{
const int days[] = {31,28,31,30,31,30,31,31,30,31};
int index;
for (index = 0; index < sizeof days / sizeof days[0]; index++)
printf("Month %2d has %d days.\n", index +1,
days[index]);
return 0;
}
上述例子中体现了c语言的优点,即例如
dates+2==&date[2] //相同的地址
*(dates+2)==dates[2] //相同的值
此外,days是数组首元素的地址,day+index是元素days[index]的地址,*
(days+index)是这个元素的值,与days[index]等价。
数组由一系列类型相同的元素构成。可以使用声明告诉编译器你需要一个数组。
数组的声明中包括数组元素的数目和元素的类型。
1.初始化
含有12个元素的数组可以用来存储12个月的天数。
int days[12]={31,28,31,30,31,30,31,31,30,31,30,31};
数组的第一个元素为days[0],最后一个元素为days[11],没有day[12]这个元素。
如果出现 int days[12]={};这种初始化,代表12个元素的数值都为0.
若是int days[12]={31,28};则表示后面10个元素的数值为0.
#include <stdio.h>
#define MONTHS 12
int main(void)
{
int days[MONTHS] = {31,28,31,30,31,30,31,31,30,31,30,31};
int index;
for (index = 0; index < MONTHS; index++)
printf("Month %d has %2d days.\n", index +1,
days[index]);
return 0;
}
这个例子打印12个月的天数。例子中采用标识符常量来代表数组的大小,这样利
于我们修改程序。
如果我们进行了如下的声明:
const int days[MONTHS]={31,28,31,30,31,30,31,31,30,31,30,31};
这样,程序会把数组中的每个元素当做常量处理,无法改变,不能赋值。
#include <stdio.h>
#define SIZE 4
int main(void)
{
int no_data[SIZE];
int i;
printf("%2s%14s\n",
"i", "no_data[i]");
for (i = 0; i < SIZE; i++)
printf("%2d%14d\n", i, no_data[i]);
return 0;
}
和不同变量相似,在初始化之前数组元素的数值是不定的。
#include <stdio.h>
#define SIZE 4
int main(void)
{
int some_data[SIZE] = {1492, 1066};
int i;
printf("%2s%14s\n",
"i", "some_data[i]");
for (i = 0; i < SIZE; i++)
printf("%2d%14d\n", i, some_data[i]);
return 0;
}
初始化列表中的元素数目应该和数组大小一致。如果不一致,当数值数目少于数
组元素数目时,多余的元素初始化为0,当数值数目多余数组元素数目时,编译器
会认为这是一个错误。我们可以省略括号中的数字,让编译器自动匹配数组大小
和初始化列表中的项目数目。
#include <stdio.h>
#define MONTHS 12
int main(void)
{
int days[MONTHS] = {31,28,31,30,31,30,31,31,30,31,30,31};
int index;
for (index = 0; index < MONTHS; index++)
printf("Month %2d has %d days.\n", index +1,
*(days + index));
return 0;
}
需要注意的两点:
1.使用空括号进行初始化,编译器会根据列表中的数值数目来确定数组的大小。
2.使用for循环控制语句时,由于人工计算容易出错,可以让计算机来计算数组的
大小。
2.指定初始化项目
c99增加了一种新特性:指定初始化项目。此特性允许选择对某些元素进行初始化
。例如:int arr[6]={[5]=212};
#include <stdio.h>
#define MONTHS 12
int main(void)
{
int days[MONTHS] = {31,28, [4] = 31,30,31, [1] = 29};
int i;
for (i = 0; i < MONTHS; i++)
printf("%2d %d\n", i + 1, days[i]);
return 0;
}
从上述例子中可以看出,我们可以指定初始化元素,并且如果一个元素进行多次
初始化,那么最后一次的初始化有效。
3.赋值
c不支持把数组作为一个整体来进行赋值,也不支持用花括号括起来的列表形式进
行赋值,而应该采用循环的方法对元素逐个赋值。
4.边界
使用数组是,需要注意的是数组的索引不能超过数组的边界。
#include <stdio.h>
#define SIZE 4
int main(void)
{
int value1 = 44;
int arr[SIZE];
int value2 = 88;
int i;
printf("value1 = %d, value2 = %d\n", value1, value2);
for (i = -1; i <= SIZE; i++)
arr[i] = 2 * i + 1;
for (i = -1; i < 7; i++)
printf("%2d %d\n", i , arr[i]);
printf("value1 = %d, value2 = %d\n", value1, value2);
return 0;
}
以上程序就使用了错误的索引,如果使用那么程序执行结果将不可知。为了避免
这个问题的出现的比较简单的方法是使用符号常量。
二.多维数组
二位数组的声明方法:
float rain[5][12];
这个数组包含5个元素的数组,每一个元素又是一个包含12个元素的数组。即数组
是一个5行12列的数组。
#include <stdio.h>
#define MONTHS 12
#define YEARS 5
int main(void)
{
const float rain[YEARS][MONTHS] =
{
{4.3,4.3,4.3,3.0,2.0,1.2,0.2,0.2,0.4,2.4,3.5,6.6},
{8.5,8.2,1.2,1.6,2.4,0.0,5.2,0.9,0.3,0.9,1.4,7.3},
{9.1,8.5,6.7,4.3,2.1,0.8,0.2,0.2,1.1,2.3,6.1,8.4},
{7.2,9.9,8.4,3.3,1.2,0.8,0.4,0.0,0.6,1.7,4.3,6.2},
{7.6,5.6,3.8,2.8,3.8,0.2,0.0,0.0,0.0,1.3,2.6,5.2}
};
int year, month;
float subtot, total;
printf(" YEAR RAINFALL (inches)\n");
for (year = 0, total = 0; year < YEARS; year++)
{
for (month = 0, subtot = 0; month < MONTHS; month++)
subtot += rain[year][month];
printf("%5d %15.1f\n", 2000 + year, subtot);
total += subtot;
}
printf("\nThe yearly average is %.1f inches.\n\n",
total/YEARS);
printf("MONTHLY AVERAGES:\n\n");
printf(" Jan Feb Mar Apr May Jun Jul Aug Sep Oct ");
printf(" Nov Dec\n");
for (month = 0; month < MONTHS; month++)
{
for (year = 0, subtot =0; year < YEARS; year++)
subtot += rain[year][month];
printf("%4.1f ", subtot/YEARS);
}
printf("\n");
return 0;
}
这个一个二维数组以及他的应用。
二位数组的初始化:
const int rain [2][2]={
{1,3},
{4,5}
};
初始化使用了2个数组列表,每个数组列表都用花括号括起来。第一个列表被赋值
给数组的第一行,第二个列表被赋值给数组的第二行。初始化的时候也可以省略
内部花括号,只保留最外面的一对花括号,只要保证数值的个数正确即可。
对于更加多维的数组声明方法和二维一样:
int rain[10][20][30]
三.数组和指针
由于指针提供了一种用来使用地址的符号方法,使得指针能够类似计算机底层的
表达方式来表达自己的意愿,使得依赖指针能够更加高效的工作。特别的,指针
能够很有效地处理数组。例如:
flizny==&flizny[0]
数组名同时也是该数组首个元素的地址。
#include <stdio.h>
#define SIZE 4
int main(void)
{
short dates [SIZE];
short * pti;
short index;
double bills[SIZE];
double * ptf;
pti = dates;
ptf = bills;
printf("%23s %10s\n", "short", "double");
for (index = 0; index < SIZE; index ++)
printf("pointers + %d: %10p %10p\n",
index, pti + index, ptf + index);
return 0;
}
在c中对一个指针加1的结果是指对该指针增加一个存储单元。对于数组而言,地
址会增加到下一个元素的地址,而不是下一个字节。
#include <stdio.h>
int main(void)
{
const int days[] = {31,28,31,30,31,30,31,31,30,31};
int index;
for (index = 0; index < sizeof days / sizeof days[0]; index++)
printf("Month %2d has %d days.\n", index +1,
days[index]);
return 0;
}
上述例子中体现了c语言的优点,即例如
dates+2==&date[2] //相同的地址
*(dates+2)==dates[2] //相同的值
此外,days是数组首元素的地址,day+index是元素days[index]的地址,*
(days+index)是这个元素的值,与days[index]等价。