int a[10]; //a为包含10个整型数据的数组
int* p; //p为指向整型变量的指针变量
p = &a[0]; /*把a[0]元素的地址赋给指针变量p,
即让p指向a数组的第0号元素等价于p=a;*/
/*也可以写作:
int* p = &a[0]; or
int* p = a;*/
*p = 5; //通过p访问a[0],将数值5存入a[0]
指针的算术运算有且仅有三种:
指针加上整数、指针减去整数、两个指针相减
(1)指针加上整数
int a[10], * p, * q, i;
p = &a[2]; //p指向了a[2]
q = p + 2; //q指向了a[4]
p += 3; //p指向了a[5]
(2)指针减去整数
int a[10], * p, * q, i;
p = &a[8]; //p指向了a[8]
q = p - 2; //q指向了a[6]
p -= 3; //p指向了a[5]
(3)两个指针相减
int a[10], * p, * q, i, j;
p = &a[5]; //p指向了a[5]
q = &a[1]; //q指向了a[1]
i = p - q; //i=4
j = q - p; //j=-4
注:
如果p的初值为&a[0],则:
(1) p+i和a+i是a[i]的地址,即它们指向a[i]
(2) * (p+i )和 * (a+i)就是a[i]
(3) p[i]与*(p+i)等价
(4)指针可以用关系运算符和判等运算符进行比较:< <= >= >;== !=
比较的结果依赖于指针指向的元素的相对位置,例如
int a[10], * p, * q, i, j;
p = &a[5]; //p指向了a[5]
q = &a[1]; //q指向了a[1]
p <= q; //值为0
p > q; //值为1
(5)指针的算术运算只有当指针指向数据元素时,才有意义,对未指向数组元素的指针执行算术运算、或者对两个并非指向同一数组的指针做减法、做比较,都将导致未定义行为!
访问数组元素通常有两种方法:
(1)下标法:a[2];
(2)指针法:
*(a+2)或*(p+2)
例如,输出数组中的全部元素。其中整型数组a有10个元素,输出各元素的方法有三种:
(1)下标法
#include
int main()
{
int a[10], i;
for (i = 0; i < 10; i++)
scanf("%d", &a[i]);
for (i = 0; i < 10; i++)
printf("%d\n", a[i]);
return 0;
}
(2)通过数组名计算数组元素地址
#include
int main()
{
int a[10], i;
for (i = 0; i < 10; i++)
scanf("%d", &a[i]);
for (i = 0; i < 10; i++)
printf("%d ", *(a+i));
return 0;
}
上述代码第8行也可以改为
printf("%d ", *(p+i));
(3)用指针变量指向数组元素
#include
int main()
{
int a[10], i, * p;
for (i = 0; i < 10; i++)
scanf("%d", &a[i]);
for (p = a; p < a + 10; p++)
printf("%d ", *p);
return 0;
}
上述代码第6行可以改为
scanf("%d", p++);
分析:下面代码问题出在哪里?
#include
int main()
{
int i, a[10], * p = a;
for (i = 0; i < 10; i++)
scanf("%d", p++);
for (i = 0; i < 10; i++, p++)
printf("%d ", *p);
return 0;
}
输出结果:
回答:在数组输入部分结束后,指针*p的位置在a[10];所以后面输出部分p从a[11]位置开始输出,故出现问题。应如下改正:
#include
int main()
{
int i, a[10], * p = a;
for (i = 0; i < 10; i++)
scanf("%d", p++);
p = a;
for (i = 0; i < 10; i++, p++)
printf("%d ", *p);
return 0;
}
注:
*和++的几种组合(++的优先级高于*)
(1)*p++:*p++等价于*(p++);含义:自增前表达式的值为*p,然后自增p;
(2)*++p:*++p等价于*(++p);含义:先自增p,自增后表达式的值为*p;
(3)(*p)++:含义:自增前表达式的值为*p,然后自增*p;
(4)++(*p):含义:先自增*p,自增后表达式的值为*p;
区别:指针的自增 与 指针所指向的变量的自增
#include
void f(int arr[], int n);
int main()
{
int array[15] = { 1,2,3,4,5 };
f(array, 2);
return 0;
}
void f(int arr[], int n)
{
printf("%d\n", *arr);
arr += n;
printf("%d\n", *arr);
}
C编译系统将形参数组名作为指针变量来处理:
void f(int arr[], int n)
相当于
void f(int *arr, int n)
例,数组反向输出。
#include
void reverse(int x[], int n);
int main()
{
int i, a[10] = { 0,1,2,3,4,5,6,7,8,9 };
printf("数组顺序输出为:\n");
for (i = 0; i < 10; i++)
printf("%d, ", a[i]);
printf("\n");
reverse(a, 10);
printf("数组逆序输出为:\n");
for(i=0;i<10;i++)
printf("%d, ", a[i]);
printf("\n");
return 0;
}
void reverse(int x[], int n)
{
int i, j, temp, m = (n - 1) / 2;
for (i = 0; i <= m; i++)
{
j = n - i - 1;
temp = x[i];
x[i] = x[j];
x[j] = temp;
}
}
上述reverse函数还可以改写为:
void reverse(int* x, int n)
{
int* p, * i, * j, temp, m = (n - 1) / 2;
i = x;
j = x + n - 1;
p = x + m;
for (; i <= p; i++, j--)
temp = *i;
*i = *j;
*j = temp;
}
实参和形参的对应情况
(1)实参和形参都用数组名
void f(int x[], int n)
{
...
}
int main()
{
int a[10];
...
f(a, 10);
}
此时,数组a[i]对应x[i];
(2)实参用数组名,形参用指针变量
void f(int *x, int n)
{
...
}
int main()
{
int a[10];
...
f(a, 10);
}
此时,指针x指向a[0];
(3)实参和形参都用指针变量
void f(int *x, int n)
{
...
}
int main()
{
int a[10], * p = a;
...
f(p, 10);
}
此时,指针p,x指向a[0];
(4)实参用指针,形参用数组名
void f(int x[], int n)
{
...
}
int main()
{
int a[10], * p = a;
...
f(p, 10);
}
此时,指针p指向a[0],x[0];
例,用选择法对10个整数按由大到小顺序排序
#include
void sort(int x[],int n);
int main()
{
int i, * p, a[10];
p = a;
for (i = 0; i < 10; i++)
scanf("%d", p++);
p = a;
sort(p, 10);
for (p=a,i = 0; i < 10; i++, p++)
printf("%d, ", *p);
printf("\n");
return 0;
}
void sort(int x[], int n)
{
int i, j, k, t;
for (i = 0; i < n - 1; i++)
{
k = i;
for (j = i + 1; j < n; j++)
if (x[j] < x[k]) k = j;
t = x[i];
x[i] = x[k];
x[k] = t;
}
}
也可以用指针作形参:
void sort(int* x, int n)
{
int i, j, k, t;
for (i = 0; i < n - 1; i++)
{
k = i;
for (j = i + 1; j < n; j++)
if (*(x + j) > * (x + k)) k = j;
t = *(x + i);
*(x + i) = *(x + k);
*(x + k) = t;
}
}
8.5 指针与多维数组
设a是多维数组,则
a + i、&a[i] | 第i行的首地址 |
a[i]、*(a + i) | 第i行第0列元素的地址 |
* (a[i] + j)、* (*(a + i) + j) | a[i][j]的值 |
表示形式 | 含义 | 地址 |
---|---|---|
a | 二维数组名,即0行首地址 | 2000 |
a[0],*(a+0),*a | 0行0列元素a[0][0]的地址 | 2000 |
a+1,&a[1] | 1行首地址 | 2016 |
a[1],*(a+1) | 1行0列元素a[1][0]的地址 | 2016 |
a[1]+2, *(a+1)+2, &a[1][2] | 1行2列元素a[1][2]的地址 | 2024 |
* (a[1]+2), * (*(a+1)+2), a[1][2] | 1行2列元素a[1][2]的值 | 元素值为13 |
再看如下程序:
#include
int main()
{
int a[3][4] = { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23 };
int* p;
for (p = a[0]; p < a[0] + 12; p++)
{
if ((p - a[0]) % 4 == 0)
printf("\n");
printf("%4d", *p);
}
return 0;
}
指针p不是指向一个变量,而是指向一个包含m个元素的一维 数组。如果p先指向a[0](即p = &a[0]),则p+1指向a[1],p的增值是以一维数组的长度为单位。
用指向数组的指针作函数参数:
例,有一个班,3个学生,各学4门课,计算总平均分数及第n个学生的成绩。要求:
(1)用函数average求总平均成绩
(2)用函数search找出并输出第n个学生的成绩
#include
void average(float* p, int n);
void search(float(*p)[4], int n);
int main()
{
float score[3][4] = { {65,67,70,60},{80,87,90,81},{90,99,100,98} };
average(*score, 12);
search(score, 2);
return 0;
}
void average(float* p, int n)
{
float* p1;
float sum = 0, aver;
p1 = p + n - 1;
for (; p <= p1; p++)
sum += *p;
aver = sum / 12;
printf("average=%5.2f\n", aver);
}
void search(float(*p)[4], int n)
{
int i;
printf("The score of No .%d are:\n", n);
for (i = 0; i < 4; i++)
printf("%5.2f, ", *(*(p + n) + i));
}
例,在上题基础上,查找有一门以上课程不及格的学生,输出其全部课程的成绩。
#include
void search(float(*p)[4], int n);
int main()
{
float score[3][4] = { {65,57,70,60},{80,87,90,81},{90,99,100,98} };
search(score, 3);
return 0;
}
void search(float(*p)[4], int n)
{
int i, j, flag;
for (j = 0; j < n; j++)
{
flag = 0;
for (i = 0; i < 4; i++)
{
if (*(*(p + j) + i) < 60) flag = 1;
if (flag == 1)
{
printf("No.%d is fails, his scores are :\n", j+1);
for (i = 0; i < 4; i++)
{
printf("%5.1f ", *(*(p + j) + i));
}
printf("\n");
}
}
}
}