在C中,完全可以创建一个指针,它指向数组的最后一个元素,并在指针算术中使用它,只要您不取消引用它:
int a[5], *p = a+5, diff = p-a; // Well-defined然而,这些都是瑞银:
p = a+6;
int b = *(a+5), diff = p-a; // Dereferencing and pointer arithmetic现在我有一个问题:这是否适用于动态分配的内存?假设我只在指针算法中使用指向最后一个指针的指针,而没有取消引用,那么malloc()就成功了。
int *a = malloc(5 * sizeof(*a));
assert(a != NULL, "Memory allocation failed");
// Question:
int *p = a+5;
int diff = p-a; // Use in pointer arithmetic?发布于 2017-12-20 08:05:38
使用指向一个过去的malloc的指针是定义良好的吗?
如果p指向已分配的内存,并且没有取消引用,则定义得很好。
n1570 -§6.5.6 (p8):
..。如果结果指向数组对象的最后一个元素,则不应将其用作计算的一元
*操作符的操作数。
只有当指针指向同一个数组对象的元素或数组对象的最后一个元素时,减去两个指针才是有效的,否则将导致未定义的行为。
(p9):
当两个指针被减去时,两个指针都将指向同一个数组对象的元素,或者指向数组对象的最后一个元素.
上述引号适用于动态和静态分配的内存。
int a[5];
ptrdiff_t diff = &a[5] - &a[0]; // Well-defined
int *d = malloc(5 * sizeof(*d));
assert(d != NULL, "Memory allocation failed");
diff = &d[5] - &d[0]; // Well-defined正如乔纳森·莱弗勒在评论中指出的那样,这对于动态分配内存有效的另一个原因是:
§7.22.3 (p1):
对
aligned_alloc、calloc、malloc和realloc函数的连续调用分配的存储顺序和连续性未指定。如果分配成功,则返回的指针被适当地对齐,以便可以将其分配给具有基本对齐要求的任何类型对象的指针,然后用于访问这样一个对象或--分配空间中的此类对象的数组--(直到空间显式地被解除分配)。
malloc在上面的片段中返回的指针被分配给d,而分配的内存是一个由5个int对象组成的数组。
发布于 2017-12-20 07:18:14
用于n4296的C11草案明确指出,指向数组的指针定义得很好: 6.5.6语言/表达式/加法运算符:
§8当具有整数类型的表达式添加到指针或从指针中减去时,结果具有指针操作数的类型。..。此外,如果表达式P指向数组对象的最后一个元素,表达式(P)+1指向数组对象的最后一个元素,如果表达式Q指向数组对象的最后一个元素,则表达式(Q)-1指向数组对象的最后一个元素.如果结果指向数组对象的最后一个元素,则不应将其用作求值的一元*操作符的操作数。
由于该内存的类型从未在该分句中被加进,因此它适用于任何类型的内存,包括已分配的内存。
这显然意味着:
int *a = malloc(5 * sizeof(*a));
assert(a != NULL, "Memory allocation failed");两者都有
int *p = a+5;
int diff = p-a;定义得很好,并且随着通常的指针算术规则的应用,diff将接收值5。
发布于 2017-12-20 08:10:49
是的,同样的规则适用于具有动态和自动存储持续时间的变量。它甚至适用于单个元素的malloc请求(在这方面,标量相当于一个元素数组)。
指针算法仅在数组中有效,包括数组结束后的一个。
关于取消引用,重要的是要注意一个问题:对于初始化int a[5] = {0};,编译器不能试图在表达式int* p = &a[5]中取消引用a[5];它必须再次将其编译为int* p = a + 5;,同样的事情也适用于动态存储。
https://stackoverflow.com/questions/47900466
复制相似问题