Take a look at this function signature:
AudioBlock (SampleType *const *channelData, size_t numberOfChannels, size_t startSampleIndex, size_t numberOfSamples)
from here
The main type used if float* so let's think of the signature as
AudioBlock (float *const *channelData, size_t numberOfChannels, size_t startSampleIndex, size_t numberOfSamples)
What does float *const *channelData mean? channelData should be a const pointer to a float pointer? What is a const* something? I don't see the type of the inner pointer.
Suppose I want to create a vector of zeros so I can pass to AudioBlock:
std::vector<float> v(bufferOriginal.getNumChannels()*bufferOriginal.getNumSamples(), 0);
How do I get a float *const *channelData to this vector data?
What does float* const* mean?
float is a fundamental floating point type. T* is a pointer to T. const is a qualifier that applies to whatever is on the left side of it (except when it is the left most token in which case it applies to right). Since both qualifier and the pointer apply to left, it is easies to read from right to left (there are more complicated cases where this simplified rule of thumb is wrong):
float * const * // original
* const * float // reversed
* | const * | float // added spaces and separators
non-const pointer to | const pointer to | non-const float // translated to english
Arrays are an example of more complex cases where just right to left doesn't work. For the more complex rule that works with all compound types, see "clockwise rule" or "spiral rule".
So it's not possible to get a float* const * to the vector data then, right?
You could, if you had a vector like this:
std::vector<float*> vector_of_pointers;
float* const* ptr = vector_of_pointers.data();
You could make element of that vector point to your vector of floats.
vector_of_pointers.push_back(v.data());
This parameter declaration
float *const *channelData
means that the variable channelData (read from tight to left) is a pointer to a constant pointer (the pointer itself that is constant) to a non-constant object of the type float.
To make it more clear consider the following demonstrative program.
#include <stdio.h>
int main(void)
{
float x = 1.1f;
float y = 2.2f;
printf( "x = %f\n", x );
float * const px = &x;
// px = &y; // error: assignment of read-only variable ‘px’
*px = y;
printf( "x = %f\n", x );
float * const * ppx = &px;
// *ppx = &y; // error: assignment of read-only location ‘*ppx’
**ppx = 3.0f;
printf( "x = %f\n", x );
return 0;
}
Its output is
x = 1.100000
x = 2.200000
x = 3.000000
As you can see as the pointer px is a constant variable it has to be initialized when it is declared. You can not change it such a way that it will point to another variable. But you can use pc to change the value of the object pointed to by px. The variable ppx is a pointer to such a pointer.
Related
This question already has answers here:
What is the difference between const int*, const int * const, and int const *?
(23 answers)
Closed last year.
I have a program like below and expect that:
with function void myFunc1 ( const int *x) ==> I cannot change the value of at the memory location that x points to, but can change the memory location that x points to.
with function void myFunc2 ( int const *x) ==> I cannot change the location that x points to as it is a const pointer. But I could change the value at the memory location that x points to.
However, upon compiling the code, I don't see the difference between const int *x vs int const *x:
in both function, the lines *x=8 in both function return error. I didn't expect error from myFunc2 because it is a const pointer, not a pointer to a const value.
in myFunc1, I expected to see value 5 after myFunc1 is close.
Could the experts here explain my 2 unexpected results above ? Here is my code:
#include "stdio.h"
int a = 5; // declared a global,
void myFunc1 ( const int *x) { // const parameter: pointer to a const int value.
// *x= 8; // error: assignment of read-only location ‘* x’ ==> cannot change the value at the location pointed by pointer. This is expected
printf("%d \n ", *x);
x = &a; // can change where the pointer point to.
// a is global and is not loss after closing myFunc2
printf("value in myFunc1: %d \n ", *x);
}
void myFunc2 ( int const *x) { // const parameter: const pointer, cannot change the address that x points to.
// *x= 8; // error: assignment of read-only location ‘* x’
printf("%d \n ", *x);
x = &a; // no compiling error here. This is not expected.
printf("value in myFunc2: %d \n ", *x);
}
int main() {
int *y;
int z = 6;
y = &z;
printf("value before myFunc1: %d \n", *y);
myFunc1(y);
printf("value after myFunc1: %d \n", *y); // expect to print 5. Result: print 6.
printf("value before myFunc2: %d \n", *y);
myFunc2(y);
printf("value after myFunc2: %d \n", *y); // expect to print 8 if the line *x=8 could be compiled . Result: print 6.
return 1;
}
I don't see the different between having 2 parameters (const int *x) vs (int const *x):
That's because int const* and const int* are the same thing.
If you want to make the pointer const, you have to put a const on its right, like this: int * const, a constant pointer to (non-constant) integer.
Unrelated (is it?) note on East const
I am one of those in favour of the so called East const, which means I prefer writing the const always on the right of what it applies to. For instance,
for a "pointer to constant int", I write int const *,
for a "constant pointer to constant int", I write int const * const.
As you see, the sentences in quotes map to the types if you read them right-to-left:
// 1 2 3 4 4 3 2 1
int const * const // constant pointer to constant int
Furthermore, always thinking of const as something that can be put on the right of what it applies to has also other advantages, sometimes in terms of peculiarities of the language that you can discover.
For instance, the following is how I discovered something more about references.
Take the declaration of a function parameter taken by reference to constant: int const& p. If you write it like this and think of it the East const way, it is clear that it declaring a p which is a reference to a constant int, not a constant reference to int.
After all, thinking East const, what would a constant reference to int look like? It'd be int & const, with the const on the right of what we'd like it to apply to, the reference &. However, this syntax is incorrect.
Why is that? Why can't I make a reference constant? Because it always is, as references cannot rebind. The standard simply doesn't let you write something totally redundant as a const applied to a reference.
I received data from some other function to myfunction(const void *data) where pointer data stores the values like {0,0,0,0,0,0,0,40,20,0,0,0,0,0,0}.
I want to access just values from {40,20,0,0,0,0,0,0} and convert into a double type value that should give 8.0 . For accessing and conversion to double type I have tried pointer to double:
double* dptr;
dptr=&(*data+8);
dptr;
that was giving error like
"error: ‘const void*’ is not a pointer-to-object type"
In C you cannot de-reference a void pointer.
So you can type cast the void pointer and use it.
something like this dptr=((double*)data+8); So the data which is void is considered as a double pointer now.
Edit Your post is very unclear. Assuming data is actually a pointer to an array of double the solution is even simpler:
double * pd = static_cast<double const *>(data);
double d0 = pd[0];
double d1 = pd[1];
or (C):
double * pd= (double const *)(data);
double d0 = pd[0];
double d1 = pd[1];
You cannot perform pointer arithmetics and dereferencing on void * so *data or data + 8 are invalid.
I don’t understand exactly what you are trying to do, but here is how you access data in your array:
Assuming the data stored is actually int, to access the 8th element and convert it into double you should write:
double el = static_cast<double>*(static_cast<int const *>(data) + 8));
better yet:
int *p = static_cast<int const *>(data);
double el = static_cast<double>(p[8]);
Please note that is is really important that you convert data to the original pointer type . In my example I used int but you should replace it with what your data actually is.
On that note, if what you are showing as {0,0,0,0,0,0,0,40,20,0,0,0,0,0,0} are actually bytes, then the original pointer type is char * and you should convert to char *.
To clarify furthermore converting data from pointers:
Let’s say you have a pointer to int:
int i = 24;
int *pi = &i;
How would you convert to double the data found on address pi?
// wrong:
double *pd = &i;
cout << *pd << endl;
That is wrong because what you do is converting the pointer type and not the actual data. In effect you interpret the bit pattern found at address pi as a bit pattern representing a double. But that bit pattern represents and int.
What you need to do is retrieve the data as it is: an int and then convert the int to double:
int x = *pi;
double d = (double) x;
#include <stdio.h>
#include <string.h>
double myfunction(const void *data){
double v;
memcpy(&v, data, sizeof(v));
return v;
}
int main (int argc, char *argv[]) {
unsigned char data[] = {0x40,0x20,0,0,0,0,0,0};
int i, len = sizeof(data);
//reverse data If necessary
for(i=0;i<len/2;++i){
unsigned char c = data[i];
data[i] = data[len -1 -i];
data[len -1 -i] = c;
}
double v;
v = myfunction(data);
printf("%f\n", v);//8.000000
return 0;
}
You cannot perform pointer arithmetic in void pointers, since you don't know the size of the inner data (as it says, it is void). You have to typecast it to a type with a known size.
The correct typecasting and pointer arithmetic is as follows (using old C conversions):
char * ptr=(char *)data;
double * myDoublePtr=(double *)(ptr+8);
double myDouble=*myDouble;
Or, as you have two doubles consecutive:
double * ptr=(double *)data;
double myDouble=*(ptr+1); //This will access the second double.
This is because an offset in pointer arithmetics will perform a jump of offset*sizeof(type) bytes, so in a char type, the number of bytes jumped will actually be the same as your offset.
This question specifically relates to C++98, but feel free to pitch in any useful info w/regard to newer standards if you like.
In case you know the answer and want to skip the rest, the short & sweet of it is:
int **w;
int volatile* *x = w; // error
int volatile*const*y = w; // OK
int const *const*z = w; // OK
Why would const be necessary to the right of volatile in the declaration of y? What possible evil could someone accomplish if the declaration for x were allowed?
In section 4.4.4 of the standard it says:
A conversion can add cv-qualifiers at levels other than the first in multi-level pointers, subject to the following rules:
Two pointer types T1 & T2 are similar if there exists a type T and integer n > 0 such that:
T1 is CV10 ptr to CV11 ptr to ... CV1N T
T2 is CV20 ptr to CV21 ptr to ... CV2N T
... where each CVij is const, volatile, const volatile, or nothing. The n-tuple of cv-qualifiers after the first in a pointer type, e.g., CV11, CV12, ..., CV1N in the pointer type T1, is called the cv-qualification signature of the pointer type. An expression of type T1 can be converted to type T2 iff the following conditions are satisfied:
the pointer types are similar
for every j > 0, if const is in CV1j, then const is in CV2j, and similarly for volatile.
if the CV1j and CV2j are different, then const is in every CV2k for 0 < k < j
... after which it goes on to give an example for assigning a ** to a const**. The emphasis above is mine, italics are from the document.
Putting this into code:
int CV13* CV12* CV11* CV10 b1;
int CV23* CV22* CV21* CV20 b2 = b1;
I'm a little fuzzy on some of the details ... so here's some questions or potentially flawed observations:
1) It says at levels other than the first; this isn't elaborated on any further, but CV20 can be any valid CV qualifier.
2) The 3rd rule at the bottom says if T2 adds either const OR volatile at level j, then levels 1 ... j-1 must be const (or suffer the wrath). In the following, the # of stars differs from the one at the top to emphasize what the 3rd rule says:
int *****w;
int **volatile* * *x = w; // error
int **volatile*const*const*y = w; // OK
int **const *const*const*z = w; // OK
I understand why it's needed for z, but why with y? Here's roughly what the example in 4.4.4 looks like, modified for the volatile case:
void f( int **x ) {
int volatile**y = x; // not allowed
// do some evil here
}
What evil could be put there?
(Note: "This question specifically relates to C++98" but the state of affairs is the same in all versions of the Standard, past and present (and future too I would bet), because it's essentially about const-correctness and preventing coders from opening a hole in the type system.)
As the Standard uses the general term "cv-qualifiers", I find it easier to understand when reasoning only with "const" (no "volatile") [but see further below for an example with volatile]. The "C++ FAQ Lite" has a related entry : Why am I getting an error converting a Foo** → Foo const**?
Essentially, allowing the conversion would let you silently modify a const T (through a pointer to non-const T):
int const theAnswer = 42;
int* p = 0; // int* p = &theAnswer; is not allowed of course...
int** pp = &p;
int const** ppc = pp; // <-- Error, but imagine this were allowed...
*ppc = &theAnswer; // &theAnswer is `int const*` and *ppc is `int const*` too,
// but it's also doing *pp = &theAnswer; i.e. p = &theAnswer;
*p = 999; // I.e. theAnswer = 999; => modifying a const int!
But by adding a "first-level" const, the conversion int const* const* pcpc = pp; is valid because the compiler will prevent you doing *pcpc = &theAnswer; afterwards (because *pcpc is const).
Edit: As for volatile, the problem is maybe less obvious than with const, but allowing the conversion would let you silently incorrectly access (read or write) a volatile T as if it were not volatile (through a pointer to non-volatile T):
extern int volatile externTimer;
int* p = 0; // int* p = &externTimer; is not allowed...
int** pp = &p;
int volatile** ppv = pp; // <-- Error, but imagine this were allowed...
*ppv = &externTimer; // &externTimer is `int volatile*` and *ppv too,
// but it's also doing *pp = &externTimer; i.e. p = &externTimer;
int a1 = externTimer; // First read
int a2 = externTimer; // Second read, mandatory: the value may have changed externally
int b1 = *p; // First read
int b2 = *p; // Second read? may be optimized out! because *p is not volatile
But by adding a "first-level" const, the conversion int volatile* const* pcpv = pp; is valid because the compiler will prevent you doing *pcpv = &externTimer; afterwards (because *pcpv is const).
//v is a random number 0 or 1
const char *str;
//str = 48 + v; //how to set??
I tried memcpy and sprintf and get issues with it being "const char*"
I want to set "str" to 0 or 1 as defined by "v". But it must be of type " const char* "
My guess is you want to change the value of the const char after you first declare it, correct? While you cannot change the value of the const char* directly, you may be able to change the pointer value to a normal variable.
For example look at this page here: Constants in C and C++
This is what you can and cannot do using your pointers to change const values: (Adopted from link above):
const int x; // constant int
x = 2; // illegal - can't modify x
const int* pX; // changeable pointer to constant int
*pX = 3; // illegal - can't use pX to modify an int
pX = &someOtherIntVar; // legal - pX can point somewhere else
int* const pY; // constant pointer to changeable int
*pY = 4; // legal - can use pY to modify an int
pY = &someOtherIntVar; // illegal - can't make pY point anywhere else
const int* const pZ; // const pointer to const int
*pZ = 5; // illegal - can't use pZ to modify an int
pZ = &someOtherIntVar; // illegal - can't make pZ point anywhere else
This also works for chars like you're trying to do.
Here's the deal with const char *. It is a pointer to const char. const char means that the characters cannot change. The pointer is not const, so it can change.
When you do this:
str = 48 + v;
You are attempting to change a pointer to either 48 or 49, depending on what v is. This is nonsensical. If it compiled, it would point to random memory. What you want is to change what `str' points to to 0 or 1.
Since it can only point to constant characters, it can only point to something defined as a value, in quotes. So, for example, it can be set to point to "0", which is a constant character or "1", which is a constant character. So you can do something like this:
str = "0"; // point to a constant character string "0"
if( v )
str = "1"; // point to a constant character string "1"
Note that since str points to constant characters, you cannot modify what it points to:
*str = '1'; // Won't work because you are trying to modify "0" directly.
From my understanding, const modifiers should be read from right to left. From that, I get that:
const char*
is a pointer whose char elements can't be modified, but the pointer itself can, and
char const*
is a constant pointer to mutable chars.
But I get the following errors for the following code:
const char* x = new char[20];
x = new char[30]; //this works, as expected
x[0] = 'a'; //gives an error as expected
char const* y = new char[20];
y = new char[20]; //this works, although the pointer should be const (right?)
y[0] = 'a'; //this doesn't although I expect it to work
So... which one is it? Is my understanding or my compiler(VS 2005) wrong?
Actually, according to the standard, const modifies the element directly to its left. The use of const at the beginning of a declaration is just a convenient mental shortcut. So the following two statements are equivalent:
char const * pointerToConstantContent1;
const char * pointerToConstantContent2;
In order to ensure the pointer itself is not modified, const should be placed after the asterisk:
char * const constantPointerToMutableContent;
To protect both the pointer and the content to which it points, use two consts.
char const * const constantPointerToConstantContent;
I've personally adopted always putting the const after the portion I intend not to modify such that I maintain consistency even when the pointer is the part I wish to keep constant.
It works because both are same. May be you confused in this,
const char* // both are same
char const*
and
char* const // unmutable pointer to "char"
and
const char* const // unmutable pointer to "const char"
[To remember this, here is a simple rule, '*' affects its whole LHS first]
That is because the rule is:
RULE: const binds left, unless there is nothing on the left, then it binds right :)
so, look at these as:
(const --->> char)*
(char <<--- const)*
both same! oh, and --->> and <<--- are NOT operators, they just show what the const binds to.
(from 2 simple variable initialization question)
A really good rule of thumb regarding const:
Read Declarations Right-to-Left.
(see Vandevoorde/Josutiss "C++ Templates: The Complete Guide")
E.g.:
int const x; // x is a constant int
const int x; // x is an int which is const
// easy. the rule becomes really useful in the following:
int const * const p; // p is const-pointer to const-int
int const &p; // p is a reference to const-int
int * const * p; // p is a pointer to const-pointer to int.
Ever since I follow this rule-of-thumb, I never misinterpreted such declarations again.
(: sisab retcarahc-rep a no ton ,sisab nekot-rep a no tfel-ot-thgir naem I hguohT :tidE
Here is how I always try to interpret:
char *p
|_____ start from the asterisk. The above declaration is read as: "content of `p` is a `char`".
char * const p
|_____ again start from the asterisk. "content of constant (since we have the `const`
modifier in the front) `p` is a `char`".
char const *p
|_____ again start from the asterisk. "content of `p` is a constant `char`".
Hope it helps!
In both of your cases you're pointing to a constant char.
const char * x //(1) a variable pointer to a constant char
char const * x //(2) a variable pointer to a constant char
char * const x //(3) a constant pointer to a variable char
char const * const x //(4) a constant pointer to a constant char
char const * const * x //(5) a variable pointer to a constant pointer to a constant char
char const * const * const x //(6) can you guess this one?
By default, const applies to what is inmediately at is left, but it could apply to what is inmediately at its right if there's nothing preceeding it, as in (1).