This question already has answers here:
How do pointer-to-pointers work in C? (and when might you use them?)
(14 answers)
Closed 9 years ago.
How do you exactly use the operator ** (pointer to a pointer)?
I saw these operator used to declare a variable and is declared by a structure such as
struct name_of_struct **p_strutture;
What does it do exactly? What is the variable created?
How is this equivalent to *ptr[]?
What is its significance?
When is using a pointer to a pointer important in a program?
A pointer to a pointer basically stores the address of another pointer. A variable has a memory location and a pointer variable is used to store this address. Similarly a pointer variable has a memory address and a pointer to a pointer stores such a memory address
The type struct name_of_struct ** is a pointer to a pointer to struct
name_of_struct see for example here:
// strutture is a struct name_of_struct object
struct name_of_struct strutture;
// p1_strutture is a struct name_of_struct * object
struct name_of_struct *p1_strutture = &strutture;
// p_strutture is a struct name_of_struct ** object
struct name_of_struct **p_strutture = &p1_strutture;
The & operator yields a pointer to an object.
If you declare:
char **myPointer;
you get a pointer pointing to a pointer.
Why would you do such a thing?
If you want for example save some characters (text) you could use a two dimensional array, or you could use a pointer to a pointer.
With the two dimensional array the longest word would "assign" your array size (so a very short word would waste memory). With a pointer to a pointer you do not waste memory! So more elegant in this case would be an array of pointers and every pointer inside of that array points to an array of char.
myPointer = calloc(2, sizeof(char*));
char pointer1[] = "hello";
char pointer2[] = "world";
*myPointer = pointer1;
*(myPointer + 1) = pointer2;
The value of *myPointer would give you the address of pointer1.
The value of of *pointer1 would give you 'h'
This would be the same: *( (*myPointer)) and would also have value: 'h'
With: *( (*myPoniter) + 1) you get as value: 'e'
And *( *(myPointer + 1) ) would return: 'w'
A pointer to a pointer stores the address of a pointer variable.A pointer variable is assigned a memory location just like some other variable . The actual data type of the value of all pointers, whether integer, float, character, or otherwise, is the same, a long hexadecimal number that represents a memory address.
But remember that representation of pointer values depends on the platform. They may be simple integral values (as in a flat memory model), or they may be structured values like a page number and an offset (for a segmented model), or they may be something else entirely.
Related
I am checking out a tutorial video about heap from Bucky on YT.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <math.h>
int n, howMany;
int total;
float average = 0.0;
int * pointsArray;
printf("How many numbers do you want to average?\n");
scanf(" %d", &howMany);
pointsArray = (int *) malloc(howMany * sizeof(int));
printf("Enter numbers! \n");
for(n = 0; n<howMany; n++){
scanf(" %d", &pointsArray[n]);
total += pointsArray[n];
}
average = (float)total /(float)howMany;
printf("average is %f", average);
free(pointsArray);
return 0;
}
I don't understand how pointer-pointsArray changed from a pointer to a pointer array in the above for loop.
I have knowledge on rvalue and Ivalue in variable. I would appreciate if you may include these concept in the answer.
At what line did pointsArray become a pointer array?
pointsArray = (int *) malloc(howMany * sizeof(int)); should only increase the memory size of pointsArray.
Why complier knows how to input value in array when complier sees &pointsArray[n]?
I am able to identify my problem should lie in my confusion of array and pointer that becomes an array. May I have a clear definition so that I can separate them?
Thanks a lot. Please let me know if my question is unclear. I will try to improve it.
I don't understand how pointer-pointsArray changed from a pointer to a
pointer array in the above for loop. I have knowledge on rvalue and
Ivalue in variable. I would appreciate if you may include these
concept in the answer.
At what line did pointsArray become a pointer array? pointsArray = (int *) malloc(howMany * sizeof(int)); should only increase the memory
size of pointsArray.
First, let's start with the basics. A pointer is not an array, and an array is not a pointer, they are two separate types in C. An array type is converted to a pointer to the first element of the array on access as provided in C11 Standard - 6.3.2.1 Lvalues, arrays, and function designators(p3)
int * pointsArray;
...
pointsArray = (int *) malloc(howMany * sizeof(int));
What is pointsArray? (it is a pointer to type int).
Well, What is a Pointer?
A pointer is simply a normal variable that holds the address of something else as its value. In other words, a pointer points to the address where something else can be found. Where you normally think of a variable holding an immediate values, such as int a = 5;, a pointer would simply hold the address where 5 is stored in memory, e.g. int *b = &a; declares b as a pointer to type int and initializes its value to the address where 5 is stored in memory (e.g. b points to a -- where 5 is currently stored). It works the same way regardless what type of object the pointer points to.
Pointer arithmetic will work the same for all pointers regardless of the type because the type of the pointer controls the pointer arithmetic, e.g. with a char * pointer, pointer+1 points to the next byte after pointer. For an int * pointer (normal 4-byte integer), pointer+1 will point to the next integer at an offset 4-bytes after pointer. (so a pointer, is just a pointer.... where arithmetic is automatically handled by the type)
At what line did pointsArray become a pointer array? pointsArray = (int *) malloc(howMany * sizeof(int)); should only increase the memory
size of pointsArray.
Recall, "a pointer is not an array and an array is not a pointer." An array is declared either with:
type name[CONST]; /* declares an array of type with CONST elements */
type name[var]; /* declares a VLA C99+ with var no. of elements */
type name[] = { 1, 2, 3 }; /* declares & initializes an array of 3 elements */
Constrast with:
type *name; /* declares a pointer to type */
In the case of an array with a constant number of elements or with an initialization list, automatic-storage is provided for the array. Storage for the variable-length array (VLA) is similar but within another segment (generally within .bss [block stated by symbol]). On access (except when "it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, or is a string literal used to initialize an array") an array is converted pointer to type that points to the initial element of the array object and is not an lvalue. 6.3.2.1(p3) (You will often see the phrase an "Array decays to a pointer" -- which is referring to this conversion)
(Note: it does not work in reverse, a pointer is never converted to an array)
The declaration type *name; declares name as a pointer to type. It is uninitialized and it holds an indeterminate address. Any attempt to access or otherwise make use of an uninitialized pointer invokes Undefined Behavior (frequently leading to a Segmentation Fault). The pointer must hold a valid address (e.g. it must point to valid storage) before you can access the memory. The easiest way to provide valid storage for a pointer is to dynamically allocate a block of memory and assign the starting address for the block to the pointer. This is done in your code with:
pointsArray = (int *) malloc(howMany * sizeof(int));
(note: there is no need to cast the return of malloc, it is unnecessary. See: Do I cast the result of malloc?)
A better approach would be:
pointsArray = malloc (howMany * sizeof *pointsArray);
(pointsArray is type int*, so *pointsArray is type int. If you use the derefernced pointer as your type-size, you will eliminate the potential for type-size error)
Above, malloc reserves a valid block of memory guaranteed to be at least howMany * sizeof *pointsArray bytes in size. The starting address for the block of memory is assigned to pointsArray (e.g. pointsArray now points to that block) The memory has allocated storage duration and remains valid until you free() it, or the program ends. YOU are responsible for preserving a pointer holding the starting address of the block of memory so it can be freed when no longer needed.
You can now store up to howMany integers in the block of memory pointed to by pointsArray. To access the first address for an integer, you can use *(pointArray + 0) (which is just *pointsArray) using pointer notation or you can use pointsArray[0] using array index notation. (the key is to understand that [] acts as a defeference just the same as the '*' in *(name + offset) does. So to access the second element, you can use either *(pointsArray + 1) or pointsArray[1], etc.. While you can use array index notation with a pointer -- that does NOT make the pointer an array or cause it to be converted to one.
Why complier knows how to input value in array when complier sees &pointsArray[n]?
That has more to do with the requirements of scanf than anything funny with pointsArray. Think about it. From man 3 scanf() when using the %d format conversion specifier, scanf:
Matches an optionally signed decimal integer; the next pointer
must be a pointer to int.
So if instead you wanted to read an integer into the variable declared with int a;, your use of scanf would be:
if (scanf ("%d", &a) == 1) {
/* you have a good integer */
}
else {
/* a matching or input failure occurred */
}
For the integer value to be placed by scanf in a, you must provide a pointer to a. It is no different when you want to put the value in the integer pointsArray[n]. How do you provide a pointer to (address of) pointsArray[n]? (answer: you prefix it with the unary '&' address of operator -- &pointsArray[n])
Hopefully this will take care of your No. 3 as well. Look things over and let me know if you have further questions.
Array is contiguous block of memory and variable holds start of memory.
int* pointsArray
pointsArray = malloc(sizeof(*pointsArray) * howMany);
Now pointsArray holds (points to) some block of memory, in this case returned by malloc and you can normally use array annotation to access to memory entries.
Your pointer points to memory of type int which (I assume) is on your machine 4 bytes each. When you trying to access memory pointsArray[n] you are accessing memory locations:
pointsArray[0] = pointsArray + 4 * 0;
pointsArray[1] = pointsArray + 4 * 1;
pointsArray[n] = pointsArray + 4 * n;
If we look very generic way, each index has offset for sizeof(type), in your case type is int which is 4 bytes.
pointsArray[n] = pointsArray + sizeof(*pointsArray) * n
Please not that it is not a good idea to cast return of malloc and that it is better and safer to add sizeof(...) part to beginning of size calculation.
Do I cast the result of malloc?
At what line did pointsArray become a pointer array?
pointsArray = (int *) malloc(howMany * sizeof(int)); should only increase the memory size of pointsArray.
You are correct. It does not become a pointer array.
Why complier knows how to input value in array when complier sees &pointsArray[n]?
The compiler has nothing to do with this. The code is just reading input values to the extent of sizeof(int) (4 bytes) into the memory pointed to by pointsArray. At every iteration of the for loop it moves four bytes and writes the value of the input into that memory location.
I am able to identify my problem should lie in my confusion of array and pointer that becomes an array. May I have a clear definition so that I can separate them?
Since a pointer holds value of an address location, the address of any type including an array is a pointer. So pointer arithmetic can be applied on it.
Array is just a continuous memory location, so if you have address of the first element you can access other elements by adding to the first address.
So if you have a pointer which points to first element of the array like here
pointsArray = (int *) malloc(howMany * sizeof(int));
pointsArray points to the first element.
Now to access other elements you can use pointsArray[n] which translates to pointsArray + sizeof(*pointsArray) * n (address of the nth element) to access other elements.
Pointer is just an address (index) of a specific cell in the memory and it knows the basic length of its type, e.g. int32_t *p = 0x12345678 is an address at byte 0x12345678 with length 4 bytes. So when we do p+1, the result is 0x1234567c. Note Pointer itself is a type with a length of 4 or 8 bytes depending on your box.
For your question,
pointsArray is always and only a pointer of int. it doesn't know any information about the array, e.g. the length of the array. after the line pointsArray = (int *) malloc(howMany * sizeof(int)), pointsArray has a valid value (an address), which is the address of the memory allocated for an int array. (pointsArray doesn't know the length of the array).
for &pointsArray[n], compiler just write to the memory of address pointsArray + n.
The name of an array is very similar to a const pointer (the only difference I remember is that when you use sizeof to the name of an array you can get the size of the array while for a const pointer you get the size of the pointer). In C, I prefer not to use the concept of array, just consider it as a const pointer of some type.
struct packet_event *packet_event_p[8];
What does this mean ? Is it a pointer to an array of structure data type (struct packet_event) that has 8 elements ? And how could I make use of this pointer ?
Is it different from :
struct packet_event **packet_event_p;
If yes, how could I use this pointer ?
The first one:
struct packet_event *packet_event_p[8];
stands for 'declare packet_event_p as an array of 8 pointers to struct packet_event'. Thus, you create an array packet_event_p of 8 elements, which are pointers to the struct packet_event. Please see this link.
whereas the second one:
struct packet_event **packet_event_p;
stands for 'declare packet_event_p as pointer to pointer to struct packet_event'. Please see this link.
Hope this is helpful.
The first declaration :
struct packet_event *packet_event_p[8];
defines an array of 8 elements, each element of which is a pointer to struct packet_event . In other words, you have an array of 8 pointers, and each one points to a struct packet_event.
And how could I make use of this pointer ?
You can allocate memory for a struct packet_event and set a pointer of your array point to it, like this :
struct packet_event *ptr = malloc(sizeof(struct packet_event));
if (ptr == NULL)
printf ("Error\n");
else
packet_event_p[0] = ptr; //choose a pointer packet_event_p[0] - packet_event_p[7]
The second declaration :
struct packet_event **packet_event_p;
is different, as you declare a pointer (and not an array), named packet_event_p, which points to a pointer to struct packet_event.
If yes, how could I use this pointer ?
Allocate memory for the double pointer packet_event_p. See this link for allocating memory for double pointers.
It is true that arrays can be decayed to pointers, but they are not the same.
regarding the type it is "Array of 8 pointers to a struct of packed event"
reading the types in C usually goes in some sort of a whirlwind fashion. To properly to do, you can read this here.
Usually when you are passing this type as function argument, you will also add the size of the array, or use an external known variable to mark its length. Usually function declarations will be pointers instead of arrays type. I think even that the compiler does automatically (comments about that will be useful)
One different between those types can be seen using the sizeof operator. when applied on variable which is known to be an array type, then the result is the entire size of the array. Otherwise it will be a size of a pointer, which might be 4 byte or 8 byte (depending if its a 64/32bit machine).
#include<stdio.h>
#include<stdlib.h>
int main(){
int myChr[4][8];
printf("%x\n",myChr);
printf("%x\n",&myChr);
printf("%x\n",*myChr);
return 0;
}
After executing the above program, I get the same address as output. Do they own different value or all of them have same value? How to prove that? (*Maybe need to assume values to array, I don't know)
myChr is the address on the stack of your array.
&mychr, in this case, is probably going to give you the same value as it is the address of the pointer on the stack.
*myChr is the address of 1st entry of myChr[4][8] entry, which in the case is still the original address.
**myChar would give you the value of myChr[0][0] - in this case garbage as you have not actually assigned anything to your array.
myChar is a int [4][8].
In the printf expression:
myChar is of type int (*)[8] (after application of C array to pointer conversion rule from int [4][8])
&myChar is of type int (*) [4][8]
*myChar is of type int * (after application of C array to pointer conversion rule from int [4])
All the expressions have different types but they point to the same memory address, that is:
(void *) myChar == (void *) &myChar == (void *) *myChar
Note that the valid way to print a pointer value is to use p conversion specifier and cast the pointer to void * if it is of a different type.
Arrays are simply named extents of memory. So the address of an array is the address of the extent it occupies. At the same time it is the address of the first element of the array because it occupies the initial part of the extent.
Thus you have:
this statement
printf("%x\n",myChr);
displays the address of the first element of the array because array name is implicitly converted to pointer to its first element;
this statement
printf("%x\n",&myChr);
displays the address of the array that is the same address as above because it is the address of the allocated extent;
this statement
printf("%x\n",*myChr);
displays the same address. Why? As I have already said the name of the array is implicitly converted to pointer to its first element. The element of the array is in turn a one-dimensional array. So in expression this one-dimensional array *myChr (the first element of the original two-dimensional array) in turn is converted to pointer to its first element.
So in all three cases you display this address :)
&myChr[0][0]
I'm trying to find out how can I use a pointer to access an array of struct
#include<stdio.h>
struct p
{
int x;
char y;
};
int main()
{
struct p p1[]={1,92,3,94,5,96};
struct p *ptr1=p1;
printf("size of p1 = %i\n",sizeof(p1));
//here is my question, how can I use ptr1 to access the next element of the array
//of the struct?
printf("%i %c\n",ptr1->x,ptr1->y);
int x=(sizeof(p1)/3);
if(x == sizeof(int)+sizeof(char))
printf("%d\n",ptr1->x);
else
printf("falsen\n");
return 0;
}
//here is my question, how can I use ptr1 to access the next element of the array
of the struct?
I tried to write this line of code but an error appeared
printf("%i %c\n",ptr1[0]->x,ptr1[1]->y);
the error was
invalid type of argument '->'(have'struct p')
do I have to declare ptr1 as an array of pointers?
and if I don't know the size of the array of struct how can I declare an array of pointers,
another question here, what should be the size of the pointer? sizeof(ptr1)?
I've tried this line of code
printf("size of ptr1 = %i",sizeof(ptr1));
and the answer was 4 ?!!HOW COME?
thanks
If you want to use ptr1 to access the next, i.e. the second, element in the struct just use array notation on the value
int secondX = ptr1[1].x
char secondY = ptr1[1].y
The sizeof(ptr1) expression returns 4 because that is the typical size of pointers on x86 platforms
If you want to access the second element of the array of struct type then just increment increment pointer Like:
ptr1++;
now pointer will point to the second element of array of struct type.
and your second answer is:
pointer holds the address of the variable and address of the variable is considered as integer value. So based on the machine pointer size is also as integer. Check in your machine the integer size should be 4 that's why it is showing you size of the pointer 4.
By using the array index notation [ ], you effectively dereference the pointer. For example, ptr1[1] can be written *((ptr1)+(1)). In other words, ptr1[1] is of type struct p, not struct p *.
Because it is not a pointer, you must use the . operator to access the elements of the structure. Changing your code to ptr1[1].x works for example. If you want to use the -> notation, you can instead write (ptr1 + 1)->x. The -> operator dereferences the pointer.
If you wanted, you could use (*(ptr1 + 1)).x to accomplish the same thing, dereferencing the pointer more explicitly, but this may prevent some compilers from optimising your code and also is less readable (a number of CPUs allow for indexed access such that ptr1[1] may only require 1 instruction whereas *(ptr1 + 1) might require 3 instructions: a load operation for ptr, an addition operation to do +1, and a dereference operation.)
In response to your other question, sizeof ptr1 is 4 because that is the size of the pointer on your machine. Mine for example prints 8 because it is 64-bit and has 8 bits per byte. I'm guessing you have a 32-bit OS running, so it prints 4 because it is 32-bit with 8 bits per byte.
As I know, when a pointer is passed into a function, it becomes merely a copy of the real pointer. Now, I want the real pointer to be changed without having to return a pointer from a function. For example:
int *ptr;
void allocateMemory(int *pointer)
{
pointer = malloc(sizeof(int));
}
allocateMemory(ptr);
Another thing, which is, how can I allocate memory to 2 or more dimensional arrays? Not by subscript, but by pointer arithmetic. Is this:
int array[2][3];
array[2][1] = 10;
the same as:
int **array;
*(*(array+2)+1) = 10
Also, why do I have to pass in the memory address of a pointer to a function, not the actual pointer itself. For example:
int *a;
why not:
allocateMemory(*a)
but
allocateMemory(a)
I know I always have to do this, but I really don't understand why. Please explain to me.
The last thing is, in a pointer like this:
int *a;
Is a the address of the memory containing the actual value, or the memory address of the pointer? I always think a is the memory address of the actual value it is pointing, but I am not sure about this. By the way, when printing such pointer like this:
printf("Is this address of integer it is pointing to?%p\n",a);
printf("Is this address of the pointer itself?%p\n",&a);
I'll try to tackle these one at a time:
Now, I want the real pointer to be changed without having to return a pointer from a function.
You need to use one more layer of indirection:
int *ptr;
void allocateMemory(int **pointer)
{
*pointer = malloc(sizeof(int));
}
allocateMemory(&ptr);
Here is a good explanation from the comp.lang.c FAQ.
Another thing, which is, how can I allocate memory to 2 or more dimensional arrays?
One allocation for the first dimension, and then a loop of allocations for the other dimension:
int **x = malloc(sizeof(int *) * 2);
for (i = 0; i < 2; i++)
x[i] = malloc(sizeof(int) * 3);
Again, here is link to this exact question from the comp.lang.c FAQ.
Is this:
int array[2][3];
array[2][1] = 10;
the same as:
int **array;
*(*(array+2)+1) = 10
ABSOLUTELY NOT. Pointers and arrays are different. You can sometimes use them interchangeably, however. Check out these questions from the comp.lang.c FAQ.
Also, why do I have to pass in the memory address of a pointer to a function, not the actual pointer itself?
why not:
allocateMemory(*a)
It's two things - C doesn't have pass-by-reference, except where you implement it yourself by passing pointers, and in this case also because a isn't initialized yet - if you were to dereference it, you would cause undefined behaviour. This problem is a similar case to this one, found in the comp.lang.c FAQ.
int *a;
Is a the address of the memory containing the actual value, or the memory address of the pointer?
That question doesn't really make sense to me, but I'll try to explain. a (when correctly initialized - your example here is not) is an address (the pointer itself). *a is the object being pointed to - in this case that would be an int.
By the way, when printing such pointer like this:
printf("Is this address of integer it is pointing to?%p\n",a);
printf("Is this address of the pointer itself?%p\n",&a);
Correct in both cases.
To answer your first question, you need to pass a pointer to a pointer. (int**)
To answer your second question, you can use that syntax to access a location in an existing array.
However, a nested array (int[][]) is not the same as a pointer to a pointer (int**)
To answer your third question:
Writing a passes the value of the variable a, which is a memory address.
Writing *a passes the value pointed to by the variable, which is an actual value, not a memory address.
If the function takes a pointer, that means it wants an address, not a value.
Therefore, you need to pass a, not *a.
Had a been a pointer to a pointer (int**), you would pass *a, not **a.
Your first question:
you could pass a pointer's address:
void allocateMemory(int **pointer) {
*pointer = malloc(sizeof(int));
}
int *ptr;
allocateMemory(&ptr);
or you can return a pointer value:
int *allocateMemory() {
return malloc(sizeof(int));
}
int *ptr = mallocateMemory();
I think you're a little confused about what a pointer actually is.
A pointer is just variable whose value represents an address in memory. So when we say that int *p is pointer to an integer, that just means p is a variable that holds a number that is the memory address of an int.
If you want a function to allocate a buffer of integers and change the value in the variable p, that function needs to know where in memory p is stored. So you have to give it a pointer to p (i.e., the memory address of p), which itself is a pointer to an integer, so what the function needs is a pointer to a pointer to an integer (i.e., a memory address where the function should store a number, which in turn is the memory address of the integers the function allocated), so
void allocateIntBuffer(int **pp)
{
// by doing "*pp = whatever" you're telling the compiler to store
// "whatever" not in the pp variable but in the memory address that
// the pp variable is holding.
*pp = malloc(...);
}
// call it like
int *p;
allocateIntBuffer(&p);
I think the key to your questions is to understand that there is nothing special about pointer variables. A pointer is a variable like any other, only that the value stored in that variable is used to represent a position in memory.
Note that returning a pointer or forcing the caller to move the pointer in an out of a void * temp variable is the only way you can make use of the void * type to allow your function to work with different pointer types. char **, int **, etc. are not convertible to void **. As such, I would advise against what you're trying to do, and instead use the return value for functions that need to update a pointer, unless your function by design only works with a specific type. In particular, simple malloc wrappers that try to change the interface to pass pointer-to-pointer types are inherently broken.