How to make sure function call proper with pointer - c++

Below code will work when I call like this:
char arr[] = "foobar";
reverse(arr);
but it won't work when I call like this as it is pointing to read only portion
char*a = "foobar";
reverse(a);
Now my question is that is there any way I can avoid user to call like this?
void reverse(char *str)
{
char * end = str;
char tmp;
if (str)
{
while (*end)
{
++end;
}
--end;
while (str < end)
{
tmp = *str;
*str++ = *end;
*end-- = tmp;
}
}
}

char arr[] = "foobar";
is array of chars, containing these chars: f, o, o, b, a, r, \0. While
char* a = "foobar";
is wrong. "foobar" here is a string literal, and this statement must be
const char* a = "foobar"; // note the const
You cannot change string literals.
That is a common mistake - make difference between a pointer and an array.
And no, there's no way to prevent the user to call reverse with a string literal. The "user" is responsible for their actions.
If a is defined as it must be (using const), the compiler will tell "the user" something like invalid conversion from ‘const char*’ to ‘char*’

No, there is no way to guarantee that pointer being passed to function is valid. It is impressibility of caller to provide valid data. You can even do something like this
int i = 0xABCD;
reverse((char*) i);
Which doesn't make much sense but there is no way to check for such things in reverse.

Use a std::string. Foregoing any corruption, a std::string is a continuous block of memory with a known size.
You can even use std::reverse.
Besides with the correct settings, compilers will prevent you from assigning a string literal to a char* variable.

Related

How can I convert const char* to string and then back to char*?

