在详细说指针之前,先来聊一聊,C语言中的变量到底是什么东西。所谓的变量,只不过是一段内存空间的别名,那么,我们是否能直接操作该地址呢,对于这个问题,就引入了指针。指针,可以将其理解为一个变量,只是该变量值为地址。下面我们先来看一段代码。
#include<stdio.h>
int main(){
int i =5;
int* p = &i;
printf("%p\n", &i);
printf("%p\n", p);
printf("%d\n", *p);
*p = 10;
printf("%d\n", i);
printf("%d\n", *p);
return 0;
}
[lin@bogon C]$ ./a.out
0x7fff0bdc2834
0x7fff0bdc2834
5
10
10
这里,就直接使用指针来改变变量i的值,而且从输出结果来看,p中存的值与变量i在内存中的地址一样的,说明咱们的分析是正确的。
在指针声明的时候,*号表示所声明变量为指针。而在指针使用时,*号表示指针所值内存空间的值。
指针是一种特殊的变量,在进行整数的运算规则是
n+p = (unsigned int)p + n * sizeof(*p);
下面,我们来验证一下是否真的如此。
#include<stdio.h>
int main(){
int a[5] = {1, 2, 3, 4};
int* p = a;
printf("%p\n", p);
printf("%p\n", p+1);
return 0;
}
[lin@bogon C]$ ./a.out
0x7fffc9a76690
0x7fffc9a76694
通过程序,我们看到结果却是如此。
指针之间只支持减法计算,而且,类型必须相同,两指针相减的意义为两指针所值元素的下角标。
p1-p2 = ((unsigned int)p1 - (unsigned int)p2)/sizeof(type);
让我们看一段代码,看事实是否如此。
#include<stdio.h>
int main(){
int a[5] = {1, 2, 3, 4};
int* p1 = a;
int* p2 = &a[2];
printf("%d\n", p2 - p1);
return 0;
}
[lin@bogon C]$ ./a.out
2
下面,我们来聊聊数组。数组就是内存中连续的一段空间,而且每个元素都是相同类型的。数组的元素个数可以通过显示或者隐式进行指定。
int a[5] = {1, 2, 3, 4}; //显示指定
int b[] = {5, 6, 7}; //隐式指定
下面,我们再看看以下的代码,是否发现什么有趣的地方。
#include<stdio.h>
int main(){
int a[5] = {1, 2, 3, 4}; printf("%p\n", a);
printf("%p\n", &a);
return 0;
}
[lin@bogon C]$ ./a.out
0x7fff6552d0c0
0x7fff6552d0c0
发现两种不同的方法对同一数组地址的获取,结果完全相同。那么两者到底有什么差别呢。原来,差别在于两者在内存中的所占据的大小不相同,通过数组名获取数组地址,在内存中只占据了sizeof(array_typr)的大小,反观通过取地址符号&对数组进行取值,其在内存中所占的大小为sizeof(array_tyoe)*array_size的大小。
在指针指向数组的情况下,指针能当数组名使用,数组名能当指针进行使用。让我们来看看代码。
#include<stdio.h>
int main(){
int a[5] = {1, 2, 3, 4, 5};
int* p1 = a;
int i = 0;
for(i=0; i<sizeof(a)/sizeof(*a); i++){
printf("%d\n", a[i]);
printf("%d\n", *(p1+i));
printf("%d\n", i[a]);
printf("%d\n", *(a+i));
}
return 0;
}
在让我们来看看结果
[lin@bogon C]$ ./a.out
1
1
1
1
2
2
2
2
3
3
3
3
4
4
4
4
5
5
5
5
我们可以得出结论
a[i] = *(p+i) = *(i+p) = i[a];