有没有对指针算术有良好文章或解释(博客,示例)?目标读者是一群学习C和C++的Java程序员。
有没有对指针算术有良好文章或解释(博客,示例)?目标读者是一群学习C和C++的Java程序员。
(a_pointer + a_number)
(a_pointer + (a_number * sizeof(*a_pointer)))
在普通算术中。
首先,binky 视频可能会有所帮助。这是一个关于指针的好视频。至于算术运算,这里有一个示例:
int * pa = NULL;
int * pb = NULL;
pa += 1; // pa++. behind the scenes, add sizeof(int) bytes
assert((pa - pb) == 1);
print_out(pa); // possibly outputs 0x4
print_out(pb); // possibly outputs 0x0 (if NULL is actually bit-wise 0x0)
(请注意,严格来说对包含null指针值的指针进行递增操作是未定义的行为。我们使用NULL是因为我们只关心指针的值。通常情况下,只有在指向数组元素时才使用递增/递减)。
以下展示了两个重要概念:
拿一个实际的例子来说。假设你写了一个函数,人们给你提供了一个起始指针和一个结束指针(在C++中非常常见):
void mutate_them(int *begin, int *end) {
// get the amount of elements
ptrdiff_t n = end - begin;
// allocate space for n elements to do something...
// then iterate. increment begin until it hits end
while(begin != end) {
// do something
begin++;
}
}
ptrdiff_t
是指 (end - begin) 的类型。在某些编译器中,它可能是 "int" 的同义词,但在另一个编译器中可能是另一种类型。由于不确定,所以选择使用通用的 typedef ptrdiff_t
。
我认为指针算术的一个很好的例子是下面的字符串长度函数:
int length(char *s)
{
char *str = s;
while(*str++);
return str - s;
}
有几种方法可以解决这个问题。
直觉的方法,这是大多数C/C++程序员想到的,即指针是内存地址。litb的例子采用了这种方法。如果你有一个空指针(在大多数机器上对应地址0),并且加上一个int的大小,你会得到地址4。这意味着指针基本上只是花哨的整数。
不幸的是,这种方法存在一些问题。首先,它可能行不通。 不能保证空指针实际上使用地址0。(尽管将常量0分配给指针会产生空指针)。
此外,您不允许增加空指针,或者更一般地说,指针必须始终指向已分配的内存(或一个元素之后),或特殊的空指针常量0。
因此,更正确的思考方式是指针只是迭代器,允许您迭代分配的内存。 这实际上是STL迭代器背后的关键思想之一。它们被建模为非常像指针,并提供专门化的补丁来使原始指针作为适当的迭代器工作。
例如,这里给出了更详细的解释here。
但是这种后一种观点意味着你应该真正解释STL迭代器,然后简单地说指针是这些迭代器的特殊情况。你可以增加一个指针以指向缓冲区中的下一个元素,就像你可以使用std::vector<int>::iterator
一样。它可以指向数组末尾的一个元素,就像任何其他容器中的结束迭代器一样。你可以减去两个指向同一缓冲区的指针,以得到它们之间的元素数量,就像你可以使用迭代器一样,如果指针指向不同的缓冲区,你不能有意义地比较它们。(对于为什么不能,请考虑在分段内存空间中会发生什么。两个指向不同段的指针之间的距离是多少?)
当然,在实践中,CPU地址和C/C++指针之间有非常密切的关联。但它们并不是完全相同的东西。指针有一些限制,在你的CPU上可能并不是严格必要的。
当然,大多数C++程序员都在第一种理解上混淆,即使它在技术上是不正确的。它通常足够接近你的代码最终的行为,人们认为他们理解了它,并继续前进。
但对于一个来自Java的人,刚开始学习指针的人来说,后一种解释可能同样容易理解,并且以后不会给他们带来太多惊喜。
while(*n++ != '\0'){
len++;
}
因为我们只是沿着字节一点一点地扫描,直到遇到零为止。希望这有所帮助!
这是一个关于指针算术的链接这里非常不错。
例如:
指针和数组
计算 ptr + i 的地址公式,其中 ptr 的类型为 T *。则地址公式为:
addr( ptr + i ) = addr( ptr ) + [ sizeof( T ) * i ]
对于32位平台上int类型,addr(ptr+i) = addr(ptr)+4*i;
减法
我们也可以计算ptr-i。例如,假设我们有一个名为arr的int数组。 int arr[ 10 ] ; int * p1, * p2 ;
p1 = arr + 3 ; // p1 == & arr[ 3 ]
p2 = p1 - 2 ; // p1 == & arr[ 1 ]
int
的大小(它应该是“自然”的整数类型)。 - Toby Speight