c 语言 指针差值,C语言指针可以相减吗?为什么?

本文解释了如何在C语言中使用指针算术来确定数组元素间的间距,通过实例展示了结构体数组中指针减法的应用,以及为何在不同地址空间中进行减法操作无效。重点讲解了`ptrdiff_t`类型的使用和指针转换的重要性。
摘要由CSDN通过智能技术生成

如果两个指针向同一个数组,它们就可以相减,其为结果为两个指针之间的元素数目。仍以本章开头介绍的街道地址的比喻为例,假设我住在第五大街118号,我的邻居住在第五大街124号,每家之间的地址间距是2(在我这一侧用连续的偶数作为街道地址),那么我的邻居家就是我家往前第(124-118)/2(或3)家(我和我的邻居家之间相隔两家,即120号和122号)。指针之间的减法运算和上述方法是相同的。

在折半查找的过程中,同样会用到上述减法运算。假设p和q指向的元素分别位于你要找的元素的前面和后面,那么(q-p)/2+p指向一个位于p和q之间的元素。如果(q-p)/2+p位于你要找的元素之前,下一步你就可以在(q-p)/2+p和q之间查找要找的元素;反之,你可以停止查找了。

如果两个指针不是指向一个数组,它们相减就没有意义。假设有人住在梅恩大街110号,我就不能将第五大街118号减去梅恩大街110号(并除以2),并以为这个人住在我家往回第4家中。

如果每个街区的街道地址都从一个100的倍数开始计算,并且同一条街的不同街区的地址起址各不相同,那么,你甚至不能将第五大街204号和第五大街120号相减,因为它们尽管位于同一条街,但所在的街区不同(对指针来说,就是所指向的数组不同)。

C本身无法防止非法的指针减法运算,即使其结果可能会给你的程序带来麻烦,C也不会给出任何提示或警告。

指针相减的结果是某种整类型的值,为此,ANSIC标准头文件中预定义了一个整类型ptrdiff_t。尽管在不同的编译程序中ptrdiff_t的类型可能各不相同(int或long或其它),但它们都适当地定义了ptrdiff_t类型。

例7.7演示了指针的减法运算。该例中有一个结构体数组,每个结构体的长度都是16字节。

如果是对指向结构体数组的指针进行减法运算,则a[0]和a[8]之间的距离为8;如果将指向结构体数组的指针强制转换成指向纯粹的内存地址的指针后再相减,则a[0]和aL8]之间的距离为128(即十六进制数0x80)。如果将指向a[8]的指针减去8,该指针所指向的位置并不是往前移了8个字节,而是往前移了8个数组元素。

注意:把指针强制转换成指向纯粹的内存地址的指针,通常就是转换成void *类型,但是,本例将指针强制转换成char *类型,因为void。类型的指针之间不能进行减法运算。

例 7.7 指针的算术运算

# include

# include

struct stuff {

char name[l6];

/ * other stuff could go here, too * /

};

struct stuff array [] = {

{ "The" },

{ "quick" },

{ "brown" >,

{ "fox" },

{ "jumped" },

{ "over" },

{ "the" },

{ "lazy" },

{ "dog. " },

/*

an empty string signifies the end;

not used in this program,

but without it, there'd be no way

to find the end (see FAQ IX. 4)

*/

{ " " }

};

main ( )

{

struct stuff * p0 = &.array[0];

struct stuff * p8 = &-array[8];

ptrdiff_t diff = p8-p0;

ptrdiff_t addr.diff = (char * ) p8 - (char * ) p0;

/*

cast the struct stuff pointers to void *

(which we know printf() can handles see FAQ VII. 28)

*/

printf ("&array[0] = p0 = %P\n" , (void* ) p0);

printf ("&. array[8] = p8 = %P\n" , (void* ) p8) ;

*/

cast the ptrdiff_t's to long's

(which we know printf () can handle)

*/

printf ("The difference of pointers is %ld\n" , (long) diff) ;

printf ("The difference of addresses is %ld\n" , (long) addr_diff);

printf ("p8-8 = %P\n" , (void*) (p8-8));

/ * example for FAQ VII. 8 * /

printf ("p0 + 8 = %P (same as p8)\n", (void* ) (p0 + 8));

return 0; / * see FAQ XVI. 4 * /

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值