六、指针筑基期
?
?这一节,我们将使用指针来逛妖兽交易市场,快速掌握指针的进阶用法。
目录
六、指针筑基期
6.1 指针和数组
指针作为数组来使用
数组当成指针的合法使用
数组当成指针的非法使用
数组和指针“大小”的区别
?数组名,到底是什么
6.2 指针和const
自由指针-到处乱看,暴力砍价
指向常量的指针-佛系逛黑市,只看不还价
常量指针-看准一只妖兽,只为它而来
指向常量的常指针-不差钱的专一顾客
6.3 指向数组的指针
指向数组的指针的定义和基本使用
?指向数组的指针的加减法
6.4 函数的参数传递数组
函数的参数传递一维数组
函数的参数传递二维数组(4种方式)
6.5?函数返回数组
6.1 指针和数组
指针作为数组来使用
// 修仙界黑市中,1级到8级妖兽的价格
int prices[8] = { 100, 200, 500, 800, 1000, 2000, 5000, 10000 };
int* p = &prices[0]; //prices;
for (int i = 0; i < 8; i++) {
printf("第%d级妖兽的价格为:%d 灵石\n", i + 1, p[i]); //用数组的形式来使用指针
}
小结:对于指针p,? ?编译器把 p[i] 理解为: *(p+i)?
数组当成指针的合法使用 ?
// 修仙界黑市中,1级到8级妖兽的价格
int prices[8] = { 100, 200, 500, 800, 1000, 2000, 5000, 10000 };
*prices = 150; // 数组以指针的使用来使用
printf("%d\n", prices[0]); // 150
数组当成指针的非法使用
// 修仙界黑市中,1级到8级妖兽的价格
int prices[8] = { 100, 200, 500, 800, 1000, 2000, 5000, 10000 };
int x;
prices = &x; //数组名不能指向其它位置,类似于一个“特殊的常量指针”
数组和指针“大小”的区别
// 修仙界黑市中,1级到8级妖兽的价格
int prices[8] = { 100, 200, 500, 800, 1000, 2000, 5000, 10000 };
int* p = prices;
printf("%d, %d", sizeof(p), sizeof(prices));
// 输出 4,32 或者 8,32
// 在32位系统中(x86), 指针占用 4个字节的内存
// 在64位系统中(x64), 指针占用 8个字节的内存
?数组名,到底是什么
// 修仙界黑市中,1级到8级妖兽的价格
int prices[8] = { 100, 200, 500, 800, 1000, 2000, 5000, 10000 };
// 1. 数组名的值,就是该数组第0个成员的地址
printf("%x, %x\n", prices, &prices[0]);
// 2. 对于数据的访问,数组名,类似于一个常量指针, 不能改变指向
// 此时,p和prices很相似
int* const p = &prices[0]; //const的用法后面会详细讲解
// 3. 对于内存大小,数组和类型又不同
printf("%d, %d", sizeof(p), sizeof(prices));
6.2 指针和const
在修仙世界的妖兽黑市,使用指针逛黑市,配合const,可以得到不同的效果。
自由指针-到处乱看,暴力砍价
// 修仙界黑市中,1级到8级妖兽的价格
int prices[8] = { 100, 200, 500, 800, 1000, 2000, 5000, 10000 };
int* p = prices;
p += 2; // 改变指向
*p -= 100; //强行改变价格
printf("%d\n", *p); //400
指向常量的指针-佛系逛黑市,只看不还价
// 修仙界黑市中,1级到8级妖兽的价格
int prices[8] = { 100, 200, 500, 800, 1000, 2000, 5000, 10000 };
const int* p = prices;
p += 2; //可以改变p的指向
*p -= 100; //编译失败! 不能改变指向的内容
常量指针-看准一只妖兽,只为它而来
// 修仙界黑市中,1级到8级妖兽的价格
int prices[8] = { 100, 200, 500, 800, 1000, 2000, 5000, 10000 };
int * const p = prices;
p += 2; //编译失败!不可以改变指向
*p -= 50; //可以砍价(可以改变指向的数据)
指向常量的常指针-不差钱的专一顾客
// 修仙界黑市中,1级到8级妖兽的价格
int prices[8] = { 100, 200, 500, 800, 1000, 2000, 5000, 10000 };
const int * const p = prices;
p += 2; //编译失败!不可以改变指向
*p -= 50; //编译失败!不可以砍价,不可以改变指向的数据
6.3 指向数组的指针
我们一起来分析一下各个等级的修仙者的寿命,顺便掌握指向数组的用法。
下境界?
?练气期(吸纳天地灵气,入体化为元力,寿元可达至百来岁,可短时间御剑飞行) 筑基期(丹田为液态状,可辟谷,可达两百余岁,不能遁光,能长时间御剑飞行) 金丹期(丹田内有规则的圆形固态丹元,已辟谷,寿元可达五百载,可驾遁光飞行) 元婴期(破丹成婴,寿元可达千年岁月,遁光飞行,破体元婴可瞬移)
上境界?
化神期(体内元婴倍增,元婴向元神过渡,可超两千余年,掌握元力,可破元婴瞬移) 炼虚期(寿元可达近五千岁,体内元婴化为元神,返虚出本体,化为分身或众多分身) 合体期(分身与本体合二为一,达到返朴归真,可破炼虚万千化身,寿元可达上万年载) 大乘期(可达两万余年,熟练使用或自创神通,法力肉身已具备飞升条件,谌为修士大能)
指向数组的指针的定义和基本使用
int ages[2][4] = {
100, 200, 500, 1000, //ages[0] 下境界中4个等级的寿命数组
2000,5000,10000,20000 //ages[1] 上境界中4个等级的寿命数组
};
int(*p)[4];
//定义了一个指向数组的指针p
//p只能指向: 含有4个成员,每个成员都是int类型的数组
//注意语法,*必须在( )里面
p = &ages[0]; //ages
// 通过指向数组的指针,来访问数组内的成员
for (int i = 0; i < 4; i++) {
printf("%d ", (*p)[i]); // p[0][i]
}
// 指向数组的指针的大小
printf("\n %d %d \n", sizeof(p), sizeof(*p));
?指向数组的指针的加减法
int ages[2][4] = {
100, 200, 500, 1000, //ages[0] 下境界中4个等级的寿命数组
2000,5000,10000,20000 //ages[1] 上境界中4个等级的寿命数组
};
int(*p)[4] = &ages[0]; //ages
p++; // p指向了下一个数组!
printf("%d\n", (unsigned int)(p + 1) - (unsigned int)p); //16
for (int i = 0; i < 4; i++) {
printf("%d ", (*p)[i]); // 2000
}
6.4 函数的参数传递数组
函数的参数传递一维数组
计算1-8级妖兽的平均价格。
#include <stdio.h>
int calcAveragePrice1(int p[8]) {
// 特别注意:此时 p 不是真正的数组,实际上是一个指针 int *p
printf("%d\n", sizeof(p));
int s = 0;
for (int i = 0; i < 4; i++) {
s += p[i];
}
return s / 4;
}
int calcAveragePrice2(int p[], int n) {
int s = 0;
for (int i = 0; i < 4; i++) {
s += p[i];
}
return s / 4;
}
int calcAveragePrice3(int *p, int n) {
int s = 0;
for (int i = 0; i < 4; i++) {
s += p[i];
}
return s / 4;
}
int main(void) {
// 修仙界黑市中,1级到8级妖兽的价格
int prices[8] = { 100, 200, 500, 800, 1000, 2000, 5000, 10000 };
// 计算1-8级妖兽的平均价格
printf("%d\n", calcAveragePrice1(prices)); //ages;
printf("%d\n", calcAveragePrice2(prices, 8)); //ages;
printf("%d\n", calcAveragePrice2(prices, 8)); //ages;
return 0;
}
函数的参数传递二维数组(4种方式)
计算各阶修士的平均寿命。
#include <stdio.h>
int calcAverageAge1(int ages[2][4]) {
// 特别注意:此时 ages 不是真正的二维数组
// 实际上是一个指向一维数组的指针 int (*ages)[4]
printf("%d\n", sizeof(*ages));
int s = 0;
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 4; j++) {
s += ages[i][j];
}
}
return s / (2 * 4);
}
int calcAverageAge2(int ages[][4], int n) {
// 特别注意:此时ages 不是真正的数组
// 实际上是一个指向一维数组的指针 int (*ages)[4]
printf("%d\n", sizeof(*ages));
int s = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < 4; j++) {
s += ages[i][j]; // *(*(ages+i) + j)
}
}
return s / (2 * 4);
}
int calcAverageAge3(int(*ages)[4], int n) {
printf("%d\n", sizeof(*ages));
int s = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < 4; j++) {
s += ages[i][j]; // *(*(ages+i) + j)
}
}
return s / (2 * 4);
}
int calcAverageAge4(int* ages, int m, int n) {
int s = 0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
s += *(ages + i * n + j);
}
}
return s / (2 * 4);
}
int main(void) {
int ages[2][4] = {
100, 200, 500, 1000, //ages[0] 下境界中4个等级的寿命数组
2000,5000,10000,20000 //ages[1] 上境界中4个等级的寿命数组
};
printf("%d\n", calcAverageAge1(ages));
printf("%d\n", calcAverageAge2(ages, 2));
printf("%d\n", calcAverageAge3(ages, 2));
printf("%d\n", calcAverageAge4(ages, 2, 4));
return;
}
“C语言以及C++中,不能直接把二维数组(或更多维数组),作为一般形式的函数参数,你无法向函数传递一个普通的多维数组。” 引用自《C专家编程》第10章的第5节。
但是我们可以使用以上示例代码中4种形式来传递二维数组。
6.5?函数返回数组
定义一个函数,进行计算,返回一个数组,数组中包含各级妖兽的最低价格和最高价格,以及平均价格。
int(*calc(int prices[], int n))[3]{
int s = 0;
for (int i = 0; i < n; i++) {
s += prices[i];
}
int(*ret)[3]; // 定义一个指向数组的指针
ret = malloc(3 * sizeof(int));
(*ret)[0] = prices[0];
(*ret)[1] = prices[n - 1];
(*ret)[2] = s / n;
return ret;
}
int main(void) {
// 修仙界黑市中,1级到8级妖兽的价格
int prices[8] = { 100, 200, 500, 800, 1000, 2000, 5000, 10000 };
int(*p)[3] = calc(prices, 8);
printf("最低价格=%d, 最高价格=%d, 平均价格=%d", (*p)[0], (*p)[1], (*p)[2]);
return;
}
使用typedef 对指向数组的指针,进行优化:
typedef int(*threeValueArray_t)[3];
threeValueArray_t calc(int prices[], int n){
int s = 0;
for (int i = 0; i < n; i++) {
s += prices[i];
}
int(*ret)[3]; // 定义一个指向数组的指针
ret = malloc(3 * sizeof(int));
(*ret)[0] = prices[0];
(*ret)[1] = prices[n - 1];
(*ret)[2] = s / n;
return ret;
}
int main(void) {
// 修仙界黑市中,1级到8级妖兽的价格
int prices[8] = { 100, 200, 500, 800, 1000, 2000, 5000, 10000 };
threeValueArray_t p = calc(prices, 8);
printf("最低价格=%d, 最高价格=%d, 平均价格=%d", (*p)[0], (*p)[1], (*p)[2]);
return;
}
至此,我们以及掌握了指针的筑基期用法,马上将要进阶金丹期!
|