C Primer Plus阅读–章节9-10
函数原型
函数原型指明了函数的返回值类型和函数接受的参数类型,这些信息称为该函数的名。
对形式参数使用const
- 如果函数的意图不是修改数组中的数据内容,那么在函数原型和函数定义中声明的形式参数时应使用关键字const。
int sum(const int ar[], int n);
C99的指定数组初始化器
//该语句会初始化数组中第一个、第三个和第四个位置的的值,剩下位置为0
int arr[4] = {6, [2] = 212, [3] = 70};
//且arr为常量,不能做自增自减运算,如arr++不可以。
//未指定数组大小的,以下语句数组的大小为9,arr[7] = 7, arr[8] = 8
int arr[] = {3, [6] = 231, 7, 8};
int *ptr;
int torf[2][2] = {12,14,16};
ptr = torf[0];
//以上代码*(ptr + 2)的值为16
复合字面量
(int [2]){10, 20};
(int []){50, 20, 90} //内含3个元素
//使用方法
int * ptr1;
ptr1 = (int [2]){10, 20};
变长数组(VLA)
通过变量替代常量,声明数组
int m = 8;
int arr[m];
变长数组在声明的过程中也可以使用
int sum(int, int, int arr[*][*]);
二维数组
初始化
int arr[2][3] = {
{0, 3, 5},
{1, 2, 4}
};
或者
int arr[2][3] = {
0, 3, 5,
1, 2, 4
};
//数量能对应上就可以
数组和指针
int arr[8] = {0};
=>
arr == arr[0] == &arr[0][0]
int ar[]只能用于声明函数的形式参数,可以替代 int * ar
- *和++两个运算符的优先级相同,一般为从右至左的顺序进行计算
1.指针和多维数组
int i = 0;
int arr[2][4]= {
{0,1, 2, 3},
{4, 5, 6, 7}
};
printf("*(arr[0] + 1) = %d\n", *(arr[0] + 1));
printf("*(arr + 1) = %d\n", **(arr + 1));
printf("i:%p\n", &i);
printf("arr:%p\n", arr);
printf("arr[0]:%p\n", arr[0]);
printf("arr[0][0]:%p\n", arr);
printf("(arr + 1):%p\n", arr + 1);
printf("arr[1]:%p\n", arr[1]);
printf("arr[1][0]:%p\n", &arr[1][0]);
printf("arr[1][3]:%p", &arr[1][3]);
return 0;
//输出;
*(arr[0] + 1) = 1
*(arr + 1) = 4
i:000000000061FE1C
arr:000000000061FDF0
arr[0]:000000000061FDF0
arr[0][0]:000000000061FDF0
(arr + 1):000000000061FE00
arr[1]:000000000061FE00
arr[1][0]:000000000061FE00
arr[1][3]:000000000061FE0C
//实验二
int i = 0;
int b = 0;
int c = 0;
int d = 0;
int arr[2][4]= {
{0,1, 2, 3},
{4, 5, 6, 7}
};
printf("i:%p\n", &i);
printf("b:%p\n", &b);
printf("c:%p\n", &c);
printf("d:%p\n", &d);
printf("arr[0][0]:%p\n", &arr[0][0]);
printf("arr[0][1]:%p\n", &arr[0][1]);
printf("arr[0][2]:%p\n", &arr[0][2]);
printf("arr[0][3]:%p\n", &arr[0][3]);
printf("arr[1][0]:%p\n", &arr[1][0]);
printf("arr[1][1]:%p\n", &arr[1][1]);
printf("arr[1][2]:%p\n", &arr[1][2]);
printf("arr[1][3]:%p", &arr[1][3]);
return 0;
//结果:
i:000000000061FE1C
b:000000000061FE18
c:000000000061FE14
d:000000000061FE10
arr[0][0]:000000000061FDF0
arr[0][1]:000000000061FDF4
arr[0][2]:000000000061FDF8
arr[0][3]:000000000061FDFC
arr[1][0]:000000000061FE00
arr[1][1]:000000000061FE04
arr[1][2]:000000000061FE08
arr[1][3]:000000000061FE0C
- 由于栈空间是由高地址到低地增长的,所以变量i在栈的高地址:“61FE1C”, 由于本人的电脑是64位的,前面的0就补不了。
- 随后分析数组的存储方式,可以看到数组的最后一个元素的地址为"61FE0C",与变量i的地址相差了"10000",这数值的大小会随具体情况变化,在定义了四个变量之后,第四个变量与arr[1][3]相差4字节,也就是一个int类型的大小,在这个过程中arr的地址不会变。在增加为5个变量的时候,arr的地址开始变化。以上这个实验可以得出变量之间的距离不一定是固定的,同时数组进入栈空间的时候是先将高位写入高地址。
2.指向多维数组的指针
定义一个指向二维数组的指针
int (*pz)[2]; //指向内涵两个元素的数组
int * pax[2]; //一个包含两个int型指针的数组
3.注意事项
进行两级解引用的情况下是不安全的
const的其他内容
- 在前面提到的内容是const是用作define的替代,const可以使用的更加灵活。可以创建const数组、const指针和指向const的指针。
- 指向const的指针可以改变指向的位置,但不能改变指向位置中的值的内容。
double rates[5] = {88.99, 100.12, 56.0, 78,8, 66,8};
const double locked[4] = {0.08, 0.075, 0.0725, 0.07};
const double * pc = rates; //合法
pc = locked; //合法
pc = &rates[3]; //合法
可以将非const的数据赋值给const数据,但是不能把const数据赋值给非const数据。(书中提到,只能把非const数据的地址赋值给普通指针)