1

我有一个非常基本的问题,需要帮助。我试图了解动态分配的内存(在堆上)的范围是什么。

#include <stdio.h>
#include <malloc.h>

//-----Struct def-------
struct node {
        int x;
        int y;
};

//------GLOBAL DATA------

//-----FUNC DEFINITION----
void funct(){
  t->x = 5; //**can I access 't' allocated on heap in main over here ?**
  t->y = 6; //**can I access 't' allocated on heap in main over here ?**
  printf ("int x = %d\n", t->x);
  printf ("int y = %d\n", t->y);
  return;
}

//-----MAIN FUNCTION------
int main(void){
      struct node * t = NULL;// and what difference will it make if I define 
                                 //it outside main() instead- as a global pointer variable
          t = (struct node *) malloc (sizeof(struct node));
      t->x = 7;
      t->y = 12;
      printf ("int x = %d\n", t->x);
      printf ("int y = %d\n", t->y);

    funct(); // FUNCTION CALLED**
    return 0;
}

t在这里,funct()即使在main()没有传递参数(指向的指针t)的情况下分配了内存,我也可以访问结构function funct吗?因为堆对于线程来说是公用的?如果我struct node * t = NULL在外部定义main()为全局变量会有什么不同并且它有什么问题吗?

4

10 回答 10

8

当您使用 malloc() 时,可以在代码中的任何位置访问由它返回的内存,假设您可以看到具有 malloc() 返回的指针的变量。

所以在你的代码中,如果 t 是全局的,它将在 main 和 funct() 中可见,是的,你可以在两者中使用它。

事实上,正如前面的答案所提到的,funct() 不知道 t 是什么,因为 t 的声明和定义在 main 中;t 超出功能范围。如果funct 知道 t 是什么,您分配给 t 的内存可以在 funct 中使用。

于 2009-03-28T11:40:35.360 回答
3

不,您将无法像那样访问 t ,因为即使在 main 中您使 t 指向堆上可全局访问的东西,变量 t 本身也是 main 本地的指针(并且位于堆栈上)。

于 2009-03-28T11:36:53.217 回答
3

要访问一个变量,函数需要知道这个变量的地址——“t”指针的值。所以你必须将它传递给函数,否则函数将无法知道要访问什么。

您也可以声明一个全局变量 pinter "t" 并从任何函数中使用它,但再次显式地使用它。

于 2009-03-28T11:36:58.130 回答
2

分配的内存可以访问,但这不是你的问题。变量 't'仅在main中可见,因为那是您声明它的地方。这是您需要了解的两个不同概念。数据的存储与引用它的变量不同。

于 2009-03-28T11:37:35.213 回答
1

在您的代码中,'t' 是 main() 的局部变量 - 它不能从其他任何地方访问。这与线程无关。请更正您的代码。

于 2009-03-28T11:36:21.097 回答
1

不,您需要将 t 设为全局,或将指针传递给 funct(),我建议您执行第二个。现在, t 仅在 main() 的范围内。

如果您计划让多个线程同时在 t 上运行,您也可以考虑在结构中添加一个互斥锁。如果你这样做,还要考虑 mlock() 以确保结构不会被分页,否则锁会变慢。

于 2009-03-28T11:40:17.810 回答
1

只需更改您的函数以接受指向该内存的指针。

/* changing the variable name to make it clear that p is scoped to funct() */
/* when it's passed, just as t is local to main() */
void funct(struct node *p){
p->x = 5;
p->y = 6;
printf ("int x = %d\n", p->x);
printf ("int y = %d\n", p->y);
return;
}

...

funct(t);

/* now free the memory you allocated */
free(t);
return 0;

这是在堆上分配内存的重点——自动(堆栈)变量仅限于您在其中声明它们的块的范围。堆内存在任何地方都可用-您只需要传递一个指针,以便其他函数知道在哪里找到您存储的内容。

于 2009-03-28T11:45:10.980 回答
1

接受的答案有点误导。

