I want to pass strings to a function but save the cost of
copying the pointer on the function's stack to improve performance.
I am aware of the multithreading hazards of manipulating const-ness.
One thing is to use &arr[idx] (char array) as a pointer to pass to
void func( const char*& charArrItemRef).
Compiler complains it can't bind the reference to function arg.
how can I manipulate the build to allow it?
I tried to first forcefully cast a char* to const char*, store it in a variable and then pass that variable to your func. Note that it has to be stored in a variable since you are passing the pointer as a reference. Hope this is what you were looking for:
#include <iostream>
using namespace std;
void func(const char* &charArrItemRef)
{
cout << charArrItemRef << endl;
}
int main()
{
char* a[5] = {(char*)"abc", (char*)"def", (char*)"sss", (char*)"dasds", (char*)"aad"};
const char* c = reinterpret_cast<const char*>(a[0]);
func(c);
// EDIT:
char b[10] = "abcdefghi";
const char* d = &b[3];
func(d);
return 0;
}
Related
I have what is hopefully a trivial question that someone can explain to me in simpler terms than what I have already come across. While working through
A Tour of C++ (Second Edition)
I've been trying a few examples.
I'm currently trying to modify a pointer to a string literal in a separate function (I thought it would be easy.....).
using namespace std;
void test(char *ptr)
{
ptr = "test";
}
int main()
{
char *p = "abc";
test(p);
cout << p << "\n";
return 0;
}
When using g++ to compile, I get a
Warning: ISO C++ forbids converting a string constant to char*
Apparently g++ is auto-converting *p to a const? Surely I'm missing something basic, but my previous SO and google searches have gotten me no closer to the answer. Thank you for your responses!
EDIT:
Both great examples below. Thank you everyone for your responses, very helpful!
Apparently g++ is auto-converting *p to a const?
Quite the opposite. The string "abc" will be in your binary, and that is supposed to be readonly for your program. Therefore, that string should only be read, and the value you get when assigning the string literal in this situation is of type const char*. You get the error because you're assigning it to a non-const char*. Try this instead:
const char *p = "abc";
Also, you'll have to change the function, too:
void test(const char *ptr)
{
ptr = "test";
}
It's still going to print abc, however. That's because you're only modifying a copy of the value that you're passing. But C++ lets you pass a reference instead, which you can do like this:
void test(const char *&ptr)
{
ptr = "test";
}
Now that's a reference to a pointer pointing to a const char... whew! Both the "abc" and "test" will be in the program's binary when it is compiled. When the program is run, the address of "abc" is assigned to char *p, and then the function to change it to have the address of "test" instead is called. The & tells it to work with the actual char *p and not just a copy of it that gets lost when the function finishes.
There are two things that can be const; the pointer (char * const), or the object (const char *).
The string literal is const, that's what the compiler is complaining about. You should use
const char *p = "abc";
The function would still not modify the pointer p from main() though, because it is passed by value to the function.
This should modify the pointer:
using namespace std;
const char * str2 = "test";
void test(const char *& ptr)
{
ptr = str2;
}
int main()
{
const char *p = "abc";
test(p);
cout << p << "\n";
return 0;
}
live demo
I saw someone using this in one answer:
void methodA(const int*& var);
I couldn't understand what the argument means.
AFAIK:
const int var => const int value which can't be changed
const int* var => pointer to const int, ie *var can't be changed but var can be changed
const int& var => reference to const int, ie value of var can't be changed
What does const int*& var mean? Is const int& *var also possible?
Can you please give some example as well, like what can and can't be done with it?
UPDATE:
I am not sure if I am thinking the right way, but I began to think of a reference as an alias of the variable that was passed as argument, so:
const int * p;
methodA(p) => here we are passing p as const int * but we don't know if this is pass by value or what, until we see the definition of methodA, so if methodA is like this:
methodA(const int * & p2) ==> here p2 is another name to p, ie p and p2 are the same from now on
methodA(const int* p2) ==> here p2 is passed as value, ie p2 is just local to this method
Please correct me if I am thinking the wrong way. If yes, I might need to study some more about this. Can you please point to some nice references?
UPDATE 2:
If some beginner like me wants to know more about this thing, you can use the c++decl / cdecl program from here, which I just discovered to be very useful.
$ c++decl
Type `help' or `?' for help
c++decl> explain const int&* p
declare p as pointer to reference to const int
c++decl> explain const int*& p
declare p as reference to pointer to const int
But, as every one here pointed out, the first example isn't legal in C++.
It is a reference to a pointer to an int that is const.
There is another post somewhat related, actually, here. My answer gives a sorta of general algorithm to figuring these things out.
This: const int& *var has no meaning, because you cannot have a pointer to reference.
If the const's and pointers are getting in the way, remember you can typedef these things:
typedef int* IntPointer;
typedef const IntPointer ConstIntPointer;
void foo(ConstIntPointer&); // pass by reference
void bar(const ConstIntPointer&); // pass by const reference
void baz(ConstIntPointer); // pass by value
Might make it easier to read.
If you need more help on C++, read this. More specifically, references.
References as variables do not take space:
int i; // takes sizeof(int)
int*pi = &i; // takes sizeof(int*)
int& ri = i; // takes no space.
// any operations done to ri
// are simply done to i
References as parameters use pointers to achieve the end effect:
void foo(int& i)
{
i = 12;
}
void foo_transformed(int *i)
{
*i = 12;
}
int main()
{
int i;
foo(i); // same as:
foo_transformed(&i); // to the compiler (only sort of)
}
So it's actually passing the address of i on the stack, so takes sizeof(int*) space on the stack. But don't start thinking about references as pointers. They are not the same.
Some folks find it easier reading this from right to left. So
const int*&
is a reference to a pointer to an integer that is const.
As you know, references cannot be changed, only what they refer to can be changed. So the reference will refer to just one pointer to an integer that is const. Since the pointer is not const - the integer is const - you can change the pointer to point to a different integer.
Compare this to
int* const &
This is a reference to a constant pointer to an integer. Again the reference is immutable, and in this case it is a reference to a constant pointer. What you can change in this case is the integer value since there was no const either side of the int keyword.
Just to add confusion, const int and int const are the same. However int const * and int * const are very different. The first is a pointer to a constant integer, so the pointer is mutable. The second is a constant pointer to an integer, so the integer is mutable.
Hope this helps!
In your example, var is a refernce to a pointer to const char.
Since it's a reference, a change to the parameter inside methodA() will be reflected in the argument that is passed to methodA():
void methodA( const char*& var)
{
static const char newdata[] = {'a', 'b', 'c', '\0'};
printf( "var points to %s\n", var);
var = newdata;
}
int main()
{
const char * p = "123";
printf( "p points to: %s\n", p); // prints "p points to: 123"
methodA( p);
printf( "now p points to: %s\n", p); // prints "now p points to: abc"
}
It is a reference to a const pointer, i.e. a pointer where you cannot modify the data pointed to. As the reference is used as an argument to a method the method is able to modify the pointer to let it point to something else (still something that cannot be modified).
With regards to your update:
so if methodA is like this methodA(const int * & p2) ==> here p2 is another name to p, i.e. p and p2 are same from now on and if methodA(const int* p2) ==> here p2 is passed as value i.e p2 is just local to this method
Yes, you are correct.
Here's another example, a getter that returns the address of a private data item. The item happens to be an int for simplicity. A large array of items would be a more practical case (a zero-copy getter).
#include <iostream>
using namespace std;
class X {
public:
void getter(const int *&data) const
{
data = &val;
}
private:
int val = 5;
};
main()
{
X obj;
const int *data;
obj.getter(data);
cout << data << endl;
cout << *data << endl;
}
I am trying to pass a char & value to a char * argument in a function, but it's not working as shown below:
#include <iostream>
using namespace std;
void change_sugar(const short& sugars, char* LOC);
int main()
{
static int caga = 0;
const short* mysweets;
char& lala;
change_sugar(mysweets, lala);
}
void change_sugar(const short& sugars, char** LOC[])
{
if (sugars == 3000)
LOC[1] = 5;
cout << "Sugar is not nCaga, nor caga" << " ___ !#S ";
cerr << "nCaga failed!";
}
Error output:
error: 'lala' declared as reference but not initialized
I am trying to pass a reference to a pointer of the same type. Is this correct?
Bear with me, I am new to C++, and I think I read the tutorial on pointers and references correctly.
EXTRA: I tried this with a different compiler, Turbo 16, I think, and it threw like ten other errors, so I don't know if it's a compiler problem or not.
In C++ a reference must always be valid (and not "dangling"), so you have to initalize it when creating it.
I am not sure what you wanted to do with your lala, but a proper usage of a reference variable is like so:
char a;
char & b = a; // has to be initialized here
Now you can use b wherever a variable of type char is meant to be used. However, your function wants char * as its second parameter.
Thus, after initializing the reference, you could still use its address to make it fit: &lala.
Also your definition and declaration is mismatched.
There are lots of things wrong with your code.
A reference and a pointer are not the same thing in the C++ language, although they are implemented the same way in the compiled machine code. You cannot pass a reference where a pointer is expected, and vice versa. You are trying to pass a short* where a short& is expected, and a char& where a char* is expected.
A reference can never be uninitialized (hense the compiler error), but a pointer can be uninitialized.
The parameters in your change_sugar() declaration do not match the parameters in the definition. In C++, they must match.
It is very unclear what change_sugar() is actually trying to do. Clearly, you want to alter the char that is passed in, but char is only 1 byte in size and you are trying to alter memory past the 1-byte boundary of the data being altered.
Try this instead:
#include <iostream>
using namespace std;
void change_sugar(const short& sugars, char* LOC);
int main()
{
short mysweets = 3000;
char lala = 0;
change_sugar(mysweets, &lala);
}
void change_sugar(const short& sugars, char* LOC)
{
if ((LOC) && (sugars == 3000))
*LOC = 5;
cout << "Sugar is not nCaga, nor caga" << " ___ !#S ";
cerr << "nCaga failed!";
}
Or this:
#include <iostream>
using namespace std;
void change_sugar(const short& sugars, char& LOC);
int main()
{
short mysweets = 3000;
char lala = 0;
change_sugar(mysweets, lala);
}
void change_sugar(const short& sugars, char& LOC)
{
if (sugars == 3000)
LOC = 5;
cout << "Sugar is not nCaga, nor caga" << " ___ !#S ";
cerr << "nCaga failed!";
}
There's a very simple paradigm for passing variables to methods wanting pointers:
void clear(char *p) { *p = '\0'; }
char c = 'a';
clear(&c); // after this call c == '\0'
Are you actually looking for something more advanced here?
Reference variables:
char &r = c;
Are actually pretty complicated. (And would still be passed with &r)
There are a lot of things that bothers me with the code so I'll go through some them.
1: Your prototype does not match.
Change
void change_sugar(const short& sugars, char** LOC[])
to
void change_sugar(const short& sugars, char* LOC)
or the other way around depending on what you actually want to do.
2. Your pointer is not initialized.
const short* mysweets is not initialized. Allocate some memory for it.
const short* mysweets = malloc(sizeof(short));
then
*mysweets = 3000;
3. lala is not a pointer.
If you want to pass the address of lala to your function, change_sugar, initialize it as so
char* lala = malloc(sizeof(char));
and pass it as
change_sugar(mysweets, lala);
If you don't want it to be a pointer but still want to pass by reference, declare it as so
char lala;
and pass it as
change_sugar(mysweets, &lala);
Finally:
Your code is very confusing to read and to figure out what you actually want to do. I suggest to step back and think about what you want to achieve and redesign your code.
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
void f(char **x)
{
(*x)++;
**x = 'a';
}
int main()
{
char str[]="hello";
f(&str);
cout << str << endl;
return 0;
}
Please tell me why this program is giving compilation Error.I am using the g++ compiler
Error :temp1.cpp:16:8: error: cannot convert ‘char (*)[6]’ to ‘char**’ for
argument ‘1’ to ‘void f(char**)’
Arrays can be implicitly converted to pointers, but that doesn't mean that the implicit "pointer equivalent" already exists.
You are hoping that f(&str); will implicitly create both a pointer to str and a pointer to that pointer.
This small (working) change illustrates this point:
int main()
{
char str[]="hello";
char *pstr = str; // Now the pointer extists...
f(&pstr); // ...and can have an address
cout << str << endl;
return 0;
}
You are passing pointer of constant char to the function but in function you are taking it as pointer of pointers. That is the problem. I commented out below where the problem lies.
[Off topic but N. B. : Arrays and pointers are different concept.]
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
void f(char **x) //**x is pointer of pointer
{
(*x)++;
**x = 'a';
}
int main()
{
char str[]="hello";
f(&str); //You are passing pointer of constant char.
cout << str << endl;
return 0;
}
You're going to run into a serious problem with your function f since &str and &str[0] both evaluate to the same value ... as other posters have pointed out, these operations point to different types, but the actual pointer r-value will be the same. Thus in f when you attempt to double-dereference the char** pointer x, you're going to get a segfault even if you attempted something like a cast to massage the type differences and allow compilation to happen with errors. This is because you are never getting a pointer-to-pointer ... the fact that &str and &str[0] evaluate to the same pointer value means that a double-dereference acually attempts to use the char value in str[0] as a pointer value, which won't work.
Your problem is that you're treating arrays as pointers, when they're not. Arrays decay into pointers, and in this case, it doesn't. What you're passing in is a char (*)[6] when it expects a char **. Those are obviously not the same.
Change your parameter to char (*x)[6] (or use a template with a size parameter):
template <std::size_t N>
void f(char (*x)[N])
Once inside, you try to increment what x is pointing to. You can't increment an array, so use an actual pointer instead:
char *p = *x;
p++;
*p = 'a';
All put together, (sample)
template <std::size_t N>
void f(char(*x)[N])
{
if (N < 2) //so we don't run out of bounds
return;
char *p = *x;
p++;
*p = 'a';
}
I am reading a post on Stack Overflow and I saw this function:
advance_buf( const char*& buf, const char* removed_chars, int size );
What does char*& buf mean here and why do people use it?
It means buf is a reference to a pointer, so its value can be changed (as well as the value of the area it's pointing to).
I'm rather stale in C, but AFAIK there are no references in C and this code is C++ (note the question was originally tagged c).
For example:
void advance(char*& p, int i)
{
p += i; // change p
*p = toupper(*p); // change *p
}
int main() {
char arr[] = "hello world";
char* p = arr; // p -> "hello world";
advance(p, 6);
// p is now "World"
}
Edit: In the comments #brett asked if you can assign NULL to buff and if so where is the advantage of using a reference over a pointer. I'm putting the answer here for better visibility
You can assign NULL to buff. It isn't an error. What everyone is saying is that if you used char **pBuff then pBuff could be NULL (of type char**) or *pBuff could be NULL (of type char*). When using char*& rBuff then rBuff can still be NULL (of type char*), but there is no entity with type char** which can be NULL.
buf's a (C++) reference to a pointer. You could have a const char *foo in the function calling advance_buf and now advance_buf can change the foo pointer, changes which will also be seen in the calling function.