以下是代码:
char s[8];
int i = 0;
void **p = &s;
for (; i < 8; ++i) {
putchar( ((char*)(*p))[i] );
}
上面的代码可以工作,但给了一些垃圾字符。所以我所做的只是初始化s[8]
:
char s[8] = {0};
然后分段错误,但如果我使用VC ++编译并运行它,它可以正常工作。奇怪的。有人可以解释一下吗?谢谢!
更新: 很多人都说上面的代码是愚蠢的......这个更新适合你。原来是什么 代码看起来像:
static void*
copy_and_move(void **dst, int dsz, const void **src, int ssz) {
const int sz = ssz > dsz ? dsz : ssz;
memcpy(*dst, *src, sz);
return *dst + sz;
}
然后是主叫代码:
char d[10], s[8];
copy_and_move(&d, sizeof(char) * 10, &s, sizeof(char) * 8);
答案 0 :(得分:5)
让我们看看:
void **p = &s;
在那里,p
指向s
,也就是说,它包含s
的第一个字节的地址。
它是指向指针的指针,因此*p
被读作指针,它将使用s
的前n个字节,n等于sizeof(void*)
(4或8)。
然后你使用指针*p
来读取内存字节......
现在,哪些字节在s
的内存中,将被读取为内存地址?
{0]
,它们将全为零,因此*p
将是NULL指针和段错误。答案 1 :(得分:2)
您的表达式void **p = &s;
相当于void **p = &s[0];
。现在,后续的*p
会向您s[0]
提供((char*)(*p))[i]
s[0][i]
,*(((char*)0)+i)
为*(char*)NULL
,初始化后将等同于{{1}},或者,在第一次迭代时,{{1}} 1}}。
答案 2 :(得分:2)
void **p = &s;
将数组指针强制转换为指针指向void的指针是没有理由的。没有理由使用void**
。
所以代码没有任何意义,这就是它实际做的事情:
void **p = &s;
告诉程序数组的地址应该存储在指针变量中。该指针变量假定给出的地址依次指向另一个有效地址。这是不正确的。
(char*)(*p)
在这里,您可以获取指向指针的内容,并将其视为地址。但指针的内容是数组的实际数据。您正在调用未定义的行为。
(char*)(*p)[i]
在这里,您将获取任意随机垃圾地址并将其视为数组。这也是未定义的行为。
由于未定义的行为意味着任何可能发生,程序可能会崩溃或程序似乎正常工作。分析调用未定义行为时获得某个程序行为的原因没有意义。只需接受您的程序包含执行时可能会或可能不会检测到的错误,具体取决于编译器和系统。
答案 3 :(得分:1)
所以,正如你所说,
char s[8] = {0};
int i = 0;
void **p = &s;
for (; i < 8; ++i) {
putchar( ((char*)(*p))[i] );
}
的段错误。
你做的是
void **
指向原始char[]
void **
。我不知道它是否会受到伤害,但它不会太复杂,导致错误。
让我们仔细看看:
你做((char*)(*p))[i]
,我。即你取消引用p
- 它指向你的数组 - 将值存储在那里作为指针。为了获得字符,再次取消引用。
这是错误的。
除非您尝试某些内容,否则我建议
for (; i < 8; ++i) {
putchar(s[i]);
}
如果您想了解原始案例中发生的情况,我建议将其分解为部分:
char s[8] = {0};
int i = 0;
void **p = &s;
char * base = *p;
printf("&s: %p\n", &s);
printf("p: %p\n", p);
printf("*p: %p\n", *p); // be aware that even this might be undefined...
printf("base: %p\n", base);
for (; i < 8; ++i) {
putchar( base[i] ); // will lead to crash.
}
采用随机字节数并将它们视为指针是未定义的行为。
这里可能发生任何事情。在这种情况下,字节由所有NUL字节组成(s
在其整个长度上初始化为0),在原始情况下,数据未初始化并且运气包含有效指针(在堆栈上,这是可能会发生)。不过未定义。
答案 4 :(得分:0)
太多*
:p
保存数组的地址。 *p
取消引用该指针,并将数组内容解释为void *
。此指针包含垃圾,包括用于初始化的0
。所以你必须放弃一级*
:
void *p = &s;
for (; i < 8; ++i) {
putchar( ((char*)(p))[i] );
}
答案 5 :(得分:0)
作为
void ** p = &s; /* p points to an array of 8 char. */
丢失重要的类型信息,通过第一次,然后在之后取消引用来应用它,如下所示:
putchar( (*((char(*)[8]) p))[i] );
答案 6 :(得分:0)
正如评论中所解释的那样,这就是 sigfault 的原因:
How come an array's address is equal to its value in C?
简而言之:
如果您将数组声明为 静态 ,char array[N]
,数组和&amp;数组有相同的地址;
如果您将数组声明为 指针 ,char * array
,数组和&amp;数组有不同的地址;