首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用指向一个过去的malloc的指针是定义良好的吗?

使用指向一个过去的malloc的指针是定义良好的吗?
EN

Stack Overflow用户
提问于 2017-12-20 07:03:28
回答 4查看 4.1K关注 0票数 47

在C中,完全可以创建一个指针,它指向数组的最后一个元素,并在指针算术中使用它,只要您不取消引用它:

代码语言:javascript
复制
int a[5], *p = a+5, diff = p-a; // Well-defined

然而,这些都是瑞银:

代码语言:javascript
复制
p = a+6;
int b = *(a+5), diff = p-a; // Dereferencing and pointer arithmetic

现在我有一个问题:这是否适用于动态分配的内存?假设我只在指针算法中使用指向最后一个指针的指针,而没有取消引用,那么malloc()就成功了。

代码语言:javascript
复制
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?
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2017-12-20 08:05:38

使用指向一个过去的malloc的指针是定义良好的吗?

如果p指向已分配的内存,并且没有取消引用,则定义得很好。

n1570 -§6.5.6 (p8):

..。如果结果指向数组对象的最后一个元素,则不应将其用作计算的一元*操作符的操作数。

只有当指针指向同一个数组对象的元素或数组对象的最后一个元素时,减去两个指针才是有效的,否则将导致未定义的行为。

(p9)

当两个指针被减去时,两个指针都将指向同一个数组对象的元素,或者指向数组对象的最后一个元素.

上述引号适用于动态和静态分配的内存。

代码语言:javascript
复制
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_alloccallocmallocrealloc函数的连续调用分配的存储顺序和连续性未指定。如果分配成功,则返回的指针被适当地对齐,以便可以将其分配给具有基本对齐要求的任何类型对象的指针,然后用于访问这样一个对象或--分配空间中的此类对象的数组--(直到空间显式地被解除分配)。

malloc在上面的片段中返回的指针被分配给d,而分配的内存是一个由5个int对象组成的数组。

票数 23
EN

Stack Overflow用户

发布于 2017-12-20 07:18:14

用于n4296的C11草案明确指出,指向数组的指针定义得很好: 6.5.6语言/表达式/加法运算符:

§8当具有整数类型的表达式添加到指针或从指针中减去时,结果具有指针操作数的类型。..。此外,如果表达式P指向数组对象的最后一个元素,表达式(P)+1指向数组对象的最后一个元素,如果表达式Q指向数组对象的最后一个元素,则表达式(Q)-1指向数组对象的最后一个元素.如果结果指向数组对象的最后一个元素,则不应将其用作求值的一元*操作符的操作数。

由于该内存的类型从未在该分句中被加进,因此它适用于任何类型的内存,包括已分配的内存。

这显然意味着:

代码语言:javascript
复制
int *a = malloc(5 * sizeof(*a));
assert(a != NULL, "Memory allocation failed");

两者都有

代码语言:javascript
复制
int *p = a+5;
int diff = p-a;

定义得很好,并且随着通常的指针算术规则的应用,diff将接收值5

票数 26
EN

Stack Overflow用户

发布于 2017-12-20 08:10:49

是的,同样的规则适用于具有动态和自动存储持续时间的变量。它甚至适用于单个元素的malloc请求(在这方面,标量相当于一个元素数组)。

指针算法仅在数组中有效,包括数组结束后的一个。

关于取消引用,重要的是要注意一个问题:对于初始化int a[5] = {0};,编译器不能试图在表达式int* p = &a[5]中取消引用a[5];它必须再次将其编译为int* p = a + 5;,同样的事情也适用于动态存储。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47900466

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档