Reputation: 3231
int *x; Declares pointer which holds an ADDRESS to a location in memory *x = 51; * is de-reference operator. I'm saving 51 at that address. &x; & is address of operator, so &x would probably print some memory location
What I don't understand:
What would happen with x = 51
after declaring int *x;
Would just a '51' be stored in the pointer, so it'd be pointing to some error "51" location?
What happens if you say &x
? would it just print the memory location that the pointer is sitting in?
A function declaration is function(int *x)
but calling the function the form is function(&x)
. Why?
malloc()
I dont understand "WHY" it works, I understand what it does however. Since in the C library definition it returns a "pointer" to the requested memory.
x = (int *) malloc (sizeof (int));
is putting a pointer in x......but x is a pointer already? So is it pointing to another pointer?
I've also seen it written like this x = malloc(sizeof(int));
.....whats the difference?
5: The **
operator, I'd assume it means "pointer to a pointer"....but I guess maybe I don't understand when/why this would come into play?
Upvotes: 1
Views: 611
Reputation: 123558
What would happen with x = 51 after declaring int *x; Would just a '51' be stored in the pointer, so it'd be pointing to some error "51" location?
Essentially, yes. x
is a variable like any other, and you can assign new values to it like any other. The expression 51
will be converted from type int
to type int *
, and the result will be assigned to x
.
51
is most likely not a valid pointer value, so attempting to dereference it will likely lead to a runtime error. Valid pointer values are obtained by either applying the unary &
operator to an lvalue1, by calling one of malloc
, calloc
, or realloc
, or by using an array expression in some circumstances2.
What happens if you say &x ? would it just print the memory location that the pointer is sitting in?
The expression &x
will evaluate to the location of the object x
, and the type of the resulting value will be int **
(pointer to pointer to int
).
A function declaration is function(int *x) but calling the function the form is function(&x). Why?
Because, for any object x
of type T
, the expression &x
yields a value of type T *
:
void foo( T *ptr ) // for any type T
{
*ptr = new_value(); // write a new value to the object ptr
} // points to
void bar( void )
{
T var;
foo( &var ); // foo updates the value of var
}
In the code above,
ptr == &var // T *
*ptr == var // T
This is true for any type, including pointer types. If we replace the type T
with a pointer type P *
, that code above becomes
void foo( P **ptr )
{
*ptr = new_value(); // write a new value to the thing ptr points to
}
void bar( void )
{
P *var;
foo( &var ); // write a new value to var
}
This code is exactly the same as the code above - the only thing that has changed is the types:
ptr == &var // P **
*ptr == var // P *
**ptr == *var == some_object // P
malloc() I dont understand "WHY" it works, I understand what it does however. Since in the C library definition it returns a "pointer" to the requested memory.
x = (int *) malloc (sizeof (int)); is putting a pointer in x......but x is a pointer already? So is it pointing to another pointer?
No. x
is an object that stores a pointer value; malloc
is a function that returns a pointer value.
I've also seen it written like this x = malloc(sizeof(int)); .....whats the difference?
The (int *)
is a cast expression - it tells the compiler to treat the result of malloc
as a pointer to int
. As of the 1989 version of the language, that cast is no longer necessary, and its use is discouraged. IMO, the proper way to write a malloc
call is
T *p = malloc( sizeof *p * number_of_elements );
This works because malloc
returns void *
, which is a "generic" pointer type - a void *
value can be converted to any other pointer type (and vice versa) without a cast3.
Prior to the 1989 standard, malloc
returned char *
, which did require an explicit cast to assign the result to a different pointer type.
5: The ** operator, I'd assume it means "pointer to a pointer"....but I guess maybe I don't understand when/why this would come into play?
Multiple indirection (pointers to pointers, pointers to pointers to pointers, etc.) is a common thing. I showed one example above, where a function needs to write a new value to a parameter of pointer type. It's rare to see more than two or three levels of indirection, though.
EDIT
Some actual code might help. Here's a small example that creates two variables, one an int
, and the other an int *
. We start out with the pointer initialized to NULL
(a well-defined "nowhere" value, guaranteed to compare unequal to any valid pointer value), then we set it to point to another integer variable, then we set it to point to memory allocated by malloc
. I've added calls to a utility I wrote to display the contents of each object:
#include <stdio.h>
#include <stdlib.h>
#include "dumper.h"
int main( void )
{
int x = 10;
/**
* Start with ptr pointing "nowhere"
*/
int *ptr = NULL;
char *names[] = {"x", "ptr", "unnamed"};
void *addrs[] = {&x, &ptr, NULL };
size_t sizes[] = { sizeof x, sizeof ptr, 0 };
printf( "ptr is currently NULL\n\n" );
dumper( names, addrs, sizes, 2, stdout );
/**
* Set ptr to point to x
*/
ptr = &x; // int * = int *; use the & operator to obtain the location of x
printf( "ptr currently points to x\n\n" );
dumper( names, addrs, sizes, 2, stdout );
ptr = malloc( sizeof *ptr * 10 ); // int * = void *; use malloc to set aside
if ( ptr ) // dynamic memory and obtain its location;
{ // in C, you can assign a void * to an int * without a cast
for ( size_t i = 0; i < 10; i++ )
ptr[i] = (int) i;
}
addrs[2] = ptr;
sizes[2] = sizeof *ptr * 10;
printf( "ptr currently points to dynamically allocated memory\n\n" );
dumper( names, addrs, sizes, 3, stdout );
free( ptr );
return 0;
}
When built and run on my system (SLES-10 on x86-64, gcc 4.1.2), I get the following output:
$ ./pointer_example
ptr is currently NULL
Item Address 00 01 02 03
---- ------- -- -- -- --
x 0x7fff89aeb304 0a 00 00 00 ....
ptr 0x7fff89aeb2f8 00 00 00 00 ....
0x7fff89aeb2fc 00 00 00 00 ....
ptr currently points to x
Item Address 00 01 02 03
---- ------- -- -- -- --
x 0x7fff89aeb304 0a 00 00 00 ....
ptr 0x7fff89aeb2f8 04 b3 ae 89 ....
0x7fff89aeb2fc ff 7f 00 00 ....
ptr currently points to dynamically allocated memory
Item Address 00 01 02 03
---- ------- -- -- -- --
x 0x7fff89aeb304 0a 00 00 00 ....
ptr 0x7fff89aeb2f8 10 20 50 00 ..P.
0x7fff89aeb2fc 00 00 00 00 ....
unnamed 0x502010 00 00 00 00 ....
0x502014 01 00 00 00 ....
0x502018 02 00 00 00 ....
0x50201c 03 00 00 00 ....
0x502020 04 00 00 00 ....
0x502024 05 00 00 00 ....
0x502028 06 00 00 00 ....
0x50202c 07 00 00 00 ....
0x502030 08 00 00 00 ....
0x502034 09 00 00 00 ....
Before going over that in detail, remember that x86-64 is little-endian, so multi-byte objects are stored starting with the least-significant bit. This also means that objects that span multiple 32-bit words are stored starting with the least-significant word.
In short, read the memory dumps for each object from right to left, bottom to top.
Starting with the first section:
Item Address 00 01 02 03
---- ------- -- -- -- --
x 0x7fff89aeb304 0a 00 00 00 ....
ptr 0x7fff89aeb2f8 00 00 00 00 ....
0x7fff89aeb2fc 00 00 00 00 ....
The object x
is stored starting at location 0x7fff89aeb304
; on my system, objects of type int
take up 4 bytes. The value stored at x
is 10
(0x0000000a
; again, read the memory dump from right to left).
The object ptr
is stored starting at location 0x7fff89aeb2f8
; on my system, objects of type int *
take up 8 bytes4. The value stored at ptr
is NULL
(0).
After setting ptr
to point to x
, we get the following:
Item Address 00 01 02 03
---- ------- -- -- -- --
x 0x7fff89aeb304 0a 00 00 00 ....
ptr 0x7fff89aeb2f8 04 b3 ae 89 ....
0x7fff89aeb2fc ff 7f 00 00 ....
The value stored at ptr
is now 0x7fff89aeb304
, which is the address of x
. Right now, the expressions x
and *ptr
would yield the same value (10
).
Finally, we allocate space for 10 integers using malloc
and set ptr
to point to the first element in that sequence:
Item Address 00 01 02 03
---- ------- -- -- -- --
x 0x7fff89aeb304 0a 00 00 00 ....
ptr 0x7fff89aeb2f8 10 20 50 00 ..P.
0x7fff89aeb2fc 00 00 00 00 ....
unnamed 0x502010 00 00 00 00 ....
0x502014 01 00 00 00 ....
0x502018 02 00 00 00 ....
0x50201c 03 00 00 00 ....
0x502020 04 00 00 00 ....
0x502024 05 00 00 00 ....
0x502028 06 00 00 00 ....
0x50202c 07 00 00 00 ....
0x502030 08 00 00 00 ....
0x502034 09 00 00 00 ....
Hopefully, the pattern should be obvious by now - ptr
stores the value 0x502010
, which is the address of the first element of the dynamically-allocated sequence.
sizeof
or the unary &
, or is a string literal used to initialize a character array in a declaraction, an expression of type "N
-element array of T
" will be converted ("decay") to an expression of type "pointer to T
", and the value of the expression will be the address of the first element of the array.
malloc
in C++ does require a cast, but you shouldn't use malloc
in C++ code anyway.
Upvotes: 2
Reputation: 12625
Answers:
Yes.
print("%p", &x);
will display the address of x.
Function is declared as accepting a pointer (e.g. memory address). Therefore, when you call it you have to pass a pointer. The address &
of x is a pointer. Or you could declare int z = 10, *y = &z;
and then function(y)
call would work.
x is declared as the location of memory that can store a pointer. malloc()
returns the address (pointer to) memory it allocated. When you say x = malloc(n)
you're indicating it should store the address of the allocated memory at the location x, which is declared as memory that stores a pointer.
A common use of **
is when you want a function to save the address of memory it allocated to a caller's pointer. Example:
// Example of a common use of pointer to pointer (**)
#include <stdio.h>
#include <stdlib.h>
void mymsg(char **pointer_to_pointer) {
char *mem = malloc(NBYTES);
if (mem == NULL) {
fprintf(stderr, "out of memory\n")
exit(-1);
}
strcpy(mem, "This is some data, also see strdup() man page");
*pointer_to_pointer = mem; // Store the pointer mem at the callers pointer
// storage area, pointed to by
// pointer_to_pointer
}
int main() {
char *memptr = NULL; // Pointer variable (stores 𝒂𝒅𝒅𝒓𝒆𝒔𝒔 of chars)
mymsg(&memptr); // Pass address `*` of our pointer `*` (i.e. **)
// mymsg() will store pointer to allocated
// memory in memptr (which is our "𝒑𝒐𝒊𝒏𝒕𝒆𝒓 holder"
// location).
printf("text: %s\n", memptr); // Displays text in memory pointed to
// to by memptr. That memory was allocated
// in mymsg(), but that's irrelevant
// now. It doesn't matter where the memory
// was allocated. We have the only
// pointer to it now. mymsg()'s
// variables were all stack local
// and were destroyed when it returned.
free(memptr); // We can free the memory memptr points to now.
// No where else has or needs it at this point.
memptr = NULL; // Do this so we always know this pointer doesn't
// point to valid memory anymore. Because
// once the memory is freed contents must be
// considered garbage. If you try to free()
// memory at that address more than once
// it breaks the memory allocator, introducing
// nasty difficult to diagnose bug(s).
// Most modern C environments make freeing NULL
// a NOP (i.e. safe) so you can reduce risk of
// of double-free bugs if you set pointers to null
// after freeing them, however, if you keep multiple
// pointers to the same memory there's
// still risk you might free the same memory
// more than once via another pointer if you're
// not careful.
}
Upvotes: 4
Reputation: 1096
What would happen with x = 51 after declaring int *x; Would just a '51' be stored in the pointer, so it'd be pointing to some error "51" location?
It would do that, yes. If you tried to dereference it, you would get a segmentation fault.
What happens if you say &x ? would it just print the memory location that the pointer is sitting in?
Yes.
A function declaration is function(int *x) but calling the function the form is function(&x). Why?
With int *x
you declare that you're taking a memory address as an argument. With &x
you're getting the memory address of x
, which you're passing to the function.
malloc() I dont understand "WHY" it works, I understand what it does however. Since in the C library definition it returns a "pointer" to the requested memory.
I can see why you don't understand it, your current idea of it is a bit vague.
The full definition of malloc
is void *malloc(size_t size)
. It works by telling the operating system to allocate size
bytes of memory for you. Once it has done that, it will return the memory address of the beginning of the allocated block of memory in form of a pointer. This is the opposite of stack allocation, being heap allocation, but I won't go into detail on the difference.
To clarify, void*
more or less means "pointer to anything", which means you can cast the pointer to the new block of memory (explicitly or implicitly) to become a pointer to any data type. This means you could treat 4 allocated bytes as an int
, since an int
is (usually) 4 bytes big, for example.
x = (int *) malloc (sizeof (int)); is putting a pointer in x......but x is a pointer already? So is it pointing to another pointer? I've also seen it written like this x = malloc(sizeof(int)); .....whats the difference?
I've explained part of this already in the previous paragraph.
In C++, you need to cast the void*
to int*
explicitly, meaning you need to put (int*)
in front. However, C is glad to do this cast implicitly, meaning it will be put there for you, which means both variants are valid depending on the language.
The ** operator, I'd assume it means "pointer to a pointer"....but I guess maybe I don't understand when/why this would come into play?
Yes, it's a pointer to a pointer (a double pointer). You can even have a triple pointer with ***
. You can dereference "multi-pointers" like these fully with the same amount of asterisks (e.g. **a
).
You would use this when you need to reassign a heap-allocated variable from within a function, for example. Here's some code:
object *a = malloc(sizeof(object));
void reallocate_object(object **b) {
// Doing *b = x here is the same as doing a = x directly.
*b = malloc(sizeof(object));
}
reallocate_object(&a);
Upvotes: 3
Reputation: 1465
A pointer is a variable whose value is the address of another variable. So, yes, if you do x = 51
, you're saying the address is 51, most likely corrupting memory (unless you're sure the address 51 is actually correct)
Yes. You could use printf("Address of variable: %x\n", &x);
and see the address.
In the declaration you're saying "I expect a pointer" and when you call it, well, you want to pass the pointer - remember, the pointer is just the address of another variable.
The short answer is you don't need to cast at all b/c there are no benefits, only potential risks. See here for more details.
Yes, it means pointer to a pointer. One example of where this comes in handy is an array of strings: each string is a collection of chars, the first of which is the "first" pointer. Then you have a secondary pointer to this collection of pointers.
Side note, see if you grab a copy of The C Programming Language, it's very well written and I think it might help.
Upvotes: 3