c_primer_plus_CH10

本文介绍了C语言中的数组,包括数组的定义、初始化以及只读数组的使用。详细讲解了指定初始化器的C99特性,以及多维数组的初始化,特别是二维数组和部分初始化的情况。同时,探讨了指针与数组的关系,如何在函数中处理数组,以及如何使用指针形参传递数组信息。此外,文章还提到了`const`在指针中的应用,指向多维数组的指针,变长数组(VLA)的特性,以及复合字面量在初始化数组时的作用。
摘要由CSDN通过智能技术生成

自言自语

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;
}
  1. 如果初始化数组省略[]中的数字,编译器会根据初始化列表中的项数来确定数组的大小。

  2. 由于人工计算容易出错,所以让计算机来计算数组的大小。
    sizeof(days) / sizeof(days[0]就是整个数组的长度。因为sizeof按字节给出运算对象的大小。sizeof(days)是数组的总长度,sizeof(days[0]是数组一个元素的长度。

  3. 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

揭示了指定初始化器的两个重要特性:

  1. 如果指定初始化器后面有更多的值,如[4] = 31, 30, 31,那么后面的值将被用于初始化指定元素后面的元素,即第4个元素后面的第5,第6个元素。
  2. 如果再次初始化指定的元素,那么最后的初始化将会取代之前的初始化。比如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.

一元运算符*++的优先级相同,但结合律是从右往左࿰

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值