程序:
#include<stdio.h>
int main(void) {
int x[4];
printf("%p\n", x);
printf("%p\n", x + 1);
printf("%p\n", &x);
printf("%p\n", &x + 1);
}
Run Code Online (Sandbox Code Playgroud)
输出:
$ ./a.out
0xbff93510
0xbff93514
0xbff93510
0xbff93520
$
Run Code Online (Sandbox Code Playgroud)
我希望以下是上述程序的输出.例如:
x // 0x100
x+1 // 0x104 Because x is an integer array
&x // 0x100 Address of array
&x+1 // 0x104
Run Code Online (Sandbox Code Playgroud)
但是最后一个陈述的输出与我预期的不同.&x也是数组的地址.因此,在此处递增1将打印地址递增4.但是&x+1地址递增10.为什么?
int* p = 0;
int* q = &*p;
Run Code Online (Sandbox Code Playgroud)
这是未定义的行为吗?我浏览了一些相关问题,但这个具体方面没有显示出来.
考虑:
int* ptr = (int*)0xDEADBEEF;
cout << (void*)&*ptr;
Run Code Online (Sandbox Code Playgroud)
*如果它与一个立即使用&并且假设没有超载op&/ 在场,那么它是多么违法op*?
(这对解决过去的数组元素有一个特殊的影响&myArray[n],这个表达式明确相当于&*(myArray+n).这个Q&A解决了更广泛的情况,但我不觉得它真的满足了上面的问题.)
我很擅长使用C++,并且没有掌握语言的所有复杂性和细微之处.
在C++ 11中向任何类型的指针添加任意字节偏移量的最便携,正确和安全的方法是什么?
SomeType* ptr;
int offset = 12345 /* bytes */;
ptr = ptr + offset; // <--
Run Code Online (Sandbox Code Playgroud)
我在Stack Overflow和Google上找到了很多答案,但他们都提出了不同的建议.我遇到的一些变种:
ptr = (SomeType*)(((char*)ptr) + offset);
Run Code Online (Sandbox Code Playgroud)演员unsigned int:
ptr = (SomeType*)((unsigned int)ptr) + offset);
Run Code Online (Sandbox Code Playgroud)ptr = (SomeType*)((size_t)ptr) + offset);
Run Code Online (Sandbox Code Playgroud)"大小size_t并且ptrdiff_t总是与指针的大小一致.因此,这些类型应该用作大型数组的索引,用于存储指针和指针算术." - 关于 CodeProject上的size_t和ptrdiff_t
ptr = (SomeType*)((size_t)ptr + (ptrdiff_t)offset);
Run Code Online (Sandbox Code Playgroud)或者像之前的那样,但是intptr_t代替的size_t是签名而不是签名的:
ptr = (SomeType*)((intptr_t)ptr + (ptrdiff_t)offset);
Run Code Online (Sandbox Code Playgroud)仅转换为intptr_t,因为offset已经是有符号整数而intptr_t …
int array[10];
int* a = array + 10; // well-defined
int* b = &array[10]; // not sure...
Run Code Online (Sandbox Code Playgroud)
最后一行是否有效?
假设我有一个函数,就像这样:
void mysort(int *arr, std::size_t size)
{
std::sort(&arr[0], &arr[size]);
}
int main()
{
int a[] = { 42, 314 };
mysort(a, 2);
}
Run Code Online (Sandbox Code Playgroud)
我的问题是:(mysort更具体地说,&arr[size])代码是否定义了行为?
我知道如果被替换为完全有效arr + size; 指针算法允许正常指向过去.不过,我的问题是关于具体的使用&和[].
Per C++ 11 5.2.1/1,arr[size]相当于*(arr + size).
引用5.3.1/1,一元的规则*:
一元运算
*符执行间接:它所应用的表达式应该是指向对象类型的指针,或指向函数类型的指针,结果是引用表达式指向的对象或函数 的左值.如果表达式的类型是"指向T",则结果的类型为"T."[ 注意:可以取消引用指向不完整类型(cvvoid除外)的指针.由此获得的左值可以以有限的方式使用(例如,初始化参考); 这个左值不能转换为prvalue,见4.1.- 尾注 ]
最后,5.3.1/3给出了以下规则&:
一元运算
& …
我一直在阅读K&R关于C的书,发现C中的指针算法允许访问超出数组末尾的一个元素.我知道C允许用记忆做几乎任何事情,但我只是不明白,这种特性的目的是什么?
我刚刚进入C++,我认为我有一个指针,但std::accumulate()让我感到困惑.
鉴于阵列:
int a[3] = { 5, 6, 7 };
Run Code Online (Sandbox Code Playgroud)
我想将数组的值加起来std::accumulate(),所以我将它传递给第一个元素,然后是最后一个,然后是累加器的起始值.
std::accumulate(a, a + 2, 0);
std::accumulate(&a[0], &a[2], 0);
Run Code Online (Sandbox Code Playgroud)
糟糕:其中任何一个都只返回前两个元素的总和:11.
另一方面,如果第二个参数是一个荒谬的指针,只是超出范围......
std::accumulate(a, a + 3, 0);
std::accumulate(&a[0], &a[3], 0);
Run Code Online (Sandbox Code Playgroud)
... 18返回正确的值.
有人可以解释一下吗?我意识到我可以避免使用简单的数组,但这不是重点.
在 C 中保持指针越界(不取消引用)以进行进一步的算术是否安全?
void f(int *array)
{
int *i = array - 1; // OOB
while(...) {
++i;
...
}
}
void g(int *array, int *end /* past-the-end pointer: OOB */)
{
while(array != end) {
...
++array;
}
}
Run Code Online (Sandbox Code Playgroud)
我想象一些极端情况,如果地址是内存的第一个或最后一个......