I'm just starting c++ and am having difficulty understanding const char*. I'm trying to convert the input in the method to string, and then change the strings to add hyphens where I want and ultimately take that string and convert it back to char* to return. So far when I try this it gives me a bus error 10.
char* getHyphen(const char* input){
string vowels [12] = {"A","E","I","O","U","Y","a","e","i","o","u","y"};
//convert char* to string
string a;
int i = 0;
while(input != '\0'){
a += input[i];
input++;
i++;
}
//convert a string to char*
return NULL;
}
A: The std::string class has a constructor that takes a char const*, so you simply create an instance to do your conversion.
B: Instances of std::string have a c_str() member function that returns a char const* that you can use to convert back to char const*.
auto my_cstr = "Hello"; // A
std::string s(my_cstr); // A
// ... modify 's' ...
auto back_to_cstr = s.c_str(); // B
First of all, you don't need all of that code to construct a std::string from the input. You can just use:
string a(input);
As far as returning a new char*, you can use:
return strdup(a.c_str()); // strdup is a non-standard function but it
// can be easily implemented if necessary.
Make sure to deallocate the returned value.
It will be better to just return a std::string so the users of your function don't have to worry about memory allocation/deallocation.
std::string getHyphen(const char* input){
Don't use char*. Use std::string, like all other here are telling you. This will eliminate all such problems.
However, for the sake of completeness and because you want to understand the background, let's analyse what is going on.
while(input != '\0'){
You probably mean:
while(*input != '\0') {
Your code compares the input pointer itself to \0, i.e. it checks for a null-pointer, which is due to the unfortunate automatic conversion from a \0 char. If you tried to compare with, say, 'x' or 'a', then you would get a compilation error instead of runtime crashes.
You want to dereference the pointer via *input to get to the char pointed to.
a += input[i];
input++;
i++;
This will also not work. You increment the input pointer, yet with [i] you advance even further. For example, if input has been incremented three times, then input[3] will be the 7th character of the original array passed into the function, not the 4th one. This eventually results in undefined behaviour when you leave the bounds of the array. Undefined behaviour can also be the "bus error 10" you mention.
Replace with:
a += *input;
input++;
i++;
(Actually, now that i is not used any longer, you can remove it altogether.)
And let me repeat it once again: Do not use char*. Use std::string.
Change your function declaration from
char* getHyphen(const char* input)
to
auto hyphenated( string const& input )
-> string
and avoid all the problems of conversion to char const* and back.
That said, you can construct a std::string from a char_const* as follows:
string( "Blah" )
and you get back a temporary char const* by using the c_str method.
Do note that the result of c_str is only valid as long as the original string instance exists and is not modified. For example, applying c_str to a local string and returning that result, yields Undefined Behavior and is not a good idea. If you absolutely must return a char* or char const*, allocate an array with new and copy the string data over with strcpy, like this: return strcpy( new char[s.length()+1], s.c_str() ), where the +1 is to accomodate a terminating zero-byte.

Character pointer access

I wanted to access character pointer ith element. Below is the sample code
string a_value = "abcd";
char *char_p=const_cast<char *>(a_value.c_str());
if(char_p[2] == 'b') //Is this safe to use across all platform?
{
//do soemthing
}
Thanks in advance
Array accessors [] are allowed for pointer types, and result in defined and predictable behaviors if the offset inside [] refers to valid memory.
const char* ptr = str.c_str();
if (ptr[2] == '2') {
...
}
Is correct on all platforms if the length of str is 3 characters or more.
In general, if you are not mutating the char* you are looking at, it best to avoid a const_cast and work with a const char*. Also note that std::string provides operator[] which means that you do not need to call .c_str() on str to be able to index into it and look at a char. This will similarly be correct on all platforms if the length of str is 3 characters or more. If you do not know the length of the string in advance, use std::string::at(size_t pos), which performs bound checking and throws an out_of_range exception if the check fails.
You can access the ith element in a std::string using its operator[]() like this:
std::string a_value = "abcd";
if (a_value[2] == 'b')
{
// do stuff
}
If you use a C++11 conformant std::string implementation you can also use:
std::string a_value = "abcd";
char const * p = &a_value[0];
// or char const * p = a_value.data();
// or char const * p = a_value.c_str();
// or char * p = &a_value[0];
21.4.1/5
The char-like objects in a basic_string object shall be stored contiguously.
21.4.7.1/1: c_str() / data()
Returns: A pointer p such that p + i == &operator[](i) for each i in [0,size()].
The question is essentially about querying characters in a string safely.
const char* a = a_value.c_str();
is safe unless some other operation modifies the string after it. If you can guarantee that no other code performs a modification prior to using a, then you have safely retrieved a pointer to a null-terminated string of characters.
char* a = const_cast<char *>(a_value.c_str());
is never safe. You have yielded a pointer to memory that is writeable. However, that memory was never designed to be written to. There is no guarantee that writing to that memory will actually modify the string (and actually no guarantee that it won't cause a core dump). It's undefined behaviour - absolutely unsafe.
reference here: http://en.cppreference.com/w/cpp/string/basic_string/c_str
addressing a[2] is safe provided you can prove that all possible code paths ensure that a represents a pointer to memory longer than 2 chars.
If you want safety, use either:
auto ch = a_string.at(2); // will throw an exception if a_string is too short.
or
if (a_string.length() > 2) {
auto ch = a_string[2];
}
else {
// do something else
}
Everyone explained very well for most how it's safe, but i'd like to extend a bit if that's ok.
Since you're in C++, and you're using a string, you can simply do the following to access a caracter (and you won't have any trouble, and you still won't have to deal with cstrings in cpp :
std::string a_value = "abcd";
std::cout << a_value.at(2);
Which is in my opinion a better option rather than going out of the way.
string::at will return a char & or a const char& depending on your string object. (In this case, a const char &)
In this case you can treat char* as an array of chars (C-string). Parenthesis is allowed.

Building / Merging character array pointers in C++

I'm very new to C++ (coming from C#) and it's giving me puzzles :S
I have a very basic question about arrays and it's pointers.
So if I have the following code:
char * test1 = "com";
char * test2 = "ment";
I found similar code in some files already. I don't exactly understand how a string can fit in one character.. but ok...
However, how could I connect these arrays so that I get "comment" ?
I'm pretty sure this char * result = test1 + test2; would only increase the pointer which would then point to something in the memory, which I dont intend to use.
So is it possible to get an array like char array[] = {'c', 'o', 'm', 'm', 'e', 'n', 't'}; back from this?
or can I at least get a pointer which points to something like comment\NUL in the memory?
As you pointed out, pointer arithmetic can't solve this.
If you want to have a C-string as the result, allocating space for the whole new string is required, then copying over the characters, typically using strcat / strncat, but they are C-style string operations.
// Your C-strings
const char *test1 = "com";
const char *test2 = "ment";
// Dynamic allocation of memory for result string
char *result = new char[strlen(test1) + strlen(test2) + 1];
// Start with the empty string
*result = '\0';
// Concatenate both input strings (use strncat if you don't know
// for sure that they will fit into the result array!)
strcat(result, test1);
strcat(result, test2);
// (use result pointer)
// Free the memory after last usage
delete[] result;
In C++, you typically try to avoid them and use std::string instead. Even if you want a C-string as the result, you can use a temporary std::string for allocation and management of the required memory as well as for performing the concatenation:
// Your C-strings
const char *test1 = "com";
const char *test2 = "ment";
// Wrap in temporary C++ strings and concatenate:
std::string result = std::string(test1) + std::string(test2);
// Get the pointer (only valid as long as result is in scope!)
const char *ptr = result.c_str();
Furthermore, please note that you should not assign a string literal to a non-const char * pointer, use a const char* pointer instead. And try to avoid dealing with raw C-strings as long as possible; of course when you use C libraries you have to use them a lot.
Note also that above mentioned methods are performed at runtime; you can't get a compile-time solution for concatenating two string literals, even though the compiler could know what you want to have. I don't know your context, but maybe you only want to have a multi-line string literal, then simply drop the + and write "com" "ment".
A c style solution can be found in the following link:
http://www.cplusplus.com/forum/beginner/5681/:
int len = strlen(test1)+strlen(test2);
char* result = new char[len +1]; // +1 for null terminated string
snprintf(result,len +1, "%s%s",test1,test2);
result[len] = NULL;
// use result
delete(result);
You can utilize std::string:
#include <iostream>
int main() {
// Note: the character literals are const (non const is deprecated)!
const char * test1 = "com";
const char * test2 = "ment";
// This gives a compiler error (there is no way to add pointers)
// const char * concat = test1 + test2;
// A std::string has an overload for the operator +:
std::string comment = std::string(test1) + test2;
// The dynamically allocated string.
// Note: as soon as the comment string gets altered or destroyed the
// pointer s to the internal string data (may) become invalid.
const char* s = comment.c_str();
std::cout << s << '\n';
}

Store c_str() as char *

I'm trying to use the function with the following declaration:
extern int stem(struct stemmer * z, char * b, int k)1
I'm trying to pass a C++ string to it, so I thought I'd use the c_str() function. It returns const char *. When I try to pass it to the stem() function, I get this error: error: invalid conversion from 'const char*' to 'char*' [-fpermissive].
How can I store the result of c_str() such that I can use it with the stem function?
Here is the code I'm running:
struct stemmer * z = create_stemmer();
char * b = s.c_str();
int res = stem(z, b, s.length()); //this doesn't work
free_stemmer(z);
return s.substr(0,res);
The problem you are having is that c_str() returns a buffer that can not be modified (const), while stem() may modify the buffer you pass in (not const). You should make a copy of the result of c_str() to get a modifiable buffer.
The page http://www.cplusplus.com/reference/string/string/c_str/ has more information on the C++ 98 and 11 versions. They suggest replacing char * b = s.c_str(); with the following:
char * b = new char [s.length()+1];
std::strcpy (b, s.c_str());
You shouldn't try to remove constness of a string returned by c_str():
char * b = s.c_str();
but you can pass an address of std::string's internal buffer directly:
int res = stem(z, static_cast<char*>(&s[0]), s.length());
If stem() is going to modify the string, then make a copy of it:
char * scpy= strdup( s.c_str()) ;
int res = stem(z, scpy, strlen( scpy));
free( scpy) ;
Use const_cast:
int res = stem(z, const_cast<char*>(s.c_str()), s.length()+1);
free_stemmer(z);
return s.substr(0,res);
Note the length+1 expression which might (or might not) be needed. C-style strings (char*) have an additional null terminator (zero byte, equivalent "\0") at the end. Your stem function may (or may not) expect a null terminator at the end of the string - try both variants.
Note also that "stem" function should not try to modify the string, otherwise bad things may happen (warning based on #David Heffernan's comment)
.c_str()
Just returns a pointer to the data, I would update the stem function to accept a 'const char*' unless you are wanting to modify the data in the string, in that case you should pass it as a new string object.
If you can't edit the stem function you can cast it:
int res = stem(z, const_cast<char*>(s.c_str()), s.length());
It's not good to do this, but nothing stops you:
#include <iostream>
#include <string>
using namespace std;
void foo(char *ch)
{
ch[0] = 'B';
}
int main()
{
string str = "helo world";
char *ch = const_cast<char *>(str.c_str());
foo(ch);
// Belo world
cout << str << endl;
return 0;
}

How can I transfer string to char* (not const char*)

I wanna do something like:
string result;
char* a[100];
a[0]=result;
it seems that result.c_str() has to be const char*. Is there any way to do this?
You can take the address of the first character in the string.
a[0] = &result[0];
This is guaranteed to work in C++11. (The internal string representation must be contiguous and null-terminated like a C-style string)
In C++03 these guarantees do not exist, but all common implementations will work.
string result;
char a[100] = {0};
strncpy(a, result.c_str(), sizeof(a) - 1);
There is a member function (method) called "copy" to have this done.
but you need create the buffer first.
like this
string result;
char* a[100];
a[0] = new char[result.length() + 1];
result.copy(a[0], result.length(), 0);
a[0][result.length()] = '\0';
(references: http://www.cplusplus.com/reference/string/basic_string/copy/ )
by the way, I wonder if you means
string result;
char a[100];
You can do:
char a[100];
::strncpy(a, result.c_str(), 100);
Be careful of null termination.
The old fashioned way:
#include <string.h>
a[0] = strdup(result.c_str()); // allocates memory for a new string and copies it over
[...]
free(a[0]); // don't forget this or you leak memory!
If you really, truly can't avoid doing this, you shouldn't throw away all that C++ offers, and descend to using raw arrays and horrible functions like strncpy.
One reasonable possibility would be to copy the data from the string to a vector:
char const *temp = result.c_str();
std::vector<char> a(temp, temp+result.size()+1);
You can usually leave the data in the string though -- if you need a non-const pointer to the string's data, you can use &result[0].