0

实际上,当我使用指向字符的指针时,memcpy 工作得很好,但是当我使用指向字符的指针时停止工作。

有人可以帮我理解为什么 memcpy 在这里失败,或者更好的是,我怎么能自己弄清楚。我发现很难理解我的 c/c++ 代码中出现的问题。

char *pc = "abcd";
char **ppc = &pc;
char **ppc2 = &pc;
setStaticAndDynamicPointers(ppc, ppc2);

char c;
c = (*ppc)[1];  
assert(c == 'b');                     // assertion doesn't fail.

memcpy(&c,&(*ppc[1]),1);

if(c!='b')
  puts("memcpy didn't work.");  // this gets printed out.

c = (*ppc2)[3];
assert(c=='d');                      // assertion doesn't fail.
memcpy(&c, &(*ppc2[3]), 1);

if(c != 'd')
  puts("memcpy didn't work again.");

memcpy(&c, pc, 1);
assert(c == 'a');   // assertion doesn't fail, even though used memcpy

void setStaticAndDynamicPointers(char **charIn, char **charIn2)
{
  // sets the first arg to a pointer to static memory.
  // sets the second arg to a pointer to dynamic memory.
  char stat[5];
  memcpy(stat, "abcd", 5);
  *charIn = stat;

  char *dyn = new char[5];
  memcpy(dyn, "abcd", 5);
  *charIn2 = dyn;
}
4

7 回答 7

4

您的评论暗示char stat[5]应该是静态的,但事实并非如此。结果charIn指向一个分配在堆栈上的块,当您从函数返回时,它超出了范围。你的意思是static char stat[5]

于 2010-11-01T20:38:35.263 回答
0

char stat[5];

是超出范围的堆栈变量,它不是 // sets the first arg to a pointer to static memory.. 您需要 malloc/new 一些将 abcd 放入其中的内存。就像你为charIn2

于 2010-11-01T20:37:03.820 回答
0

请注意,赋值语句中表达式中的括号与 memcpy 表达式中的括号位于不同的位置。所以他们做不同的事情也就不足为奇了。

于 2010-11-01T21:05:15.330 回答
0

就像 Preet 所说的那样,我认为问题不在于 memcpy。在您的函数“setStaticAndDynamicPointers”中,您正在设置一个指向在该函数调用的堆栈上创建的自动变量的指针。到函数退出时,“stat”变量指向的内存将不复存在。结果,第一个参数 **charIn 将指向不存在的东西。也许您可以在这里阅读有关堆栈框架(或激活记录)的更详细信息:链接文本

您已经在该代码中有效地创建了一个指向堆栈变量的悬空指针。如果您想测试将值复制到堆栈变量中,请确保它是在调用者函数中创建的,而不是在被调用函数中。

于 2010-11-01T20:55:13.263 回答
0

除了 'stat' 的定义,我眼中的主要问题是*ppc[3](*ppc)[3]. 您想要的是后者(ppc 指向的字符串中的第四个字符),但是在您的 memcpy()s 中您使用前者,即“字符串数组” ppc 中第四个字符串的第一个字符(显然 ppc 不是的数组char*,但您强制编译器将其视为这样)。

在调试此类问题时,我通常发现打印所涉及的内存地址和内容很有帮助。

于 2010-11-01T20:57:54.487 回答
0

尽管前面的答案提出了有效的观点,但我认为您需要查看的另一件事是您的运算符优先级规则memcpy

memcpy(&c, &(*ppc2[3]), 1);

这里会发生什么?这可能不是你想要的。数组表示法的优先级高于取消引用运算符,因此您首先尝试执行与ppc2++. 然后,您取消引用值并将地址传递到memcpy. 这与 (*ppc2)[1]. 我的机器上的结果是访问冲突错误(XP/VS2005),但通常这是未定义的行为。但是,如果您以与之前相同的方式取消引用:

memcpy(&c, &((*ppc2)[3]), 1);

然后访问冲突消失了,我得到了正确的结果。

于 2010-11-01T20:58:36.697 回答
0

在处理指针时,您必须牢牢记住以下两点:

#1指针本身与它指向的数据是分开的。指针只是一个数字。这个数字告诉我们,在内存中,我们可以找到其他数据块的开头。指针可用于访问它指向的数据,但我们也可以操作指针本身的值。当我们增加(或减少)指针本身的值时,我们正在将指针的“目标”从最初指向的位置向前(或向后)移动。这将我们带到第二点......

#2每个指针变量都有一个类型,指示所指向的数据类型。Achar *指向 a char;aint *指向一个int;等等。一个指针甚至可以指向另一个指针 ( char **)。类型很重要,因为当编译器对指针值应用算术运算时,它会自动考虑所指向的数据类型的大小。这允许我们使用简单的指针算法来处理数组:

int *ip = {1,2,3,4};
assert( *ip == 1 );    // true

ip += 2;   // adds 4-bytes to the original value of ip
           // (2*sizeof(int)) => (2*2) => (4 bytes)

assert(*ip == 3);      // true

这是有效的,因为数组只是一个相同元素的列表(在本例中为ints),按顺序排列在单个连续的内存块中。指针开始指向数组中的第一个元素。然后,指针算法允许我们将指针逐个元素地推进数组。这适用于任何类型的指针(除了算术是不允许的void *)。

事实上,这正是编译器如何翻译数组索引器操作符的使用[]。它实际上是带有解引用运算符的指针添加的简写。

assert( ip[2] == *(ip+2) );  // true

那么,这一切与您的问题有什么关系?

这是你的设置...

char *pc = "abcd";
char **ppc = &pc;
char **ppc2 = &pc;

现在,我通过删除对setStaticAndDynamicPointers. (该函数也存在问题——所以请参阅@Nim 的回答和我的评论,以获取有关该函数的更多详细信息)。

char c;
c = (*ppc)[1];  
assert(c == 'b');     // assertion doesn't fail.

这行得通,因为(*ppc)说“给我任何ppc指向”。这相当于,ppc[0]。这一切都是完全有效的。

memcpy(&c,&(*ppc[1]),1);

if(c!='b')
    puts("memcpy didn't work.");  // this gets printed out.

正如其他人所指出的那样,有问题的部分是&(*ppc[1]),它的字面意思是“给我一个指向 ppc[1] 指向的任何东西的指针”。

首先,让我们简化... 运算符优先级表示:与 .&(*ppc[1])相同&*ppc[1]。然后&*是逆并相互抵消。所以&(*ppc[1])简化为ppc[1]

现在,鉴于上述讨论,我们现在可以理解为什么这不起作用:简而言之,我们将ppc其视为指向一个指针数组,而实际上它只指向一个指针。

当编译器遇到 时ppc[1],它会应用上面描述的指针算法,并给出一个指向紧跟在变量后面的内存的指针pc——无论该内存可能包含什么。(这里的行为总是未定义的)。

所以问题根本不存在memcopy()。您的调用memcpy(&c,&(*ppc[1]),1)是尽职尽责地从虚假指针指向的内存中复制 1 字节(根据请求)ppc[1],并将其写入字符变量c

正如其他人指出的那样,您可以通过移动括号来解决此问题:

memcpy(&c,&((*ppc)[1]),1)

我希望解释是有帮助的。祝你好运!

于 2010-11-02T05:33:20.350 回答