包含堆分配内存指针的c结构的按值调用

包含堆分配内存指针的c结构的按值调用,c,struct,heap-memory,C,Struct,Heap Memory,亲爱的飞越者 在一些c和structs的实验中,我和我的一个朋友遇到了一些我们不能完全理解的东西。下面是一段代码片段,描述了一个带有int指针和变量的结构。它们都是在主函数中创建结构时设置的 我们想知道c如何处理结构上的按值调用。引用调用是所有清晰、简单的引用,所有修改的内容都会发生更改。现在,奇怪的或有趣的调用随值而来。结构作为局部变量进行复制,结构中的指针和长度值也是如此。基本上是创建指向同一堆内存的另一个指针。(如果我错了,请纠正我) 不,如果释放此指针会发生什么。这是不是意味着你在那里泄

亲爱的飞越者

在一些c和structs的实验中,我和我的一个朋友遇到了一些我们不能完全理解的东西。下面是一段代码片段,描述了一个带有int指针和变量的结构。它们都是在主函数中创建结构时设置的

我们想知道c如何处理结构上的按值调用。引用调用是所有清晰、简单的引用,所有修改的内容都会发生更改。现在,奇怪的或有趣的调用随值而来。结构作为局部变量进行复制,结构中的指针和长度值也是如此。基本上是创建指向同一堆内存的另一个指针。(如果我错了,请纠正我)

不,如果释放此指针会发生什么。这是不是意味着你在那里泄露了信息?不一定,因为这些信息可能仍然在你的页面中。但是如果你再次对指针进行malloc操作会怎么样呢

为什么信息还在那里?有没有新的malloc。这不意味着操作系统会给你一块新的内存吗?为什么这个值仍然存在?如果按值传递结构调用并将指针指向堆内存,通常会发生什么情况

#include <stdio.h>
#include <stdlib.h>

typedef struct Struct
{
  int* array;
  int length;
} Struct;

void callByValue(Struct st)
{
  st.array[1] = 11;
  st.length = 11;

  /* This is weird */
  free(st. array);
}

void callByRef(Struct *st)
{
  st->array[1] = 22;
  st->length = 22;
}

int main()
{
  Struct s;
  s.array = malloc(2*sizeof(int));
  s.array[1] = 0;
  s.length = 0;

  printf("Before array[1]: %d length: %d\n", s.array[1], s.length);

  callByValue(s);

  printf("Caal-by-value array[1]: %d length: %d\n", s.array[1], s.length);

  callByRef(&s);

  printf("Caal-by-reference array[1]: %d length: %d\n", s.array[1], s.length);

  return 0;
}

当您按值调用时,代码生成一个结构副本供函数使用。所以你有这种情况

main:        s.array  ---+
                         +---> MemA (memory for 2 ints)
callByValue: st.array ---+
free(st.array)
之后,两个指针都无效,因为
MemA
已被释放

在您
malloc(1000…
之后,您会遇到这种情况

main:        s.array  ---> MemA (invalid pointer)
callByValue: st.array ---> MemB (memory for 1000 ints)

main
中的指针未更新,仍然无效。在
main
中使用指针将导致未定义的行为。

Hmm,您不会在堆上找到许多分配副本的编译器。堆栈是常见的选择。不管怎么说,这是一个重要的UB。因为在malloc之后,在打印指针之前,您没有在指针中写入任何内容。无论出于何种原因,malloc'ing再次没有改变指针指向的位置。无论如何,这是UB,所以任何事情都可能发生。你的假设是错误的。callByValue()的st参数将复制到堆栈中。当函数返回并重置堆栈指针时,您对st或其成员所做的任何更改都将被丢弃。对于堆内存数组来说,这是不正确的,这正是我们对这个特定问题感兴趣的原因。将堆分配放在结构中是非常自然的,而且一直都是这样。唯一的问题是在调用该内存上的
free
后访问内存。但是,在释放内存后,我们可以通过引用其他函数给出结构并修改数组。首先,我们没有再去马洛克,我们想的正是你所描述的。但是,我们可以访问指针并更改堆中的数据……是的,这就是未定义行为(undefined behavior,UB)的问题。有时你的程序看起来是有效的,即使它完全错了。C语言不提供针对UB的保护,作为程序员,您有义务避免UB。可以帮助您在程序中查找UB的工具之一是。我建议您使用valgrind运行代码,看看会出现什么错误。那么,为什么我会先删除空间,然后释放空间,然后访问它,这样操作系统就不会抱怨了。这仅仅是起作用的页面问题吗?因为这可以解释这个问题。操作系统并不在乎。您使用
malloc
请求内存。您可以使用
free
放弃对内存的控制。在
释放后
,操作系统可能会将内存用于其他用途。如果在操作系统将内存用于其他用途之后再使用内存,那么任何事情都可能发生。因此未定义的行为。感谢澄清!
main:        s.array  ---> MemA (invalid pointer)
callByValue: st.array ---> MemB (memory for 1000 ints)