文章目录
自言自语
1. 数组
数组
由类型相同的一系列元素组成。
使用数组时,需要明确告诉编译器数组中的元素个数
和元素类型
。
有时需要把数组设置为只读。程序只能读取数据,而不能修改数据。
使用const
声明和创建只读数组:
const int arr[5] = {1, 2, 3, 4};
只能在声明的同时初始化const
数据,一旦声明为const数据之后就不能再赋值了。
当初始化列表中的值少于数组个数时,编译器会把剩余的元素初始化为 0
.
如果部分初始化数组,剩余 的元素也为0
;
如果不初始化数组,其中存储的值都是垃圾值。
int main(){
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;
}
-
如果初始化数组省略
[]
中的数字,编译器会根据初始化列表中的项数来确定数组的大小。 -
由于人工计算容易出错,所以让计算机来计算数组的大小。
sizeof(days) / sizeof(days[0]
就是整个数组的长度。因为sizeof
按字节给出运算对象的大小。sizeof(days)
是数组的总长度,sizeof(days[0]
是数组一个元素的长度。 -
int
型以4个字节为单位,所以数组days
有10个元素就有sizeof(days) = 40
个字节。sizeof(days[0] = 4
。所以数组长度为40 / 4 = 10
。
1.1 指定初始化器
C99新增特性:指定初始化器
该特性可以初始化指定的数组元素。
比如初始化最后一个元素,对于传统C的语法,必须初始化最后一个元素之前的所以元素,才能初始化它。
// 传统的语法
int arr[6] = {
0, 0, 0, 0, 0, 999};
// C99规定, 可以在初始化列表中使用带方括号下标指明待初始化的元素
int arr[6] = {
[5] = 999};
看下面的例子:
#define MONTHS 12
int days[MONTHS] = {
31, 28, [4] = 31, 30, 31, [1] = 29};
// 输出: 1~12月份分别为 31, 29, 28, 31, 30, 31, 0, 0, 0, 0, 0, 0
揭示了指定初始化器的两个重要特性:
- 如果指定初始化器后面有更多的值,如
[4] = 31, 30, 31
,那么后面的值将被用于初始化指定元素后面的元素,即第4个元素后面的第5,第6个元素。 - 如果再次初始化指定的元素,那么最后的初始化将会取代之前的初始化。比如
days[1] = 28
但是后面又被指定初始化[1] = 29
。
注意: 数组元素的编号从0开始。最好在声明数组时使用符号常量来表示数组的大小
2. 多维数组
float rain[5]
[12];
先来看其中的rain[5]
是一个有5个元素的数组,至于这5个元素的具体情况需要看其余部分(加粗的部分):
float
rain[5][12]
;
表示一个内含12个元素的数组。
说明每个元素的类型是float[12]
,也就是rain
的5个元素本身都是一个含义12个float类型值的数组。
2.1. 初始化二维数组
#define YEARS 4
#define MONTHS 12
const float rain[YEARS][MONTHS] =
{
{
1.4, 2.5, 2.1, ...}, // 剩余9个懒得写了
{
2.1, 2.2, 2.4, ...},
{
1.1, 1.5, 1.9, ...},
{
3.1, 3.4, 1.3, ...}
}
初始化时可以省略{}
,只保留最外面的一对{}
。只要保证初始化个数正确即可达到与上面相同的结果。
如果初始化数值不够,则按先后顺序进行初始化,直到用完所有的值,后面没有值初始化的则被初始化为0
。
2.2. 其他多维数组
可以这样声明一个三维数组:
int cube[10][20][15]
;
可以把一维数组想象成一行数据,二维数组想象成一张表,三维数组想象成一叠数据表。上面的三维数组box
想象成由10个二维数组(每个二维数组都是20行15列)堆叠起来。
3. 指针和数组
数组其实就是变相地在使用指针。
int fine[3] = {
1, 2, 3};
// fine = &fine[0]
数组名就是首元素的地址,fine
和&fine[0]
都是常量。在程序运行过程中不会改变。但是可以赋值给指针变量
,然后可以修改指针变量的值。
注意:++fine是错误的用法。因为前面说了,fine是一个常量,是数组首元素的地址。
#include <stdio.h>
#define SIZE (4)
int main()
{
short date[SIZE];
short * pti;
short index;
double bills[SIZE];
double * ptf;
pti = date;
ptf = bills;
printf("Hello OKfine.\n");
printf("%23s %15s\n", "short", "double");
for (index = 0; index < SIZE; index++)
{
printf("pointes + %d: %10p %10p\n",
index, pti + index, ptf + index);
}
return 0;
}
book@OKfine:~/c_primer_plus/ch10$ ./a.out
Hello OKfine.
short double
pointes + 0: 0x7ffe1fdaecb0 0x7ffe1fdaecc0
pointes + 1: 0x7ffe1fdaecb2 0x7ffe1fdaecc8
pointes + 2: 0x7ffe1fdaecb4 0x7ffe1fdaecd0
pointes + 3: 0x7ffe1fdaecb6 0x7ffe1fdaecd8
short
占2字节,double
占8字节。
在C中,指针加一指的是增加一个存储单元
。
比如,上面例子的运行结果中:
short
类型pti + 1
的结果从…b0 增加到了 …b2,即增加了2个字节。
double
类型ptf + 1
的结果从…c0增加到了…c8,即增加了8个字节。
- 指针的值是它所指向对象的地址。
- 在指针前面使用
*
运算符可以得到该指针所指向的对象的值 - 指针加1,指针的值递增它所指向对象的类型大小(以字节为单位)
*
间接运算符的优先级高于+
*dates + 2
=(*dates) + 2
4. 函数、数组和指针
注意:只有在函数原型或函数定义头中,才可以使用int ar[]
代替int * ar
int ar[]
和int * ar
这两种形式都表示 ar 是一个指向 int 的指针。
但是,int ar[]
只能用于声明形式参数。
下面的四种函数声明都是等价的。
int sum(int *ar, int n);
int sum(int *, int);
int sum(int ar[], int n);
int sum(int [], int n);
但是在函数定义的时候就不能省略参数名。
int sum(int *ar, int n)
{
// 。。。
}
int sum(int ar[], int n)
{
// 。。。
}
4.1. 使用指针形参
函数要处理数组必须知道何时开始、 何时结束。
sum()函数使用一个指针形参标识数组的开始, 用一个整数形参表明待处理数组的元素个数(指针形参也表明了数组中的数据类型)。但是这并不是给函数传递必备信息的唯一方法。
还有一种方法是传递两个指针, 第1个指针指明数组的开始处(与前面用法相同) , 第2个指针指明数组的结束处。 下面演示了这种方法, 同时该程序也表明了指针形参是变量, 这意味着可以用索引表明访问数组中的哪一个元素。
#include <stdio.h>
#define SIZE (10)
int sump(int * start, int * end);
int main()
{
int marbles[SIZE] = {
20, 10, 5, 6, 19, 32, 21, 11, 16, 8};
long answer;
answer = sump(marbles, marbles + SIZE);
printf("The total number of marbles is %ld.\n", answer);
return 0;
}
int sump(int * start, int * end)
{
int total = 0;
while(start < end)
{
/* 下面语句等效于:
* total += *start;
* start++;
*/
total += *(start++);
}
return total;
}
注意:while循环最后处理的一个元素是end所指向位置的前一个元素。
这意味着end指向的位置实际是在数组最后一个元素的后面。
C保证指向数组后面第一个位置的指针仍是有效地址。
在最后一次while循环中执行完start++
后,start的值就是end.
一元运算符*
和++
的优先级相同,但结合律是从右往左