I am learning C++ using C++ Primer 5th edition. In particular, i read about void*. There it is written that:
We cannot use a void* to operate on the object it addresses—we don’t know that object’s type, and the type determines what operations we can perform on that object.
void*: Pointer type that can point to any nonconst type. Such pointers may not
be dereferenced.
My question is that if we're not allowed to use a void* to operate on the object it addressess then why do we need a void*. Also, i am not sure if the above quoted statement from C++ Primer is technically correct because i am not able to understand what it is conveying. Maybe some examples can help me understand what the author meant when he said that "we cannot use a void* to operate on the object it addresses". So can someone please provide some example to clarify what the author meant and whether he is correct or incorrect in saying the above statement.
My question is that if we're not allowed to use a void* to operate on the object it addressess then why do we need a void*
It's indeed quite rare to need void* in C++. It's more common in C.
But where it's useful is type-erasure. For example, try to store an object of any type in a variable, determining the type at runtime. You'll find that hiding the type becomes essential to achieve that task.
What you may be missing is that it is possible to convert the void* back to the typed pointer afterwards (or in special cases, you can reinterpret as another pointer type), which allows you to operate on the object.
Maybe some examples can help me understand what the author meant when he said that "we cannot use a void* to operate on the object it addresses"
Example:
int i;
int* int_ptr = &i;
void* void_ptr = &i;
*int_ptr = 42; // OK
*void_ptr = 42; // ill-formed
As the example demonstrates, we cannot modify the pointed int object through the pointer to void.
so since a void* has no size(as written in the answer by PMF)
Their answer is misleading or you've misunderstood. The pointer has a size. But since there is no information about the type of the pointed object, the size of the pointed object is unknown. In a way, that's part of why it can point to an object of any size.
so how can a int* on the right hand side be implicitly converted to a void*
All pointers to objects can implicitly be converted to void* because the language rules say so.
Yes, the author is right.
A pointer of type void* cannot be dereferenced, because it has no size1. The compiler would not know how much data he needs to get from that address if you try to access it:
void* myData = std::malloc(1000); // Allocate some memory (note that the return type of malloc() is void*)
int value = *myData; // Error, can't dereference
int field = myData->myField; // Error, a void pointer obviously has no fields
The first example fails because the compiler doesn't know how much data to get. We need to tell it the size of the data to get:
int value = *(int*)myData; // Now fine, we have casted the pointer to int*
int value = *(char*)myData; // Fine too, but NOT the same as above!
or, to be more in the C++-world:
int value = *static_cast<int*>(myData);
int value = *static_cast<char*>(myData);
The two examples return a different result, because the first gets an integer (32 bit on most systems) from the target address, while the second only gets a single byte and then moves that to a larger variable.
The reason why the use of void* is sometimes still useful is when the type of data doesn't matter much, like when just copying stuff around. Methods such as memset or memcpy take void* parameters, since they don't care about the actual structure of the data (but they need to be given the size explicitly). When working in C++ (as opposed to C) you'll not use these very often, though.
1 "No size" applies to the size of the destination object, not the size of the variable containing the pointer. sizeof(void*) is perfectly valid and returns, the size of a pointer variable. This is always equal to any other pointer size, so sizeof(void*)==sizeof(int*)==sizeof(MyClass*) is always true (for 99% of today's compilers at least). The type of the pointer however defines the size of the element it points to. And that is required for the compiler so he knows how much data he needs to get, or, when used with + or -, how much to add or subtract to get the address of the next or previous elements.
void * is basically a catch-all type. Any pointer type can be implicitly cast to void * without getting any errors. As such, it is mostly used in low level data manipulations, where all that matters is the data that some memory block contains, rather than what the data represents. On the flip side, when you have a void * pointer, it is impossible to determine directly which type it was originally. That's why you can't operate on the object it addresses.
if we try something like
typedef struct foo {
int key;
int value;
} t_foo;
void try_fill_with_zero(void *destination) {
destination->key = 0;
destination->value = 0;
}
int main() {
t_foo *foo_instance = malloc(sizeof(t_foo));
try_fill_with_zero(foo_instance, sizeof(t_foo));
}
we will get a compilation error because it is impossible to determine what type void *destination was, as soon as the address gets into try_fill_with_zero. That's an example of being unable to "use a void* to operate on the object it addresses"
Typically you will see something like this:
typedef struct foo {
int key;
int value;
} t_foo;
void init_with_zero(void *destination, size_t bytes) {
unsigned char *to_fill = (unsigned char *)destination;
for (int i = 0; i < bytes; i++) {
to_fill[i] = 0;
}
}
int main() {
t_foo *foo_instance = malloc(sizeof(t_foo));
int test_int;
init_with_zero(foo_instance, sizeof(t_foo));
init_with_zero(&test_int, sizeof(int));
}
Here we can operate on the memory that we pass to init_with_zero represented as bytes.
You can think of void * as representing missing knowledge about the associated type of the data at this address. You may still cast it to something else and then dereference it, if you know what is behind it. Example:
int n = 5;
void * p = (void *) &n;
At this point, p we have lost the type information for p and thus, the compiler does not know what to do with it. But if you know this p is an address to an integer, then you can use that information:
int * q = (int *) p;
int m = *q;
And m will be equal to n.
void is not a type like any other. There is no object of type void. Hence, there exists no way of operating on such pointers.
This is one of my favourite kind of questions because at first I was also so confused about void pointers.
Like the rest of the Answers above void * refers to a generic type of data.
Being a void pointer you must understand that it only holds the address of some kind of data or object.
No other information about the object itself, at first you are asking yourself why do you even need this if it's only able to hold an address. That's because you can still cast your pointer to a more specific kind of data, and that's the real power.
Making generic functions that works with all kind of data.
And to be more clear let's say you want to implement generic sorting algorithm.
The sorting algorithm has basically 2 steps:
The algorithm itself.
The comparation between the objects.
Here we will also talk about pointer functions.
Let's take for example qsort built in function
void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*))
We see that it takes the next parameters:
base − This is the pointer to the first element of the array to be sorted.
nitems − This is the number of elements in the array pointed by base.
size − This is the size in bytes of each element in the array.
compar − This is the function that compares two elements.
And based on the article that I referenced above we can do something like this:
int values[] = { 88, 56, 100, 2, 25 };
int cmpfunc (const void * a, const void * b) {
return ( *(int*)a - *(int*)b );
}
int main () {
int n;
printf("Before sorting the list is: \n");
for( n = 0 ; n < 5; n++ ) {
printf("%d ", values[n]);
}
qsort(values, 5, sizeof(int), cmpfunc);
printf("\nAfter sorting the list is: \n");
for( n = 0 ; n < 5; n++ ) {
printf("%d ", values[n]);
}
return(0);
}
Where you can define your own custom compare function that can match any kind of data, there can be even a more complex data structure like a class instance of some kind of object you just define. Let's say a Person class, that has a field age and you want to sort all Persons by age.
And that's one example where you can use void * , you can abstract this and create other use cases based on this example.
It is true that is a C example, but I think, being something that appeared in C can make more sense of the real usage of void *. If you can understand what you can do with void * you are good to go.
For C++ you can also check templates, templates can let you achieve a generic type for your functions / objects.
I can't understand some basic thing in c++ and have been wondering. Please help me.
I understand that p points to memory that would be a 2D int matrix of 3x4 size.
int(*p)[3][4];
1) Why can't I allocate memory like following?
p = new int[3][4];
2) It should be like following to work. But why?
p = new int [1][3][4]; //or new int [5][3][4]; etc
3) What does following line of code mean? It is semantically correct but what is it doing? What is significance of empty [] in following line?
p = new int [ ][3][4];
c++ is a strongly typed language. int is not the same as int*. Likewise int[3] is not the same type as int*. But just lightly poke int[3] with a stick and it will fall apart and decay to an int*. c++ does this because c does it.
Why can't I allocate memory like following?
p = new int[3][4];
Because the new is returning a pointer to int[4]:
auto p1 = new int[3][4]; // int(*p1)[4]
The array has decayed to a pointer. It has lost the type and first dimension. It would be best to avoid pointers for arrays and stick to using templates and references. Or better yet, prefer std::vector or std::array.
You could have multiple pointers to the same address, but with different types, which can be confusing.
2) It should be like following to work. But why?
p = new int [1][3][4];
In this example the array of int[3][4]s has also decayed to a pointer:
auto p2 = new int [1][3][4]; // int(*p2)[3][4]
So here the value returned by new can be assigned to p because it has the same type. Note however that the pointer type doesn't include information about the size of the array, it only has a type that points to elements which happen to be arrays of a lower dimension (that haven't decayed to pointers).
3) What does following line of code mean? It is semantically correct
but what is it doing? What is significance of empty [] in following
line?
p = new int [ ][3][4];
This might not always compile, and if it does then it is a compiler extension that will determine the value of the empty square brackets.
Because in C, "int *p" has two interpretations.
You can consider P to be a pointer to a single integer, but it can also be considered to be a pointer to an array of integer.
A common example, strings.
char *a = "hello";
"a" is a pointer to a single character, 'h', but more commonly it is treated as a pointer to an array of characters, aka a string.
So, you can do this:
char * a = new char[6];
strcpy(a, "hello");
I believe that your third example is not valid C++.
While this:
p = new int [9][3][4];
Allocates an array of 9 two dimensional arrays of 3x4.
Try this test:
int test()
{
int(* p)[3][4] = new int[1][3][4];
printf("sizeof(p)=%d, sizeof(*p)=%d\n", sizeof(p), sizeof(*p) / sizeof(int));
size_t q1 = (size_t)&p[0][0][0];
size_t q2 = (size_t)&p[1][0][0];
printf("p, diff: %d\n", (q2 - q1) / sizeof(int));
size_t r1 = (size_t)&p[0][0][0];
size_t r2 = (size_t)&p[0][1][0];
printf("p, diff: %d\n", (r2 - r1) / sizeof(int));
size_t s1 = (size_t)&p[0][0][0];
size_t s2 = (size_t)&p[0][0][1];
printf("p, diff: %d\n", (s2 - s1) / sizeof(int));
return 0;
}
I'm never used C++ before, and I used OpenCV background subtraction MOG (Mixture of Gaussian) function in Python and I need to understand how the program works, the OpenCV program line 123 there's command bgmodel.create( 1, frameSize.height*frameSize.width*nmixtures*(2 + 2*nchannels), CV_32F );.. I found the .create function is to allocate new data from here with I assumed the parameter inside was (int ndims, const int* sizes, int type), my question is what the * mean, is it multiplication or pointer?
The asterisk (*) has three use cases:
The multiply operator: 2 * 3
A pointer type declaration: int* p;
Dereferencing a pointer (making it a reference to the value the
pointer is pointing to): *p = 6;
Example:
int i;
int* p = &i; // Sorry, introducing another confusion, taking the address of i
*p = 2 * 3;
// Now *p and i have the value 6
In the question, only multiplications are involved
If we look at your example:
bgmodel.create( 1, frameSize.height*frameSize.width*nmixtures*(2 + 2*nchannels), CV_32F );
We want to know if the * is a pointer dereference or is it multiplication. The form a a pointer dereference is
*pointer_type;
Which doesn't work here as every * is preceded by another variable. If we look at the syntax for multiplication we have:
some_type * some_type;
Now that matches what we have with variables on each side of the *
Now lets say you want to dereference a pointer and multiply it with something. To do that we will wrap the dereferencing in parentheses
some_type * (*pointer_type);
This question already has answers here:
How do I use arrays in C++?
(5 answers)
Closed 7 years ago.
I'm trying to understand the different ways of declaring an array (of one or two dimensions) in C++ and what exactly they return (pointers, pointers to pointers, etc.)
Here are some examples:
int A[2][2] = {0,1,2,3};
int A[2][2] = {{0,1},{2,3}};
int **A = new int*[2];
int *A = new int[2][2];
In each case, what exactly is A? Is it a pointer, double pointer? What happens when I do A+1? Are these all valid ways of declaring matrices?
Also, why does the first option not need the second set of curly braces to define "columns"?
Looks like you got a plethora of answers while I was writing mine, but I might as well post my answer anyway so I don't feel like it was all for nothing...
(all sizeof results taken from VC2012 - 32 bit build, pointer sizes would, of course, double with a 64 bit build)
size_t f0(int* I);
size_t f1(int I[]);
size_t f2(int I[2]);
int main(int argc, char** argv)
{
// A0, A1, and A2 are local (on the stack) two-by-two integer arrays
// (they are technically not pointers)
// nested braces not needed because the array dimensions are explicit [2][2]
int A0[2][2] = {0,1,2,3};
// nested braces needed because the array dimensions are not explicit,
//so the braces let the compiler deduce that the missing dimension is 2
int A1[][2] = {{0,1},{2,3}};
// this still works, of course. Very explicit.
int A2[2][2] = {{0,1},{2,3}};
// A3 is a pointer to an integer pointer. New constructs an array of two
// integer pointers (on the heap) and returns a pointer to the first one.
int **A3 = new int*[2];
// if you wanted to access A3 with a double subscript, you would have to
// make the 2 int pointers in the array point to something valid as well
A3[0] = new int[2];
A3[1] = new int[2];
A3[0][0] = 7;
// this one doesn't compile because new doesn't return "pointer to int"
// when it is called like this
int *A4_1 = new int[2][2];
// this edit of the above works but can be confusing
int (*A4_2)[2] = new int[2][2];
// it allocates a two-by-two array of integers and returns a pointer to
// where the first integer is, however the type of the pointer that it
// returns is "pointer to integer array"
// now it works like the 2by2 arrays from earlier,
// but A4_2 is a pointer to the **heap**
A4_2[0][0] = 6;
A4_2[0][1] = 7;
A4_2[1][0] = 8;
A4_2[1][1] = 9;
// looking at the sizes can shed some light on subtle differences here
// between pointers and arrays
A0[0][0] = sizeof(A0); // 16 // typeof(A0) is int[2][2] (2by2 int array, 4 ints total, 16 bytes)
A0[0][1] = sizeof(A0[0]); // 8 // typeof(A0[0]) is int[2] (array of 2 ints)
A1[0][0] = sizeof(A1); // 16 // typeof(A1) is int[2][2]
A1[0][1] = sizeof(A1[0]); // 8 // typeof(A1[0]) is int[2]
A2[0][0] = sizeof(A2); // 16 // typeof(A2) is int[2][2]
A2[0][1] = sizeof(A2[0]); // 8 // typeof(A1[0]) is int[2]
A3[0][0] = sizeof(A3); // 4 // typeof(A3) is int**
A3[0][1] = sizeof(A3[0]); // 4 // typeof(A3[0]) is int*
A4_2[0][0] = sizeof(A4_2); // 4 // typeof(A4_2) is int(*)[2] (pointer to array of 2 ints)
A4_2[0][1] = sizeof(A4_2[0]); // 8 // typeof(A4_2[0]) is int[2] (the first array of 2 ints)
A4_2[1][0] = sizeof(A4_2[1]); // 8 // typeof(A4_2[1]) is int[2] (the second array of 2 ints)
A4_2[1][1] = sizeof(*A4_2); // 8 // typeof(*A4_2) is int[2] (different way to reference the first array of 2 ints)
// confusion between pointers and arrays often arises from the common practice of
// allowing arrays to transparently decay (implicitly convert) to pointers
A0[1][0] = f0(A0[0]); // f0 returns 4.
// Not surprising because declaration of f0 demands int*
A0[1][1] = f1(A0[0]); // f1 returns 4.
// Still not too surprising because declaration of f1 doesn't
// explicitly specify array size
A2[1][0] = f2(A2[0]); // f2 returns 4.
// Much more surprising because declaration of f2 explicitly says
// it takes "int I[2]"
int B0[25];
B0[0] = sizeof(B0); // 100 == (sizeof(int)*25)
B0[1] = f2(B0); // also compiles and returns 4.
// Don't do this! just be aware that this kind of thing can
// happen when arrays decay.
return 0;
}
// these are always returning 4 above because, when compiled,
// all of these functions actually take int* as an argument
size_t f0(int* I)
{
return sizeof(I);
}
size_t f1(int I[])
{
return sizeof(I);
}
size_t f2(int I[2])
{
return sizeof(I);
}
// indeed, if I try to overload f0 like this, it will not compile.
// it will complain that, "function 'size_t f0(int *)' already has a body"
size_t f0(int I[2])
{
return sizeof(I);
}
yes, this sample has tons of signed/unsigned int mismatch, but that part isn't relevant to the question. Also, don't forget to delete everything created with new and delete[] everything created with new[]
EDIT:
"What happens when I do A+1?" -- I missed this earlier.
Operations like this would be called "pointer arithmetic" (even though I called out toward the top of my answer that some of these are not pointers, but they can turn into pointers).
If I have a pointer P to an array of someType, then subscript access P[n] is exactly the same as using this syntax *(P + n). The compiler will take into account the size of the type being pointed to in both cases. So, the resulting opcode will actually do something like this for you *(P + n*sizeof(someType)) or equivalently *(P + n*sizeof(*P)) because the physical cpu doesn't know or care about all our made up "types". In the end, all pointer offsets have to be a byte count. For consistency, using array names like pointers works the same here.
Turning back to the samples above: A0, A1, A2, and A4_2 all behave the same with pointer arithmetic.
A0[0] is the same as *(A0+0), which references the first int[2] of A0
similarly:
A0[1] is the same as *(A0+1) which offsets the "pointer" by sizeof(A0[0]) (i.e. 8, see above) and it ends up referencing the second int[2] of A0
A3 acts slightly differently. This is because A3 is the only one that doesn't store all 4 ints of the 2 by 2 array contiguously. In my example, A3 points to an array of 2 int pointers, each of these point to completely separate arrays of two ints. Using A3[1] or *(A3+1) would still end up directing you to the second of the two int arrays, but it would do it by offsetting only 4bytes from the beginning of A3 (using 32 bit pointers for my purposes) which gives you a pointer that tells you where to find the second two-int array. I hope that makes sense.
For the array declaration, the first specified dimension is the outermost one, an array that contains other arrays.
For the pointer declarations, each * adds another level of indirection.
The syntax was designed, for C, to let declarations mimic the use. Both the C creators and the C++ creator (Bjarne Stroustrup) have described the syntax as a failed experiment. The main problem is that it doesn't follow the usual rules of substitution in mathematics.
In C++11 you can use std::array instead of the square brackets declaration.
Also you can define a similar ptr type builder e.g.
template< class T >
using ptr = T*;
and then write
ptr<int> p;
ptr<ptr<int>> q;
int A[2][2] = {0,1,2,3};
int A[2][2] = {{0,1},{2,3}};
These declare A as array of size 2 of array of size 2 of int. The declarations are absolutely identical.
int **A = new int*[2];
This declares a pointer to pointer to int initialized with an array of two pointers. You should allocate memory for these two pointers as well if you want to use it as two-dimensional array.
int *A = new int[2][2];
And this doesn't compile because the type of right part is pointer to array of size 2 of int which cannot be converted to pointer to int.
In all valid cases A + 1 is the same as &A[1], that means it points to the second element of the array, that is, in case of int A[2][2] to the second array of two ints, and in case of int **A to the second pointer in the array.
The other answers have covered the other declarations but I will explain why you don't need the braces in the first two initializations. The reason why these two initializations are identical:
int A[2][2] = {0,1,2,3};
int A[2][2] = {{0,1},{2,3}};
is because it's covered by aggregate initialization. Braces are allowed to be "elided" (omitted) in this instance.
The C++ standard provides an example in § 8.5.1:
[...]
float y[4][3] = {
{ 1, 3, 5 },
{ 2, 4, 6 },
{ 3, 5, 7 },
};
[...]
In the following example, braces in the initializer-list are elided;
however the initializer-list has the same effect as the
completely-braced initializer-list of the above example,
float y[4][3] = {
1, 3, 5, 2, 4, 6, 3, 5, 7
};
The initializer for y begins with a left brace, but the one for y[0]
does not, therefore three elements from the list are used. Likewise
the next three are taken successively for y[1] and y[2].
Ok I will try it to explain it to you:
This is a initialization. You create a two dimensional array with the values:
A[0][0] -> 0
A[0][1] -> 1
A[1][0] -> 2
A[1][1] -> 3
This is the exactly the same like above, but here you use braces. Do it always like this its better for reading.
int **A means you have a pointer to a pointer of ints. When you do new int*[2] you will reserve memory for 2 Pointer of integer.
This doesn't will be compiled.
int A[2][2] = {0,1,2,3};
int A[2][2] = {{0,1},{2,3}};
These two are equivalent.
Both mean: "I declare a two dimentional array of integers. The array is of size 2 by 2".
Memory however is not two dimensional, it is not laid out in grids, but (conceptionaly) in one long line. In a multi-dimensional array, each row is just allocated in memory right after the previous one.
Because of this, we can go to the memory address pointed to by A and either store two lines of length 2, or one line of length 4, and the end result in memory will be the same.
int **A = new int*[2];
Declares a pointer to a pointer called A.
A stores the address of a pointer to an array of size 2 containing ints. This array is allocated on the heap.
int *A = new int[2][2];
A is a pointer to an int.
That int is the beginning of a 2x2 int array allocated in the heap.
Aparrently this is invalid:
prog.cpp:5:23: error: cannot convert ‘int (*)[2]’ to ‘int*’ in initialization
int *A = new int[2][2];
But due to what we saw with the first two, this will work (and is 100% equivalent):
int *A new int[4];
int A[2][2] = {0,1,2,3};
A is an array of 4 ints. For the coder's convenience, he has decided to declare it as a 2 dimensional array so compiler will allow coder to access it as a two dimensional array. Coder has initialized all elements linearly as they are laid in memory. As usual, since A is an array, A is itself the address of the array so A + 1 (after application of pointer math) offset A by the size of 2 int pointers. Since the address of an array points to the first element of that array, A will point to first element of the second row of the array, value 2.
Edit: Accessing a two dimensional array using a single array operator will operate along the first dimension treating the second as 0. So A[1] is equivalent to A[1][0]. A + 1 results in equivalent pointer addition.
int A[2][2] = {{0,1},{2,3}};
A is an array of 4 ints. For the coder's convenience, he has decided to declare it as a 2 dimensional array so compiler will allow coder to access it as a two dimensional array. Coder has initialized elements by rows. For the same reasons above, A + 1 points to value 2.
int **A = new int*[2];
A is pointer to int pointer that has been initialized to point to an array of 2 pointers to int pointers. Since A is a pointer, A + 1 takes the value of A, which is the address of the pointer array (and thus, first element of the array) and adds 1 (pointer math), where it will now point to the second element of the array. As the array was not initialized, actually doing something with A + 1 (like reading it or writing to it) will be dangerous (who knows what value is there and what that would actually point to, if it's even a valid address).
int *A = new int[2][2];
Edit: as Jarod42 has pointed out, this is invalid. I think this may be closer to what you meant. If not, we can clarify in the comments.
int *A = new int[4];
A is a pointer to int that has been initialized to point to an anonymous array of 4 ints. Since A is a pointer, A + 1 takes the value of A, which is the address of the pointer array (and thus, first element of the array) and adds 1 (pointer math), where it will now point to the second element of the array.
Some takeaways:
In the first two cases, A is the address of an array while in the last two, A is the value of the pointer which happened to be initialized to the address of an array.
In the first two, A cannot be changed once initialized. In the latter two, A can be changed after initialization and point to some other memory.
That said, you need to be careful with how you might use pointers with an array element. Consider the following:
int *a = new int(5);
int *b = new int(6);
int c[2] = {*a, *b};
int *d = a;
c+1 is not the same as d+1. In fact, accessing d+1 is very dangerous. Why? Because c is an array of int that has been initialized by dereferencing a and b. that means that c, is the address of a chunk of memory, where at that memory location is value which has been set to the value pointed to by tovariable a, and at the next memory location that is a value pinned to by variable b. On the other hand d is just the address of a. So you can see, c != d therefore, there is no reason that c + 1 == d + 1.