当您使用 malloc() 时,可以在代码中的任何位置访问由它返回的内存,假设您可以看到具有 malloc() 返回的指针的变量。

这同样适用于在 C 或 C++ 中分配的任何内存,无论是堆、堆栈还是静态。只需将 & 放在局部变量的前面,您现在就拥有了允许程序的任何其他部分获取该变量的存储空间的密钥,并像他们可以看到变量名本身一样有效地使用它。

局部变量名称仅在它们声明的范围内可见,但它们的存储可以从任何地方、任何线程中访问,假设地址已被获取并传递。

在 C/C++ 中获取局部变量的地址是危险的,但经常是必要的,因此不幸的是,如果不理解这一点,就不可能有效地使用这些语言。

更新

@kevinf 说:

在本地范围内使用本地地址很好,但您的建议不是内存安全的

区分范围生命周期很重要。范围是指标识符(例如变量名),它是代码中可以提及标识符的一组位置。这是一个编译时的概念。

这是与内存安全或存储位置中对象的生命周期不同的概念。这是一个运行时概念。例如:

void g(int *p)
{
    (*p)++;
}

void f()
{
    int n = 1;
    g(&n);
}

此处,标识符n仅在f. 它命名运行时存在的存储位置f。我们获取该&n存储位置的地址并将其传递给g. 注意g不能n直接使用名称。n不在此范围内!然而,存储位置在此示例中完全可用,因为f仍未完成(等待g完成)。

大多数真正的 C 和 C++ 程序经常这样做,而且标准允许这样做。它既不是一般安全的,也不是一般不安全的。它有时是安全的,有时不是。这是 C 和 C++ 的核心挑战。未定义的行为并不总是可以从函数的本地检查中检测到;你必须知道它是如何在更广泛的背景下使用的。

最近对该语言的更改(在 g++ 中使用-std=c++14选项来编译它)引入了探索这个灰色区域的其他方法:

auto f()
{
    int n = 1;

    auto g = [&] 
    { 
        ++n; 
        cout << "Incremented to " << n << endl;
    };

    g();

    return g;
}

void h()
{
    auto g = f();

    cout << "Returned into h" << endl;

    g();
}

fn在范围内。并g拥有一个 lambda 实例,其主体也是n. 对ginside的调用f非常好。但是f当我们将 lambda 存储在另一个名为 的变量中时g,不允许对其进行后续调用!我们在没有使用过的情况下&n,隐式捕获了一个我们不再可用的存储位置,因为它的生命周期仅限于我们调用f.

顺便说一句,当我说不允许时,它会编译。但在我的系统上它打印:

Incremented to 2
Returned into h
Incremented to 167772162

这清楚地表明了未定义的行为。

于 2009-03-28T11:59:01.603 回答
0

因为 t 是指向函数 main 中定义的结构的指针。您无法在funct() 中访问它。将 t 设为全局,以便可以在 funct() 中访问它或将指针作为参数传递给 funct()。使其全球化并不是最佳选择。在多线程环境中,多个线程可能会尝试访问它,因此您需要有某种锁定机制来避免同时访问。添加锁定它的功能可能会导致其他开销,因此最好的选择应该是将其作为参数传递。

于 2009-03-29T07:44:23.377 回答
0

t 是 main() 的本地指针变量,但 't' 中的内容存在于整个程序中,直到/除非我们明确释放它。 t 持有的地址的生命周期在整个程序中动态分配在堆中。所以你可以在程序中的任何地方使用该内存地址,但不能使用变量局部变量't'。由于 t 是一个局部变量,它只有那个块范围,只能在 main 中使用()>因此,使用 t 及其内容的最佳方式是声明 t,然后在全局范围内动态分配内存。

In short variable 't' is local but the value in 't' is in heap.Only way to acess the heap memory is via 't'.So declare t in the global space,so we can acess the heap memory anywhere in the program via 't' .Else how you will acess the heap memory,when t goes out of scope

于 2013-02-08T08:27:36.560 回答