How can I access each member in a std::string variable? For example, if I have
string buff;
suppose buff conatains "10 20 A" as ASCII content. How could I then access 10, 20, and A separately?
Here is an answer for you on SO:
How do I tokenize a string in C++?
There are many ways to skin that cat...
You can access the strings by index. i.e duff[0], duff[1] and duff[2].
I just tried. This works.
string helloWorld[2] = {"HELLO", "WORLD"};
char c = helloWorld[0][0];
cout << c;
It outputs "H"
Well I see you have tagged both C and C++.
If you are using C, strings are an array of characters. You can access each character like you would a normal array:
char a = duff[0];
char b = duff[1];
char c = duff[2];
If you are using C++ and using a character array, see above. If you are using a std::string (this is why C and C++ should be tagged separately), there are many ways you can access each character in the string:
// std::string::iterator if you want the string to be modifiable
for (std::string::const_iterator i = duff.begin(); i != duff.end(); ++i)
{
}
or:
char c = duff.at(i); // where i is the index; the same as duff[i]
and probably more.
Related
Do you guys know why the following code crash during the runtime?
char* word;
word = new char[20];
word = "HeLlo";
for (auto it = word; it != NULL; it++){
*it = (char) tolower(*it);
I'm trying to lowercase a char* (string). I'm using visual studio.
Thanks
You cannot compare it to NULL. Instead you should be comparing *it to '\0'. Or better yet, use std::string and never worry about it :-)
In summary, when looping over a C-style string. You should be looping until the character you see is a '\0'. The iterator itself will never be NULL, since it is simply pointing a place in the string. The fact that the iterator has a type which can be compared to NULL is an implementation detail that you shouldn't touch directly.
Additionally, you are trying to write to a string literal. Which is a no-no :-).
EDIT:
As noted by #Cheers and hth. - Alf, tolower can break if given negative values. So sadly, we need to add a cast to make sure this won't break if you feed it Latin-1 encoded data or similar.
This should work:
char word[] = "HeLlo";
for (auto it = word; *it != '\0'; ++it) {
*it = tolower(static_cast<unsigned char>(*it));
}
You're setting word to point to the string literal, but literals are read-only, so this results in undefined behavior when you assign to *it. You need to make a copy of it in the dynamically-allocated memory.
char *word = new char[20];
strcpy(word, "HeLlo");
Also in your loop you should compare *it != '\0'. The end of a string is indicated by the character being the null byte, not the pointer being null.
Given code (as I'm writing this):
char* word;
word = new char[20];
word = "HeLlo";
for (auto it = word; it != NULL; it++){
*it = (char) tolower(*it);
This code has Undefined Behavior in 2 distinct ways, and would have UB also in a third way if only the text data was slightly different:
Buffer overrun.
The continuation condition it != NULL will not be false until the pointer it has wrapped around at the end of the address range, if it does.
Modifying read only memory.
The pointer word is set to point to the first char of a string literal, and then the loop iterates over that string and assigns to each char.
Passing possible negative value to tolower.
The char classification functions require a non-negative argument, or else the special value EOF. This works fine with the string "HeLlo" under an assumption of ASCII or unsigned char type. But in general, e.g. with the string "Blåbærsyltetøy", directly passing each char value to tolower will result in negative values being passed; a correct invocation with ch of type char is (char) tolower( (unsigned char)ch ).
Additionally the code has a memory leak, by allocating some memory with new and then just forgetting about it.
A correct way to code the apparent intent:
using Byte = unsigned char;
auto to_lower( char const c )
-> char
{ return Byte( tolower( Byte( c ) ) ); }
// ...
string word = "Hello";
for( char& ch : word ) { ch = to_lower( ch ); }
There are already two nice answers on how to solve your issues using null terminated c-strings and poitners. For the sake of completeness, I propose you an approach using c++ strings:
string word; // instead of char*
//word = new char[20]; // no longuer needed: strings take care for themseves
word = "HeLlo"; // no worry about deallocating previous values: strings take care for themselves
for (auto &it : word) // use of range for, to iterate through all the string elements
it = (char) tolower(it);
Its crashing because you are modifying a string literal.
there is a dedicated functions for this
use
strupr for making string uppercase and strlwr for making the string lower case.
here is an usage example:
char str[ ] = "make me upper";
printf("%s\n",strupr(str));
char str[ ] = "make me lower";
printf("%s\n",strlwr (str));
I want to do something similar to this:
char* a = (char*)msg[0];
char* b = (char*)msg[1];
char* c = a + "," + b;
Where msg is an array of int.
N.B.: This is Arduino C++, not regular C++.
Arduino doesn't use std::string, instead it uses String (note the capital S and dropped std::). They're used the same way as std::string for the most part. So basically you should just be able to do this:
String a("hello");
String b(" world");
c = a + b;
If you want to convert an integer to a String, it has a constructor to do just that, e.g.:
String a = String(msg[0]);
String b = String(msg[1]);
You can find more examples here and here.
See strcat.
You seem to be programming C, not C++.
This should be covered in the most basic tutorials.
SOLUTION
so here is my solution thank everyone.
String a = String(msg[0]);
String b = String(msg[1]);
String c = a + "," + b;
char* d;
c.toCharArray(d,c.length());
mclient.publish("topic1/sensorAck",d);
I'm new to C++ and I've encountered a problem... I can't seem to create an array of characters from a string using a for loop. For example, in JavaScript you would write something like this:
var arr = [];
function setString(s) {
for(var i = s.length - 1; i >= 0; i--) {
arr.push(s[i]);
}
return arr.join("");
}
setString("Hello World!"); //Returns !dlroW olleH
I know it's a bit complicated, I do have a little bit of background knowledge on how to do it but the syntax of it is still not too familiar to me.
Is there any way that I could do that in c++ using arrays?
Could I join the array elements into one string as I do in JavaScript?
It would be greately appreciated if you could help. Thanks in advance.
If anyone needs more information just tell me and I'll edit the post.
By the way, my code in c++ is really messy at the moment but I have an idea of what I'm doing... What I've tried is this:
function setString(s) {
string arr[s.size() - 1];
for(int i = s.size() - 1; i >= 0; i--) {
arr[i] = s.at(i); //This is where I get stuck at...
//I don't know if I'm doing something wrong or not.
}
}
It would be nice if someone told me what I'm doing wrong or what I need to put or take out of the code. It's a console application compiled in Code::Blocks
std::string has the c_str() method that returns a C style string, which is just an array of characters.
Example:
std::string myString = "Hello, World!";
const char *characters = myString.c_str();
The closest thing to a direct translation of your function:
string setString(string s) {
string arr;
for(int i = s.length() - 1; i >= 0; i--) {
arr.push_back(s[i]);
}
return arr;
}
A std::string is a dynamic array underneath a fairly thin wrapper. There is no need to copy character by character, as it will do it properly for you:
If the character array is null-terminated (that is, the last element is a '\0'):
const char* c = "Hello, world!"; // '\0' is implicit for string literals
std::string s = c; // this will copy the entire string - no need for your loop
If the character array is not null-terminated:
char c[4] = {'a', 'b', 'c', 'd'}; // creates a character array that will not work with cstdlib string functions (e.g. strlen)
std::string s(c, 4); // copies 4 characters from c into s - again, no need for your loop
If you cannot use std::string (e.g. if you are forced to use ANSI C):
const char* c = "Hello, World!";
// assume c2 is already properly allocated to strlen(c) + 1 and initialized to all zeros
strcpy(c2, c);
In your javascript example, you are reversing the string, which can be done easily enough:
std::string s = "Hello, world!";
std::string s1(s.rbegin(), s.rend());
Additionally, you can cut your iterations in half (for both C++ and Javascript) if you fix your loop (pseudo-code below):
string s = "Hello, world!"
for i = 0 to s.Length / 2
char t = s[i]
s[i] = s[s.Length - 1 - t]
s[s.Length - 1 - i] = t
Which will swap the ends of the string to reverse it. Instead of looping through N items, you loop through a maximum of N / 2 items.
I need an empty char array, but when i try do thing like this:
char *c;
c = new char [m];
int i;
for (i = 0; i < m; i++)
c[i] = 65 + i;
and then I print c. can see that c = 0x00384900 "НННННННээээ««««««««юоюою"
after cycle it becomes: 0x00384900 "ABCDEFGээээ««««««««юоюою"
How can I solve this problem? Or maybe there is way with string?
If you're trying to create a string, you need to make sure that the character sequence is terminated with the null character \0.
In other words:
char *c;
c = new char [m+1];
int i;
for (i = 0; i < m; i++)
c[i] = 65 + i;
c[m] = '\0';
Without it, functions on strings like printf won't know where the string ends.
printf("%s\n",c); // should work now
If you create a heap array, OS will not initialiase it.
To do so you hvae these options:
Allocate an array statically or globally. The array will be filled with zeroes automatically.
Use ::memset( c, 0, m ); on heap-initialised or stack array to fill it with zeroes.
Use high-level types like std::string.
I believe that's your debugger trying to interpret the string. When using a char array to represent a string in C or C++, you need to include a null byte at the end of the string. So, if you allocate m + 1 characters for c, and then set c[m] = '\0', your debugger should give you the value you are expecting.
If you want a dynamically-allocated string, then the best option is to use the string class from the standard library:
#include <string>
std::string s;
for (i = 0; i < m; i++)
s.push_back(65 + i);
C strings are null terminated. That means that the last character must be a null character ('\0' or just 0).
The functions that manipulate your string use the characters between the beginning of the array (that you passed as parameter, first position in the array) and a null value. If there is no null character in your array the function will iterate pass it's memory until it finds one (memory leak). That's why you got some garbage printed in your example.
When you see a literal constant in your code, like printf("Hello");, it is translate into an array of char of length 6 ('H', 'e', 'l', 'l', 'o' and '\0');
Of course, to avoid such complexity you can use std::string.
I'm trying to use MurmurHash (returning 64 bit hashes on a 64bit comoputer) and have sent it the simple 3 letter string 'yes' as follows
char* charptr = "yes";
cout << MurmurHash64A(charptr, 3, 10);
(where 3 is the length and 10 is the seed)
This gives a 64bit hashed response as expected, I can set up more pointers to C strings holding yes and they all return the same hashed value.
But if I try to sending it a C++ string:
string mystring = "yes";
string* strptr = &mystring;
cout << MurmurHash64A(strptr, 3, 10);
...I get a different result to the C string method, what's more if I set up several of these strings in the same way, they all give different results.
This suggests to me that strings are maybe not stored in contiguous memory locations, some Googling backed this up.
So I then tried to set up a vector in dynamic memory as this was the only way I could think of to force contigous memory.
Just like the C++ string method it returned a different result from the C string method and when I set up several they all return a different result from each other. I set them up like follows:
char yes[3] = {'y', 'e', 's'};
vector<char> *charvec = new vector<char>;
void* myvecptr3 = &charvec;
charvec->reserve(3);
charvec->push_back(yes[0]);
charvec->push_back(yes[1]);
charvec->push_back(yes[2]);
As I understand it my char vector will start at the address the vector is given and fill consecutive bytes with my three characters in the same way as a C string.
I am confused why I'm getting different results, any help appreciated?
Thanks
C
&mystring points at the string object. You want to use mystring.c_str() to get a pointer to a raw character array.
For the vector, you want &(*charvec)[0]. But you probably don't want to use new; you could just do vector<char> charvec; void *myvecptr3 = &charvec[0];.
The reason is that std::string itself stores a pointer to the char array. Try
string mystring = "yes";
cout << MurmurHash64A(mystring.c_str(), 3, 10);
And you would not need to work with char vector indeed.