i've looked over so many topics and i still could not find out why this happens:
struct B
{
int _arr[5];
};
struct A
{
struct B * _pb;
};
int main() {
int i;
struct B b;
struct A *pa = (struct A*)malloc(sizeof (struct A));
for (i=0;i<5;++i)
{
b._arr[i] = i;
}
pa->_pb=&b;
Struct A a = *pb;
}
How come pa found on stack and *pa is found on heap! both are local variables and should be only valid through scope so it should be on stack.
also why is a._pb->_arr[2] on stack should not be on heap? can anyone clarify for me when it should be on stack and when on heap
The variable pa is on the stack. The memory it points to is on the heap.
Somewhat graphically a pointer variable can be describes like this:
+----+ +--------------------------------+
| pa | --> | allocated memory for structure |
+----+ +--------------------------------+
The two locations illustrated above (pa and the memory it points to) can be in different "segments", or they can be in the same.
And a._pb->_arr[2] is on the stack because a._pb is pointing to b which is on the stack.
Lastly a note about the "stack". While it's common to store local variables on the stack, the C specification doesn't say anything about it. Local variables are really automatic variables, and the C specification only specifies the semantics of those not where they should be stored.
First off, the C standard says nothing about stacks and heaps. Those are implementation details of a given compiler. That being said, most compilers for desktop applications use both of these.
You are correct that pa is local to the main function and therefore resides on the stack. *pa however is not a local variable. It is an expression which evaluates to an instance of struct A.
In this case, the malloc function returns a pointer to a block of memory big enough for a struct A and the value of that pointer is stored in pa.
Generally speaking, anything returned by malloc, realloc, or calloc lives in the heap, while variables declared local to a function (even pointer variables which may point to the heap) reside on the stack.
Short answer: *pa (what pa points to) is found on the heap because that's where you allocated the memory using malloc(). The variable pa, the pointer itself, is allocated on the stack because it's a local variable.
Long answer: Make sure you note the difference between a pointer and what the pointer refers to.
A declaration like this:
int a[5]
Tells the compiler to reserve space for a 5-element array, while a declaration like this:
int *a;
Tells the compiler to reserve space for a pointer. If you want the pointer to refer to an array then you need to allocate the memory, usually on the heap using malloc() and then release it when you're done using free().
And just to confuse things, in the C language, the array operator, [], is equivalent to the pointer arithmetic *() so that these two statements are wholly equivalent, regardless of whether a was declared as a pointer or an array:
a[2] = 5;
*(a + 2) = 5;
Digression: Which leads to some amusing possibilities. The above two statements are also equivalent to this one:
2[a] = 5;
Because addition is commutative in C:
2[a] = 5;
*(2 + a) = 5;
*(a + 2) = 5;
a[2] = 5;
But this absolutely does not work in C++ for reasons that are too far afield for this digression.
Related
int *tomato(int *a, int *b) {
int *foo = (int*)malloc(sizeof(int));
*foo = *a + *b;
return foo;
}
In this function I have foo that is allocated in heap and returns a pointer to int, but are the pointers *a and *b in the function arguments also allocated in heap? I am a bit confused here, generally, arguments are allocated in stack.
The pointers are local variables in the tomato function, just like foo.
The values that they point to can be allocated anywhere. For instance, you can call it like this:
int foo = 1;
int *bar = malloc(sizeof(int));
*bar = 3;
int *result = tomato(&foo, bar);
a will point to a the foo variable, while b will point to the memory allocated by malloc.
Parameters in C are not necessarily allocated in the stack (*), but their scope will necessarily be restricted to the tomato function block, and they will necessarily be passed by value.
When you dereference a and b in the assignment *foo = *a + *b, you are interpreting the memory address stored in pointers a and b as integers, summing them, and writing the result in the memory address stored in pointer foo (which, in your example, happens to be in the heap).
After the assignment, you could change a and b at will by assigning different memory addresses to them (i.e. pointers), and there would be no consequence to any external memory references as their scope is limited to the function block (e.g. a = foo). If, however, you changed the memory contents referred by them (e.g. *a = 0), this would become visible outside the scope of the function as you would be writing on a memory space (stack or heap) allocated somewhere else.
(*) Parameters may not be passed in memory (i.e. stack) to functions. Depending on the compiler/architecture, they may be directly assigned to a processor register. Either way, this is a transparent compiler optimization and you don't have to worry about it... the parameters will behave just the same.
Thanks for notice my question.
In C Primer Plus, it first writes
The argument to free() should be a pointer to a block of memory allocated by malloc(); you can’t use free() to free memory allocated by other means
which means ONE malloc(), ONE and ONLY one free().
But later it goes
It’s okay to use a different pointer variable with free() than with malloc(); what must agree are the addresses stored in the pointers.
which seems contradict to the first statement.
So my understanding is that as long as a pair of malloc() and free() share the same address there is no error, and the name of pointers doesn't matter. Am I right?
For example:
void* p = malloc (100);
void* q = p;
free (q);
...is fine. The argument for free () is the value that was returned by malloc. The sentence
"It’s okay to use a different pointer variable with free() than with
malloc()"
is actually pointless and just creates confusion - of course it is fine to use different variables as long as the value is the same.
Just remember that freeing any alias, makes all the pointers invalid
int *a, *b, *c, *d, *e;
a = malloc(42 * sizeof (int));
b = a;
c = b;
d = c;
e = d;
a[0] = 42;
b[1] = 100; // same as a[1]
c[2] = 999; // same as a[2]
d[3] = -1; // same as a[3]
e[4] = 0; // same as a[4]
free(d); // for example
// all of a, b, c, d, and e are now invalid;
Variables contain some value, which could be a pointer (i.e. a memory address).
Two variables could contain the same pointer (that is, the same address), it is called pointer aliasing.
What matters to free is to get the value of a pointer previously given by malloc (that is a memory address previously given by malloc)
Given pointers to char, one can do the following:
char *s = "data";
As far as I understand, a pointer variable is declared here, memory is allocated for both variable and data, the latter is filled with data\0 and the variable in question is set to point to the first byte of it (i. e. variable contains an address that can be dereferenced). That's short and compact.
Given pointers to int, for example, one can do this:
int *i;
*i = 42;
or that:
int i = 42;
foo(&i); // prefix every time to get a pointer
bar(&i);
baz(&i);
or that:
int i = 42;
int *p = &i;
That's somewhat tautological. It's small and tolerable with one usage of a single variable. It's not with multiple uses of several variables, though, producing code clutter.
Are there any ways to write the same thing dry and concisely? What are they?
Are there any broader-scope approaches to programming, that allow to avoid the issue entirely? May be I should not use pointers at all (joke) or something?
String literals are a corner case : they trigger the creation of the literal in static memory, and its access as a char array. Note that the following doesn't compile, despite 42 being an int literal, because it is not implicitly allocated :
int *p = &42;
In all other cases, you are responsible of allocating the pointed object, be it in automatic or dynamic memory.
int i = 42;
int *p = &i;
Here i is an automatic variable, and p points to it.
int * i;
*i = 42;
You just invoked Undefined Behaviour. i has not been initialized, and is therefore pointing somewhere at random in memory. Then you assigned 42 to this random location, with unpredictable consequences. Bad.
int *i = malloc(sizeof *i);
Here i is initialized to point to a dynamically-allocated block of memory. Don't forget to free(i) once you're done with it.
int i = 42, *p = &i;
And here is how you create an automatic variable and a pointer to it as a one-liner. i is the variable, p points to it.
Edit : seems like you really want that variable to be implicitly and anonymously allocated. Well, here's how you can do it :
int *p = &(int){42};
This thingy is a compound literal. They are anonymous instances with automatic storage duration (or static at file scope), and only exist in C90 and further (but not C++ !). As opposed to string literals, compound literals are mutable, i.e you can modify *p.
Edit 2 : Adding this solution inspired from another answer (which unfortunately provided a wrong explanation) for completeness :
int i[] = {42};
This will allocate a one-element mutable array with automatic storage duration. The name of the array, while not a pointer itself, will decay to a pointer as needed.
Note however that sizeof i will return the "wrong" result, that is the actual size of the array (1 * sizeof(int)) instead of the size of a pointer (sizeof(int*)). That should however rarely be an issue.
int i=42;
int *ptr = &i;
this is equivalent to writing
int i=42;
int *ptr;
ptr=&i;
Tough this is definitely confusing, but during function calls its quite useful as:
void function1()
{
int i=42;
function2(&i);
}
function2(int *ptr)
{
printf("%d",*ptr); //outputs 42
}
here, we can easily use this confusing notation to declare and initialize the pointer during function calls. We don't need to declare pointer globally, and the initialize it during function calls. We have a notation to do both at same time.
int *ptr; //declares the pointer but does not initialize it
//so, ptr points to some random memory location
*ptr=42; //you gave a value to this random memory location
Though this will compile, but it will invoke undefined behaviour as you actually never initialized the pointer.
Also,
char *ptr;
char str[6]="hello";
ptr=str;
EDIT: as pointed in the comments, these two cases are not equivalent.
But pointer points to "hello" in both cases. This example is written just to show that we can initialize pointers in both these ways (to point to hello), but definitely both are different in many aspects.
char *ptr;
ptr="hello";
As, name of string, str is actually a pointer to the 0th element of string, i.e. 'h'.
The same goes with any array arr[], where arr contains the address of 0th element.
you can also think it as array , int i[1]={42} where i is a pointer to int
int * i;
*i = 42;
will invoke undefined behavior. You are modifying an unknown memory location. You need to initialize pointer i first.
int i = 42;
int *p = &i;
is the correct way. Now p is pointing to i and you can modify the variable pointed to by p.
Are there any ways to write the same thing dry and concisely?
No. As there is no pass by reference in C you have to use pointers when you want to modify the passed variable in a function.
Are there any broader-scope approaches to programming, that allow to avoid the issue entirely? May be I should not use pointers at all (joke) or something?
If you are learning C then you can't avoid pointers and you should learn to use it properly.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Stack variables vs. Heap variables
What is the difference between declaring an array as:
int arr[100];
and
int* arr=(int*)malloc(sizeof(int)*100);
Which one is preferred? Is there something like heap and stack memory involved in this?
I suggest a trip to the bookstore to pickup a copy of Kernighan and Ritchie's The C Programming Language, and optionally, a copy of Harbison & Steele's C: A Reference Manual.
The first case gives you an array of 100 ints, allocated on the stack. The latter case gives you a pointer to an int, whose address is that of a buffer allocated on the heap, the size of which is large enough to contain 100 ints.
The C language is fundamentally a hardware agnostic assembly language. The distinction between a pointer and an array is intentionally fuzzy, since array reference notation is syntactic sugar for pointer arithmetic. This:
int foo( int a )
{
int x[100] = load_X() ;
int y = x[ a ] ;
return y ;
}
is identical to
int foo( int a )
{
int *x = load_X() ;
int y = *( x + a ) ;
// note that the use of sizeof() isn't required. For the pointer carries around
// an implicit increment size (the size of the object to which it points). The above
// is equivalent to
//
// int y = *(int*)((char*)x + (a*sizeof(*x)) ) ;
}
Further, the compiler will (or should) whine about type mismatches, given function foo():
public void foo( int a[] )
{
...
}
The invocation:
int *p = malloc(...) ;
foo(p) ;
should results in a compiler whine regarding type mismatches.
The first one declares arr as an array of type int[100] that resides on the stack. In some contexts arr will decay to a pointer of type int *, but that doesn't make it a pointer. To further emphasize that it is not a pointer, sizeof(arr) will yield sizeof(int) * 100, not the size of an address.
The second one declares a pointer of type int * and initializes it to the pointer returned by malloc, which in fact allocates memory on the heap. Note that in this case arr is not an array - you can use the array notation to offset and dereference the pointer, but that doesn't make it an array.
The former allocates an automatic array of size 100, which will be automatically released once it goes out of scope.
The latter allocates space for 100 ints in the free store, and returns a pointer to the start of the block of memory. It will remain allocated until free() is called on the pointer.
If you need the memory only for as long as the current scope, then the former is easier to work with (assuming it's not too big.) Otherwise, the latter option is the approach to take.
I am new to C and i have this question. why does the following code crash:
int *a = 10;
*a = 100;
Because you are trying to write 100 to the memory location 0x0000000A which is probably not allocated to your program. That is,
int *a = 10;
does not mean that the pointer 'a' will point to a location in memory having the value of 10. It means it is pointing to address 10 (0x0000000A) in the memory. Then, you want to write something into that address, but you don't have the "rights" to do so, since it is not allocated
You can try the following:
int *a = malloc(sizeof(int));
*a = 100;
This would work, although horribly inefficient. If you only need a single int, you should just put it into the stack, not the heap. On a 32-bit architecure, a pointer is 32 bits long, and an int is 32 bits long too, so your pointer-to-an-int structure takes up (at least) 8 bytes of memory space this way instead of 4. And we haven't even mentioned caching issues.
You need to assign the pointer to a memory location, not arbitrary value (10).
int cell = 10;
int *a = &cell; // a points to address of cell
*a = 100; // content of cell changed
See my answer to another question, about being careful with C.
I would like to propose a slight change in the use of malloc(), for all the answers that suggest using it to allocate memory for the int. Instead of:
a = malloc(sizeof(int));
I would suggest not repeating the type of the variable, since that is known by the compiler and repeating it manually both makes the code more dense, and introduces an error risk. If you later change the declaration to e.g.
long *a;
Without changing the allocation, you would end up allocating the wrong amount of memory ( in the general case, on 32-bit machines int and long are often the same size). It's, IMO, better to use:
a = malloc(sizeof *a);
This simply means "the size of the type pointed at by a", in this case int, which is of course exactly right. If you change the type in the declaration as above, this line is still correct. There is still a risk, if you change the name of the variable on the left hand side of the assignment, but at least you no longer repeat information needlessly.
Also note that no parenthesis are needed with sizeof when using it on actual objects (i.e. variables), only with type names, which look like cast expressions. sizeof is not a function, it's an operator.
Because you've never allocated any memory for a. You've just allocated some stack space for a pointer to a.
int *a = NULL;
a = malloc (sizeof (int));
if (a != NULL)
{
*a =10;
}
Will work.
Alternatively you could give a the address of some existing variable, which would work as well.
i.e.
int a* = NULL;
int b = 10;
a = &b;
This will now mean that doing something like
*a = 100;
will also set b to be == 100
Check out this:
http://home.netcom.com/~tjensen/ptr/pointers.pdf
The following line,
int *a = 10;
defines a pointer to an integer a. You then point the pointer a to the memory location 10.
The next line,
*a = 100;
Puts the value 100 in the memory location pointed to by a.
The problem is:
You don't know where a points to. (You don't know the value of memory location 10)
Wherever a points to, you probably have no right changing that value. It's probably some other program/process's memory. You thief!
Because You declare a pointer to int, initialize the pointer to 10 (an address) and then try to assign a value to an int at this address. Since the memory at address 10 does not belong to your process, You get a crash. This should work:
int *a;
a = malloc(sizeof(int));
*a = 10;
printf("a=%i\n", *a);
free(a);
Does this code even compile? 10 isn't convertible to an int *, unless you cast it like so:
int *a = (int *) 10;
*a = 100;
In that case, you're trying to write 100 into the memory address at 10. This isn't usually a valid memory address, hence your program crashes.
It's probably crashing because you are assigning the pointer to some part of memory which you don't have access to and then you're assigning some value to that memory location (which you're not allowed to do!).
You could also write it as:
int* a = 10;
*a = 100;
Note the different spacing on the first line. It's not a popular style, but I personally think it's clearer. It has exactly the same meaning to the compiler.
Then, read it out loud:
"Pointer-to-int 'a' becomes 10"
"Value-pointed-to-by 'a' becomes 100"
Substituting the actual value:
"Value-pointed-to-by 10 becomes 100"
... at which you realise that 10 is unlikely to point to a piece of memory you can use.
You would pretty much never assign to a pointer with a literal:
int* ptr = (int*)10; // You've guessed at a memory address, and probably got it wrong
int* ptr = malloc(sizeof(int)); // OS gives you a memory address at runtime
I guess there might be some very low level jobs where you directly specify absolute memory addresses. Kernel implementation for example?
Okay, trying to give the simplest explanation today, while trying to give you more detailed picture about it all. Lets add some parentheses shall we?
(int*) a = 10;
(*a) = 100;
You attempt to write four bytes into the address-range [10-13]. The memory layout of your program starts usually higher, so your application does not accidentally overwrite anything from where it could and still function (from .data, .bss, and stack for instance). So it just ends up crashing instead, because the address-range has not been allocated.
Pointer points to a memory location and C static typing defines a type for a pointer. Though you can override the pointer easily. Simply:
(void*) v = NULL;
Here we go further to things. What is a null pointer? It's simply pointer that points to address 0.
You can also give a struct type for your pointer:
struct Hello {
int id;
char* name;
};
...
struct Hello* hello_ptr = malloc(sizeof Hello);
hello_ptr->id = 5;
hello_ptr->name = "Cheery";
Ok, what is malloc? Malloc allocates memory and returns a pointer to the allocated memory. It has a following type signature:
void* malloc(size_t size);
If you do not have a conservative garbage collector, it is likely that your memory won't end up being freed automatically. Therefore, if you want to get the memory back into use from what you just allocated, you must do:
free(hello_ptr);
Each malloc you do has a size-tag in it, so you do not need to state the size of the chunk you pointed for free -routine.
Ok, yet one thing, what does a character string look like in memory? The one similar to "Cheery" for instance. Simple answer. It's a zero-terminated array of bytes.
0.1.2.3.4.5. 6
C h e e r y \0