Get a char from a pointer to a string - c++

Hello I am trying to write a function that converts a string to lowercase by using a pointer instead of a return value.
void makeLowerCase(std::string* in){
//for loop tolower(char from *in);}
but I have no idea how to get each char out of my pointer to use tolower() with, or how to get how many chars are in the string as
*in.length()
and
sizeof(*in)/sizeof(char)
don't work for it. The former I get an error on the use of a pointer, the latter I get the same return value for sizeof(*in) so I don't even know how I would end my for loop.

C++ has a shortcut to get the member of an object pointed to by a pointer:
in->length()
For accessing characters, use parentheses:
(*in)[i]

Instead of passing by pointer and dealing with pointer syntax you can pass the string by reference and then you can use it just like a normal std::string. If you have to use a pointer then you can either use
in->length();
or
(*in).length();
The parentheses are required in the second case as . has a higher precedence then *.
As for transforming the string to lower case you can use the built in functions from <algorithm> and and that would give you
void makeLowerCase(std::string& in)
{
std::transform(in.begin(), in.end(), in.begin(), ::tolower);
}

*in.length()
does not work because . has a higher precedence than *. Use parantheses:
(*in).length()
sizeof(*in)/sizeof(char)
is the same as
sizeof(*in) / 1
because sizeof(char) == 1. sizeof(*in) == sizeof(std::string), so this yields the size of the std::string object itsself, not the string of characters, which is implemention-defined.
This information, in combination with iterators, for_each, and lambdas, make for a pretty three-liner without any functions:
#include <cctype>
...
for (char& c : str)
c = std::tolower(c);
Notes:
Use references instead. They look better and are easier usable. Pointers should only be used in C++ for low-level stuff or when there's no way to cut them out.

For pointers you would use the pointer operator. So that would be
in->length();
However a naked loop is not the ideal way (nor is using pointers to be honest).
A better way would be to use iterators to iterate through the string and convert it that way.
for (auto it=in->begin(); it!=in->end(); ++it) {
*it = std::tolower(*it);
}

Related

Comparing two strings in c++ issue.

Having this code:
char a[20]="wasd", b[20]="asd";
if((a+1)==b)
printf("yes");
Will not return "yes", even if "a+1" is "asd". I am wondering what am I doing wrong?
You need to use strcmp to compare C strings. == will just compare the pointers.
For example:
#include <string.h> // or <cstring> if you're writing C++
...
char a[20]="wasd", b[20]="asd";
if(strcmp(a+1, b)==0)
printf("yes");
By the way, if you're writing C++, you'd be better off using std::string. Then you could have simply used == to compare them.
If it's not a student assignment and you truly are using C++(as your tag says) you should use strings. Now you're using arrays and comparing arrays addresses instead of real strings. In a C++ way your code might look like:
#include <iostream>
#include <string>
int main()
{
std::string a ="wasd";
std::string b ="asd";
if(a.substr(1) == b)
std::cout << "Yes!\n";
}
Well, there is a better way to find if one string contains another but the code is a direct mapping of your C code to the C++-ish one.
You are actually comparing pointer addresses, not the actual string contents.
Your code should use strcmp:
char a[20]="wasd", b[20]="asd";
if(strcmp(a+1, b) == 0)
printf("yes");
Be careful that strcmp returns 0 if the strings are identical.
A better and more idiomatic alternative would be to use std::string:
std::string a = "wasd", b = "asd";
if(a.substr(1) == b)
std::cout << "yes";
substr does copy the string though, so it is slightly less efficient than the previous approach.
You have to use strcmp from string.h to compare strings.
if(strcmp(a+1,b)==0)
in Your case.
As per your code, when using (a+1)==b you are comparing the addresses of the pointers pointing respectively to second character of string 'a' and the first character of string 'b'.
It can work if you modify your code as:
char a[20]="wasd", b[20]="asd";
if(*(a+1)==*b) // now we are comparing the values towards which the
printf("yes"); // respective pointers are pointing
You can also use compare() for comparison of strings included in .

std::string without null-character

Is a std::string without a null-character in the end valid and can it be acquired like this?:
std::string str = "Hello World";
str.resize(str.size() - 1);
For those who are curious:
I have a 3rd party function taking a string and iterating over the chars (using iterators). Unfortunately the function is buggy (as its a dev-version) and cannot deal with null-characters. I dont have another signature to chose from, I cant modify the function (as I said, 3rd party and we dont want to fork) and at the same time I dont want to reinvent the wheel. As far as I can tell, the function should work as desired without the null-character so I want atleast to give it a try.
The iteration takes place like this:
bool nextChar(CharIntType& c)
{
if (_it == _end) return false;
c = *_it;
++_it;
return true;
}
where _it is initialized to std::string::begin() and _end to std::string::end()
Until C++11, std::string was not required to include a trailing nul until you called c_str().
http://en.cppreference.com/w/cpp/string/basic_string/data
std::string::data()
Returns pointer to the underlying array serving as character storage. The pointer is such that the range [data(); data() + size()) is valid and the values in it correspond to the values stored in the string.
The returned array is not required to be null-terminated.
If empty() returns true, the pointer is a non-null pointer that should not be dereferenced. (until c++11)
The returned array is null-terminated, that is, data() and c_str() perform the same function.
If empty() returns true, the pointer points to a single null character. (since c++11)
From this we can confirm that std::string::size does not include any nul terminator, and that std::string::begin() and std::string::end() describe the ranges you are actually looking for.
We can also determine this by the simple fact that std::string::back() doesn't return a nul character.
#include <iostream>
#include <string>
int main() {
std::string s("hello, world");
std::cout << "s.front = " << s.front() << " s.back = " << s.back() << '\n';
return 0;
}
http://ideone.com/nUX0AB
While it is possible to have non null terminated strings I would not recommend it, strings are null terminated for a good reason, i would actually recommend in this instance that you either go ahead and write the function properly or get in touch with the third party and have them fix it.
To answer your questions yes a std::string is valid if it is not null terminated, to achieve this you can use the overload of string copy with a maximum length loaded, once again i do not recommend this.
See this page for more information:
http://c2.com/cgi/wiki?NonNullTerminatedString
This is a very late answer but I just post it so that anyone who comes later can use it for their reference. If you write a null terminated string into the string.data() array, it will terminate the string and would not let you to continue concatenate the string if you need to. The way to solve it is already answer in the question.
str.resize(str.size() - 1);
This would solve the problem, I have tested out in my code.

Print text between pointers

I have a character range with pointers (pBegin and pEnd). I think of it as a string, but it is not \0 terminated. How can I print it to std::cout effectively?
Without creating a copy, like with std::string
Without a loop that prints each character
Do we have good solution? If not, what is the smoothest workaround?
You can use ostream::write, which takes pointer and length arguments:
std::cout.write(pBegin, pEnd - pBegin);
Since C++17 you can use std::string_view, which was created for sharing part of std::string without copying
std::cout << std::string_view(pBegin, pEnd - pBegin);
pEnd must point to one pass the last character to print, like how iterators in C++ work, instead of the last character to print
What is string_view?
In C++11 what is the most performant way to return a reference/pointer to a position in a std::string?
In older C++ standards boost::string_ref is an alternative. Newer boost versions also have boost::string_view with the same semantics as std::string_view. See Differences between boost::string_ref and boost::string_view
If you use Qt then there's also QStringView and QStringRef although unfortunately they're used for viewing QString which stores data in UTF-16 instead of UTF-8 or a byte-oriented encoding
However if you need to process the string by some functions that require null-terminated string without any external libraries then there's a simple solution
char tmpEnd = *pEnd; // backup the after-end character
*pEnd = '\0';
std::cout << pBegin; // use it as normal C-style string, like dosomething(pBegin);
*pEnd = tmpEnd; // restore the char
In this case make sure that pEnd still points to an element inside the original array and not one past the end of it

Character Pointers (allotted by new)

I wrote the following code:
char *pch=new char[12];
char *f=new char[42];
char *lab=new char[20];
char *mne=new char[10];
char *add=new char[10];
If initially I want these arrays to be null, can't I do this:
*lab="\0";
*mne="\0";
and so on.....
And after that if I want to add some cstring to an empty array can't I check:
if(strcmp(lab,"\0")==0)
//then add cstring by *lab="cstring";
And if I can't do any of these things, please tell me the right way to do it...
In C++11, an easy way to initialize arrays is by using brace-initializers:
char * p = new char[100] { 0 };
The reasoning here is that all the missing array elements will be zero-initialized. You can also use explicit value-initialization (I think that's even allowed in C++98/03), which is zero-initalization for the primitive types:
char * q = new char[110]();
First of all, as DeadMG says, the correct way of doing this is using std:string:
std::string lab; // empty initially, no further initialization needed
if (lab.size() == 0) // string empty, note, very fast, no character comparison
lab += "cstring"; // or even lab = "cstring", as lab is empty
Also, in your code, if you insist in using C strings, after the initialization, the correct checking for the empty string would be
if (*lab == '\0')
First of all, I agree with everybody else to use a std::string instead of character arrays the vast majority of the time. Link for help is here: C++ Strings Library
Now to directly answer your question as well:
*lab="\0";
*mne="\0";
and so on.....
This is wrong. Assuming your compiler doesn't give you an error, you're not assigning the "null terminator" to those arrays, you're trying to assign the pointer value of where the "\0" string is to the first few memory locations where the char* is pointing to! Remember, your variables are pointers, not strings. If you're trying to just put a null-character at the beginning, so that strlen or other C-string functions see an "empty" string, do this: *lab='\0'; The difference is that with single-ticks, it denotes the character \0 whereas with double, it's a string literal, which returns a pointer to the first element. I hope that made sense.
Now for your second, again, you can't just "assign" like that to C-style strings. You need to put each character into the array and terminate it correctly. Usually the easiest way is with sprintf:
sprintf(lab, "%s", "mystring");
This may not make much sense, especially as I'm not dereferencing the pointer, but I'll walk you through it. The first argument says to sprintf "output your characters to where this pointer is pointing." So it needs the raw pointer. The second is a format string, like printf uses. So I'm telling it to use the first argument as a string. And the 3rd is what I want in there, a pointer to another string. This example would also work with sprintf(lab, "mystring") as well.
If you want to get into C-style string processing, you need to read some examples. I'm afraid I don't even know where to look on the 'net for good examples of that, but I wish you good luck. I'd highly recommend that you check out the C++ strings library though, and the basic_string<> type there. That's typedef'd to just std::string, which is what you should use.

Pass contents of stringstream to function taking char* as argument

I have a function for writing ppm files (a picture format) to disk. It takes the filename as a char* array. In my main function, I put together a filename using a stringstream and the << operator. Then, I want to pass the results of this to my ppm function. I've seen this discussed elsewhere, often with very convoluted looking methods (many in-between conversion steps).
What I've done is shown in the code below, and the tricky part that others usually do in many steps with temp variables is (char*) (PPM_file_name.str().data()). What this accomplishes is to extract the string from stringstream PPM_file_name with .str(), then get the pointer to its actual contents with .data() (this is a const char*), then cast that to a regular (char*). More complete example below.
I've found the following to work fine so far, but it makes me uneasy because usually when other people have done something in a seemingly more convoluted way, it's because that's a safer way to do it. So, can anyone tell me if what I'm doing here is safe and also how portable is it?
Thanks.
#include <iostream>
#include <sstream>
#include <stdio.h>
#include <string>
using namespace std;
int main(int argc, char *argv[]){
// String stream to hold the file name so I can create it from a series of other variable
stringstream PPM_file_name;
// ... a bunch of other code where int ccd_num and string cur_id_str are created and initialized
// Assemble the file name
PPM_file_name << "ccd" << ccd_num << "_" << cur_id_str << ".ppm";
// From PPM_file_name, extract its string, then the const char* pointer to that string's data, then cast that to char*
write_ppm((char*)(PPM_file_name.str().data()),"ladybug_vidcapture.cpp",rgb_images[ccd_num],width,height);
return 0;
}
Thanks everyone. So, following a few peoples' suggestions here, I've done the following, since I do have control over write_ppm:
Modified write_ppm to take const char*:
void write_ppm(const char *file_name, char *comment, unsigned char *image,int width,int height)
And now I'm passing ppm_file_name as follows:
write_ppm((PPM_file_name.str().c_str()),"A comment",rgb_images[ccd_num],width,height);
Is there anything I should do here, or does that mostly clear up the issues with how this was being passed before? Should all the other char arguments to write_ppm be const as well? It's a very short function, and it doesn't appear to modify any of the arguments. Thanks.
This looks like a typical case of someone not writing const-correct code and it having the knock-on effect. You have several choices:
If write_ppm is under your control, or the control of anyone you know, get them to make it const corrct
If it is not, and you can guarantee it never changes the filename then const_cast
If you cannot guarantee that, copy your string into a std::vector plus the null terminator and pass &vec[0] (where vec represents the name of your vector variable)
You should use PPM_file_name.str().c_str(), since data() isn't guaranteed to return a null-terminated string.
Either write_ppm() should take its first argument by const char* (promising not to change the string's content) or you must not pass a string stream (because you must not change its content that way).
You shouldn't use C-style casts in C++, because they don't differentiate between different reasons to cast. Yours is casting away const, which, if at all, should be done using const_cast<>. But as a rule of thumb, const_cast<> is usually only required to make code compile that isn't const-correct, which I'd consider an error.
It's absolutely safe and portable as long as write_ppm doesn't actually change the argument, in which case it is undefined behavior. I would recommend using const_cast<char*> instead of C-style cast. Also consider using c_str() member instead of the data() member. The former guarantees to return a null-terminated string
Use c_str() instead of data() (c_str() return a NULL-terminated sequence of characters).
Why not simply use const_cast<char *>(PPM_file_name.str().c_str()) ?