1、什么是指针?
首先,回顾一下什么是变量?所谓程序变量,只是程序运行时某一段内存空间的别名,通过它可操作此段内存空间,但这不是唯一操作此段内存空间的办法,通过指针就是一个不错的选择!
示例:
#include <stdio.h>
int main()
{
int i=50;
int* p=&i;
printf("%d\t%08X\n",i,p);
*p=100;
printf("%d\t%08X\n",i,p);
return 0;
}
2、指针的本质是?
指针变量,应该都听过此称呼,可见指针变量本质上也是一个变量,具有变量的特征;所以,指针变量也有变量名,也需要占用一定的内存空间,该内存空间中存放的是当前指针要指向的内存单元的地址,指针变量本身也存在地址,因为它占用了内存空间;
分析如下示例:
#include <stdio.h>
int main()
{
int i=50;
int* p=&i;
printf("p的地址:%08X,p的值:%08X,p所指向的值:%d\n",&p,p,*p);
return 0;
}
仔细查看上述示例中的&p,p,*p,其实可以看出,指针变量p其实和普通变量而言就只多了一个*p的操作,其余操作完全一样!
那么,不同类型的指针所占内存大小是否一样呢?
分析如下示例:
#include <stdio.h>
typedef struct _t
{
int i;
char c;
double d;
} T;
int main()
{
char* pC=NULL;
int* pI=NULL;
short* pS=NULL;
double* pD=NULL;
long long* pL=NULL;
T* pT;
printf("%d\t%d\t%d\t%d\t%d\t%d\n",sizeof(pC),sizeof(pI),sizeof(pS),sizeof(pD),sizeof(pL),sizeof(pT));
return 0;
}
可见,上述无论什么类型,尽管是结构体,它的指针变量所占内存总是4个字节。
所以,指针本质上就是一个4字节的无符号整数,这个整数代表着一个内存单元,而这内存单元中存放的是什么类型的值,完全取决于这个指针指向了什么类型,所有类型数据的指针都是一个4字节的无符号整数!当然,这是在32位操作系统上,如果是64位操作系统,指针变量会占用8个字节!如果在64位操作系统上运行32位的程序,那么指针变量还会是4字节!
3、*号的意义
- 在指针声明时,*号表示所声明的变量为指针变量;
- 在指针使用时,*号表示取指针指向的内存空间中的值,这个操作也被称为解引用;
4、传值调用与传址调用
- 指针是变量,因此可以声明指针参数;
- 当一个函数体内部需要改变实参的值,则需要使用指针参数;
- 函数调用时实参值将复制到形参;
- 指针适用于复杂或者较大的数据类型作为参数时的函数中,比如一个大的数组和结构体等等;
5、指针小结
- 指针是C语言中一种特别的变量;
- 指针所保存的值是内存地址;
- 可以通过指针修改内存中任意地址的内容,只要能让指针指向该地址!
指针的另类使用:
示例:#include <stdio.h>
int main()
{
int i=50;
int* p=&i;
printf("i的值:%d,i的地址:0x%08X\t",*p,p);
return 0;
}
在Windows 下运行如上程序多次,你可能会发现,几次运行的结果中变量i的地址都是一样的:
虽然说不清楚为什么,可能是Windows 的优化,亦或是Windows的bug,反正可是试着利用一番,做如下的改动:
#include <stdio.h>
int main()
{
int i=50;
int* p=&i;
printf("i的值:%d,i的地址:0x%08X\t",*p,p);
*((int*)(0x0028FF18))=100;
printf("i的值:%d,i的地址:0x%08X\t",*p,p);
return 0;
}
这里的0x0028FF18是变量i几次运行的地址值,我们把它强制转换成一个int*型变量,然后改变它的值,效果和*p=100;一样;其实也很好理解,因为在程序中,指针变量p的值就是0x0028FF18,所以直接把这个地址值转换成一个int*型的变量后操作和原表达式等效!