Can all functions in a thread have access to dynam

2019-08-12 23:25发布

I have a very basic question and need help. I am trying to understand what is the scope of a dynamically allocated memory (on heap).

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

Here, can I access structure t in funct() even though the memory is allocated in main() without passing argument (pointer to t to function funct) - since heap is common to a thread? What difference will it make if I define struct node * t = NULL outside of main() as a global variable and is there anything wrong with it?

10条回答
何必那么认真
2楼-- · 2019-08-12 23:58

In your code 't' is a local variable of main() - it cannot be accessed from anywhere else. This has nothing to do with threading. Please correct your code.

查看更多
成全新的幸福
3楼-- · 2019-08-13 00:01

To access a variable the function needs to know the address of this variable - the value of "t" pointer. So you must pass it into the function, otherwise the function will have no means to know what to access.

You could as well declare a global variable pinter "t" and use it from any function but again explicitly.

查看更多
ら.Afraid
4楼-- · 2019-08-13 00:02

The accepted answer is a little misleading.

When you use malloc(), the memory returned by that can be accessed anywhere in your code, assuming that you can see the variable which has the pointer returned by malloc().

This is equally true of any memory allocated in C or C++, whether heap, stack or static. Just put & in front of a local variable, and you now have the key that allows any other part of the program to get at the storage for that variable, and use it just as effectively as if they could see the variable name itself.

Local variable names are only visible inside the scope they are declared in, but their storage is accessible from anywhere, in any thread, assuming the address has been taken and passed around.

It dangerous, and yet frequently necessary, to take the address of local variables in C/C++, and so it is unfortunately impossible to use those languages effectively without understanding this.

UPDATE

@kevinf says:

Using the address of a local within the scope of the local is fine, but your suggestion is NOT memory safe

It's important to distinguish between scope and lifetime. Scope refers to identifiers (e.g. variable names), and it is the set of locations in your code where the identifier can be mentioned. It's a compile-time concept.

This is a separate concept from memory safety, or lifetime of an object in a storage location. This is a runtime concept. For example:

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

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

Here, the identifier n is only in scope within f. It names a storage location that exists while f is running. We get the address &n of that storage location and pass it to g. Note that g cannot use the name n directly. n is not in scope here! Yet the storage location is perfectly usable in this example because f is still unfinished (waiting for g to complete).

Most real C and C++ programs do this a lot, and it is allowed by the standard. It is neither generally safe nor generally unsafe. It is sometimes safe and sometimes not. This is the core challenge with C and C++. Undefined behaviour is not always detectable from local examination of a function; you have to know how it is being used in a wider context.

More recent changes to the language (in g++ use the -std=c++14 option to compile this) introduce other ways of exploring this grey area:

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

Inside f, n is in scope. And g holds an instance of a lambda, the body of which is also part of the scope of n. And the call to g inside f is perfectly fine. But in f when we store the lambda in another variable called g, the subsequent call to it is not allowed! We have, without ever using &n, implicitly captured a storage location that is no longer available to us, because its lifetime was limited to the duration of our call to f.

By the way, when I say not allowed, it will compile. But on my system it prints:

Incremented to 2
Returned into h
Incremented to 167772162

Which clearly demonstrates undefined behaviour.

查看更多
Animai°情兽
5楼-- · 2019-08-13 00:10

Just change your function to accept the pointer to that memory.

/* 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;

This is the whole point of allocating memory on the heap - automatic (stack) variables are limited to the scope of the block you declare them in. Heap memory is available anywhere - you just need to pass a pointer so that other functions know where to find what you stored.

查看更多
相关推荐>>
6楼-- · 2019-08-13 00:10

No, you would need to make t global, or pass the pointer to funct(), I'd recommend doing the second. Right now, t is in the scope of main() only.

You might also consider adding a mutex to the structure, if you plan on having several threads operating on t at once. If you do that, also consider mlock() to ensure the structure is not paged out, or locks get slow.

查看更多
爷的心禁止访问
7楼-- · 2019-08-13 00:12

as t is a pointer to the structure defined in the function main. you cannot have an access to it in funct(). Make t global so that it can be accessed in the funct() or pass the pointer as a argument to funct(). making it global is not the best choice. In a multithreaded environment muiltiple threads may try to access it so u need to have some kind of locking mechanism to avoid access at the same time. adding the locking it functionality may lead to other overhead so the best choice should be to pass it as the argument.

查看更多
登录 后发表回答