memcpy 失败,但不能对字符指针进行赋值

发布于 2024-09-30 08:24:46 字数 1046 浏览 12 评论 0原文

实际上,当我使用指向字符的指针时,memcpy 工作得很好,但当我使用指向字符的指针时,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;
}

Actually, memcpy works just fine when I use pointers to characters, but stops working when I use pointers to pointers to characters.

Can somebody please help me understand why memcpy fails here, or better yet, how I could have figured it out myself. I am finding it very difficult to understand the problems arising in my c/c++ code.

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;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

捶死心动 2024-10-07 08:24:46

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

your comment implies that char stat[5] should be static, but it isn't. As a result charIn points to a block that is allocated on the stack, and when you return from the function, it is out of scope. Did you mean static char stat[5]?

长梦不多时 2024-10-07 08:24:46

char stat[5];

是一个超出范围的堆栈变量,它不是 // 将第一个参数设置为指向静态内存的指针。.您需要 malloc/new 一些内存来将 abcd 放入其中。就像您对 charIn2 所做的那样

char stat[5];

is a stack variable which goes out of scope, it's not // sets the first arg to a pointer to static memory.. You need to malloc/new some memory that gets the abcd put into it. Like you do for charIn2

内心旳酸楚 2024-10-07 08:24:46

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

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

Just like what Preet said, I don't think the problem is with memcpy. In your function "setStaticAndDynamicPointers", you are setting a pointer to an automatic variable created on the stack of that function call. By the time the function exits, the memory pointed to by "stat" variable will no longer exist. As a result, the first argument **charIn will point to something that's non-existent. Perhaps you can read in greater detail about stack frame (or activation record) here: link text

You have effectively created a dangling pointer to a stack variable in that code. If you want to test copying values into a stack var, make sure it's created in the caller function, not within the called function.

难如初 2024-10-07 08:24:46

除了“stat”的定义之外,我眼中的主要问题是 *ppc[3](*ppc)[3] 不同。你想要的是后者(ppc指向的字符串中的第四个字符),但是在你的memcpy()中你使用前者,“字符串数组”ppc中第四个字符串的第一个字符(显然ppc不是一个 char* 数组,但你强制编译器这样对待它)。

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

In addition to the definition of 'stat', the main problem in my eyes is that *ppc[3] is not the same as (*ppc)[3]. What you want is the latter (the fourth character from the string pointed to by ppc), but in your memcpy()s you use the former, the first character of the fourth string in the "string array" ppc (obviously ppc is not an array of char*, but you force the compiler to treat it as such).

When debugging such problems, I usually find it helpful to print the memory addresses and contents involved.

つ可否回来 2024-10-07 08:24:46

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

Note that the parenthesis in the expressions in your assignment statements are in different locations from the parenthesis in the memcpy expressions. So its not too suprising that they do different things.

美人骨 2024-10-07 08:24:46

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

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

#2 每个指针变量都有一个类型,用于指示指向的数据类型。一个char *指向一个char; a int * 指向一个 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

这是有效的,因为数组只是相同元素(在本例中为int)的列表,按顺序布置在单个连续的内存块中。指针开始指向数组中的第一个元素。然后,指针算术允许我们在数组中逐个元素地推进指针。这适用于任何类型的指针(除了 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)

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

When dealing with pointers, you have to keep the following two points firmly in the front of your mind:

#1 The pointer itself is separate from the data it points to. The pointer is just a number. The number tells us where, in memory, we can find the beginning of some other chunk of data. A pointer can be used to access the data it points to, but we can also manipulate the value of the pointer itself. When we increase (or decrease) the value of the pointer itself, we are moving the "destination" of the pointer forward (or backward) from the spot it originally pointed to. This brings us to the second point...

#2 Every pointer variable has a type that indicates what kind of data is being pointed to. A char * points to a char; a int * points to an int; and so on. A pointer can even point to another pointer (char **). The type is important, because when the compiler applies arithmetic operations to a pointer value, it automatically accounts for the size of the data type being pointed to. This allows us to deal with arrays using simple pointer arithmetic:

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

This works because the array is just a list of identical elements (in this case ints), laid out sequentially in a single contiguous block of memory. The pointer starts out pointing to the first element in the array. Pointer arithmetic then allows us to advance the pointer through the array, element-by-element. This works for pointers of any type (except arithmetic is not allowed on void *).

In fact, this is exactly how the compiler translates the use of the array indexer operator []. It is literally shorthand for a pointer addition with a dereference operator.

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

So, How is all this related to your question?

Here's your setup...

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

for now, I've simplified by removing the call to setStaticAndDynamicPointers. (There's a problem in that function too—so please see @Nim's answer, and my comment there, for additional details about the function).

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

This works, because (*ppc) says "give me whatever ppc points to". That's the equivalent of, ppc[0]. It's all perfectly valid.

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

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

The problematic part —as others have pointed out— is &(*ppc[1]), which taken literally means "give me a pointer to whatever ppc[1] points to."

First of all, let's simplify... operator precedence says that: &(*ppc[1]) is the same as &*ppc[1]. Then & and * are inverses and cancel each other out. So &(*ppc[1]) simplifies to ppc[1].

Now, given the above discussion, we're now equipped to understand why this doesn't work: In short, we're treating ppc as though it points to an array of pointers, when in fact it only points to a single pointer.

When the compiler encounters ppc[1], it applies the pointer arithmetic described above, and comes up with a pointer to the memory that immediately follows the variable pc -- whatever that memory may contain. (The behavior here is always undefined).

So the problem isn't with memcopy() at all. Your call to memcpy(&c,&(*ppc[1]),1) is dutifully copying 1-byte (as requested) from the memory that's pointed to by the bogus pointer ppc[1], and writing it into the character variable c.

As others have pointed out, you can fix this by moving your parenthesis around:

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

I hope the explanation was helpful. Good luck!

倒带 2024-10-07 08:24:46

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

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

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

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

那么访问冲突就会消失,我会得到正确的结果。

Although the previous answers raise valid points, I think the other thing you need to look at is your operator precedence rules when you memcpy:

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

What happens here? It might not be what you're intending. The array notation takes higher precedence than the dereference operator, so you first attempt perform pointer arithmetic equivalent to ppc2++. You then dereference that value and pass the address into memcpy. This is not the same as (*ppc2)[1]. The result on my machine is an access violation error (XP/VS2005), but in general this is undefined behaviour. However, if you dereference the same way you did previously:

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

Then that access violation goes away and I get proper results.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文