Modifying pointer to string literal in separate function - c++

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

Related

Pass non const char * in to const char *& argument of a function

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;
}

Passing reference to char pointer is resulting in an error

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.

Compilation error while passing double pointer in cpp

#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';
}

deprecated conversion from string constant to 'char*' [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
C++ deprecated conversion from string constant to 'char*'
I want to pass a string via char* to a function.
char *Type = new char[10];
Type = "Access"; // ERROR
However I get this error:
error: deprecated conversion from string constant to 'char*'
How can I fix that?
If you really want to modify Type:
char *Type = new char[10];
strcpy( Type, "Access" );
If you don't want to modify access:
const char *Type = "Access";
Please note, that, however, arrays of char in C and in C++ come with a lot of problems. For example, you don't really know if the call to new has been successful, or whether it is going to throw an exception. Also, strcpy() could surpass the limit of 10 chars.
So you can consider, if you want to modify type later:
std::string Type = "Access";
And if you don't want to modify it:
const std::string Type = "Access";
... the benefit of using std::string is that it is able to cope with all these issues.
There are a couple of things going on here.
char *Type = new char[10];
This create a char* pointer named Type and initializes it to point to the first element of a newly allocated 10-element array.
Type = "Access"; // ERROR
This assignment doesn't do what you think it does. It doesn't copy the 6-character string "Access" (7 characters including the terminating '\0') to the array you just created. Instead, it assigns a pointer to the first element of that array into your pointer Type. There are two problems with that.
First, it clobbers the previous value of Type. That 10-character array you just allocated now has nothing pointing to it; you can no longer access it or even deallocate it. This is a memory leak.
This isn't what the compiler is complaining about.
Second, a string literal creates a statically allocated const array ("statically allocated" meaning it exists for the entire execution of your program). Type is not declared with a const qualifier. If the compiler allowed you to point Type to the string "Access", you could use that pointer to (attempt to) modify it:
Type = "Access";
Type[0] = 'a'; // try to change the string to "access"
The purpose of const is to prevent you from modifying, or even attempting to modify, things that are read-only. That's why you're not allowed to assign a non-const pointer value to a const pointer object.
Since you're programming in C++, you're probably better off using std::string.
I want to pass a string via char* to a function.
Here is how you can pass a string via char* to a function (note the required const keyword in the function signature.)
#include <iostream>
void f(const char* p) {
std::cout << p << "\n";
}
int main() {
f("Access");
}
But, what if you are invoking an existing function, and cannot modify its signature?
If you have some external guarantee that the function will not write through its argument pointer,
#include <iostream>
void f(char* p) {
std::cout << p << "\n";
}
int main() {
f(const_cast<char*>("Access"));
}
If, on the other hand, the function might write to the string, then you'll need to allocate space for the string:
#include <iostream>
void f(char* p) {
*++p;
std::cout << p << "\n";
}
int main() {
// Allocate read-write space on the heap
char *p = new char[strlen("Access"+1)];
// Copy string to allocated space
strcpy(p, "Access");
f(p);
delete p;
}
or,
#include <iostream>
void f(char* p) {
*++p;
std::cout << p << "\n";
}
int main() {
// Allocate read-write space on the stack
char arr[] = "Access";
f(arr);
}
But, the best course by far is to avoid the whole pointer mishegas:
#include <iostream>
void f(const std::string& p) {
std::cout << p << "\n";
}
int main() {
f("Access");
}
You've got a basic operations problem here, not a coding issue.
When you want to change the contents of a C char array, you do not use the assignment operator. That will instead change the value of the underlying pointer. Ick.
Instead you are supposed to use the C string library routines. For instance, strcpy (Type, "Access"); will copy the string literal "Access" into your character array, with its all-important trailing nul character.
If you are using C++ (as your tags indicate), you should probably be using std::string instead of arrays of char. Assignment works they way you are expecting there.

Why do people use some thing like char*&buf?

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.