毫无疑问,指针是C语言中最强大的工具之一,但它们也是最令人困惑的话题。 上面我们说了什么是指针,指针的定义,以及对指针的深入理解。 我们这篇文章继续讲指针和数组的结合。 在C语言中,指针和数组密切相关,所有通过数组下标完成的操作都可以用指针来实现。
1. 与指针相关的算术运算
对指针的操作就是对地址的操作。 由于这个特性,指针运算与普通变量不同,它只允许有限次数的运算。
int a = 3, *p1, *p2;
p1 = &a; //p1 指向 a
p2 = p1; //p2 也指向 a
注意:只有相同类型的指针才能互相赋值
对于指针的操作,请参考下面的代码示例:
#include
int main()
{double arr[4] = {1.5, 2, 3, 4};
double *p;
p = &arr[0];
printf("p中存储的值:%p\n", p);
printf("p所指变量的值:%.1f\n\n", *p);
p = p + 1;
printf("p自增1后:\n");
printf("p中存储的值:%p\n", p);
printf("p所指变量的值:%.1f\n", *p);
}
运行结果:
思考分析上面的例子:p:的值,就是a[0]的地址; p+1:, 的值是a[1]的地址。 为什么指针加1,地址加8?
注意:因为p是指向真实数据的指针,所以一个元素占用8个字节。 编译器知道向指针加 1 意味着访问该类型的下一个元素。 这就是为什么在声明指针时必须指定指针指向的变量的类型。
2. 指针和数组的关系
整数a[100]; 系统分配一块可以存储100个整数的内存空间,并将其标记为a。 通过数组名可以知道内存空间的大小。 (“%u”,(a)); 将输出400。
数组名代表一个地址——数组第一个元素的地址,数组名a是一个指向a[0]的指针。 *a 是对 a[0] 的引用,("%d ", *a); 将输出a[0]的值。
因此,对于数组int a[100]; a 是指向第一个元素(下标 0)的指针。 a+i是指向下标i的元素的指针,*(a+i)是对下标i的元素的引用。
注意:任何可以用数组下标完成的操作都可以用指针完成。 如下面的代码示例:
输入n和n个整数,将n个整数倒序输出。 要求实现无下标的数组操作。
# include
int main()
{ int i, n, a[10], sum = 0;
scanf ("%d", &n);
for(i = 0; i < n; i++)
scanf("%d", a+i);
for(i=n-1; i>=0; i--)
printf("%d ", *(a+i) );
printf("\n");
return 0;
}
运行结果:
上面代码中,a+i是a[i]的地址,即&a[i]; *(a+i) 是对 a[i] 的引用。
3.数组作为函数参数的本质
当数组名作为实参时,由于数组名是指针常量,所以形参应该是指针变量,与实参类型相同。 请看下面的示例代码——该函数实现了数组的求和:
# include
int sum (int *arr, int n)
{ int i, s = 0;
for(i=0; i
s += arr[i];
return(s);
}
int main(void )
{ int i;
int b[5] = {1, 4, 5, 7, 9};
printf("%d\n", sum(b, 5) );
return 0;
}
运行结果:
我们再看另一个例子——将数组元素逆序存储(注意逆序存储和逆序输出是不同的),继续理解数组作为参数的本质:
int main(void)
{ int i, a[10],n;
void reverse(int p[ ], int n);
scanf("%d", &n);
for(i = 0; i < n; i++)
scanf("%d", &a[i]);
reverse(a, n);
for(i = 0; i < n; i++)
printf("%d\t", a[i]);
return 0;
}
void reverse(int p[ ], int n)
{ int i, j, t;
for(i=0, j=n-1; i
{
t = p[i]; p[i] = p[j]; p[j] = t;
}
}
运行结果:
请先点击观看,然后在公众号回复“C教程”即可获取全部完整资源~
上一篇文章相关:
portant;overflow-wrap: break-word !important;">不错,点个在看吧