指针的基本概念

1.指针,变量的指针,指针变量

由于通过地址能找到所需的变量单元,因此可以说地址“指向该变量单元”。在C语言中,将地址形象化的称为“指针”,一个变量的地址称为该“变量的指针”,意思是通过它能找到以它为地址的内存单元。指针的值是指针本身存储的数值,这个值将被编译器当作一个地址,而不是一个一般的数值。

在32位程序里,所有类型的指针的值都是一个32位整数。因为32位机中的程序里内存地址全都是32位长,即sizeof(pointer)的值总为4—指针本身占据了4个字节的长度。在64位机中,sizeof(pointer)的值为8。

如果一个变量专门用来存放另一个变量的地址,则它称为“指针变量”,我们说它用来存放指针。定义了一个变量p,它用来保存另一个变量var的地址,这样的p就是指向var的指针变量。

指针变量也是变量,其定义格式为:类型标识符 *指针标识符。*号为地址解析符,表示“指向……的指针”,可以左结合,也可以右结合;其中类型标识符为指针所指向的类型。例如:

char *pc; pc具有char *类型,即pc指向char类型的变量,以1个字节为一个存取单元。

int *pi; pi具有int *类型,即pi指向int类型的变量,以4个字节为一个存取单元。

float* pf; pf具有float *类型,即pf指向float类型的变量,以4个字节为一个存取单元。

char *pc="hello";<==>char *pc;pc="hello";

2.指针变量的引用

C语言中对指针变量的引用主要通过运算符“&”和“*”来实现的。

&——取变量的地址,取指针。

*——取指针变量所指向的变量的值,解引用。

观察下面的程序段:

int x,y,*p; //定义整型变量x、y和整型指针变量p

x=168; //初始化x

p=&x; //初始化p,存储变量x的地址

y=*p; //初始化y,解引用p

上述内存变化情况如图所示:

int a=168;   int *p=&a;则*&a表示变量a本身,而&*p=&a,表示去变量a的地址。

3.指针的算术运算

指针是有类型的,故指针的算术运算(+,-)是以类型的size为单位“1”的偏移。

char型数组char cArray[5] = {1,2,3,4,5};,假设 char* pc = cArray(&cArray[0]),则“pc+1”表示偏移1个字节(sizeof(char))到下一个char,即指向cArray[1]=2。

short型数组short sArray[5] = {1,2,3,4,5};,假设short* ps = sArray(&sArray[0]),则“ps+2”表示偏移4个字节(2*sizeof(short))到下下一个short,即指向sArray[2]=3。

int型数组int iArray[5] = {1,2,3,4,5};,假设int* pi = iArray(&iArray[0]),则“pi+3”表示偏移12个字节(3*sizeof(int))到下下下一个int,即指向iArray[3]=4。   

int x,y,*p=&x;假设x,y,p顺序存放,则指针的自增自减归纳如下:

原操作

等价操作

y=*++p;

p=p+1;y=*p;

y=*p++;

y=*p;p=p+1;

y=(*p)++;

y=*p+1;

y=*(++p);

p=p+1;y=*p;

y=*--p;

p=p-1;y=*p;

y=*p--;

y=*p;p=p-1;

y=(*p)--;

y=*p-1;

y=*(--p);

p=p-1;y=*p;

 C 标准库 stddef.h 中定义了 offsetof 用于测算结构成员变量与结构起始地址的偏移量:

#define offsetof(type, member) /*implementation-defined*/

The "traditional" implementation of the macro relied on the compiler being not especially picky about pointers; it obtained the offset of a member by specifying a hypothetical structure that begins at address zero:

#define offsetof(st, m) \
     ((size_t) ( (char *)&((st *)(0))->m - (char *)0 ))

 其把常数 0 强制转换为结构体指针((st*)0),然后取其成员变量 m 的地址,强制转换成 char* 字节指针,再减去结构体起始地址((char*)0),即得到相对偏移量。

4.指针数组

指针数组和普通数组没什么区别,只不过其元素是指针。指针数组实际存储的是一系列和指针同类型变量的地址。

// 示例1
char c = 'H';
char *s ="Hello";
char str[] = "Hello";
char charArray[6] = {'H','e','l','l','o','\0'};
char *pChar[5];

pChar[0] = &c;
pChar[1] = "Hello";
pChar[2] = s;
pChar[3] = str;
pChar[4] = charArray;

//示例2
int *n0,n1,n2;
int *pInt[3];
pInt[0] = n0;
pInt[1] = &n1;
pInt[2] = &n2;

5.指针的指针

指针的指针本质还是指针,就是用来存放指针变量的地址。

对于返回二级指针的函数void** GetNextPtr(void* pNode);我们可以对返回结果进行操作:*GetNextPtr(pNode) = pHead;

我们可以用函数返回值来传递动态内存,例如void *malloc( size_t size );。但是试图用指针参数去申请内存是做不到的,只能用“指向指针的指针”。参考《高质量C++编程指南》第7章—内存管理—7.3.3 计算内存容量。

以下利用二级指针实现链表List的分槽存储:

typedef struct tagNode
{
    tagNode *pNext;
    int n;
    void **pData;
} List, *pList, *pThreadData;

pData 指向 void* pSlot[n] 数组首地址的地址:pData=&pSlot; 

实际上List可以存放任意大小任何类型的数据(包括类),在线程局部存储TLS中我们将见到这种分槽存储结构pThreadData。同时,我们也可以由此思考标准C++STL中的容器和MFC中afxtempl的实现机制。

参考:

《白话C++》南郁

内存和地址

指针

void类型指针在程序中的用途

二级指针的妙用

C++ Pointers

C/C++ Pointers

Pointers in C/C++ By Value,By reference, Pointer Arithmetic

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值