Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/65.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 取消引用包含对象地址的越界指针(数组的数组)_C_Arrays_Pointers_Language Lawyer_Memcpy - Fatal编程技术网

C 取消引用包含对象地址的越界指针(数组的数组)

C 取消引用包含对象地址的越界指针(数组的数组),c,arrays,pointers,language-lawyer,memcpy,C,Arrays,Pointers,Language Lawyer,Memcpy,对于REF的不同值,是否定义了以下各项 #include <stdio.h> #define REF 1 #define S 1 int main(void) { int a[2][S] = {{1},{2}}; int *q = REF ? a[1] : 0; int *p = a[0] + S; memcpy (&q, &p, sizeof q); printf ("q[0] = %d\n", q[0]); re

对于
REF
的不同值,是否定义了以下各项

#include <stdio.h>

#define REF 1
#define S 1

int main(void) {
    int a[2][S] = {{1},{2}};
    int *q = REF ? a[1] : 0;
    int *p = a[0] + S;
    memcpy (&q, &p, sizeof q);
    printf ("q[0] = %d\n", q[0]);
    return 0;
}
#包括
#定义参考1
#定义s1
内部主(空){
int a[2][S]={{1},{2};
int*q=REF?a[1]:0;
int*p=a[0]+S;
memcpy(q&p、q尺寸);
printf(“q[0]=%d\n”,q[0]);
返回0;
}
请注意,
p
指向
a[0]
最后一个元素的后面,而不是数组
a[0]
中的元素,因此不可取消引用。但是
p
中存储的地址是
a[1][0]
的地址
p在语义上(有意地)指向(好的,不在)
a[0]
但在物理上指向
a[1]

指针位模式的副本是否可以在语义上指向对象,而原始模式只能在物理上指向对象

另见

我用不同的“角度”问了本质上相同的C/C++问题:

  • (仅限C++语言)
指针位模式的副本能否在语义上指向 对象,而原始对象仅在物理上执行

实际上没有这样的区别,因为
a[0]+S
a[1]
相同,假设内部数组声明为
S
大小

以下是:

int a[2][S];
声明两个元素数组,其中每个元素都是
S
-类型为
int
的元素数组。数组是连续存储的,在其元素之前/之间/之后没有填充

我们将证明,
a[0]+S==a[1]
成立。它可以重写为:

*(a + 0) + S == *(a + 1)
通过指针运算,RHS将
1*sizeof(*a)
字节添加到
a
,这与内部数组的大小相同。LHS稍微复杂一些,因为加法是在
a
解引用后执行的,因此它增加了:

S*sizeof(**a)
bytes

当它们指向同一类型的同一对象(同一内存位置)时,保证两侧相等。因此,您可以将其改写为“绝对”单字节形式,如下所示:

(char *)a + S * sizeof(**a) == (char *)a + sizeof(*a)
这可归结为:

S * sizeof(**a) == sizeof(*a)
我们知道,子数组
*a
具有
S
类型为
**a
(即
int
)的元素,因此两个偏移量相同。Q.E.D.

已给出

int blah(int x, int y)
{
  int a[2][5];
  a[1][0] = x;
  a[0][y] = 9;
  return a[1][0];
}
标准中没有任何内容禁止编译器将其重新编码为
intblah(intx,inty){return x;}
,也不禁止在
y>=5
时捕获(或做任何事情),因为
a[0]
a[1]
是由五个元素组成的不同数组。在间接访问结构的最后一个元素是单元素数组的情况下,编译器通常包含允许该数组上的指针算法生成指向结构外部存储的指针的代码。虽然这种指针算法将被标准禁止,但它支持在C99之前无法以任何标准兼容方式实际实现的有用构造


请注意,将5添加到
a[0]
将生成一个与
a[1]
相同的
int*
,但“过去一次”指针与标识内存中下一个对象的指针进行比较的事实并不意味着可以安全地使用它访问后一个对象。这样的访问通常是有效的,但这并不意味着编译器必须让它们这样做。

a实际上不是数组数组数组,而是具有二维访问的数组。在这种情况下,内存将被分配为一个块,并在内部作为一维块处理。@SamiKuhmonen你是说只要我留在一个块内,就没有数组绑定?所以
a[0][1]
可以吗?我不认为这很好,因为它在语义上仍在进行,但使用原始指针可以连续访问内存。试图找到一个关于这个分配的文档如果你把一个指向一个数组,很可能还有其他变量!由于指针不可取消引用,您不必在意。@BoPersson这里我取消了对数组指针的引用,那里有一个对象,我的目的是更改它。我知道具有相同数值的指针可以具有不同的语义值,但我使用
memcpy
复制数值。
memcpy
magic吗?它能传递语义值吗?@curiousguy:现代编译器理论似乎表明,编译器可以自由地让
memcpy
memmove
携带指针的出处,也可以不带指针。据我所知,memcpy需要执行的唯一一种“清理”是解决与复制内容有关的任何严格的别名问题。给定
void*p=malloc(sizeof(long));长*lp=p;short*sp=p*lp=1234;memmove(sp、lp、sizeof(短));printf(“%d”,*sp)
memmove
将使对
*sp
的访问定义明确。如果没有
memmove
,这将是未定义的行为。请注意,
memcpy
将直接生成UB。