I following code illustrates the use of c_str function
#include <iostream>
#include <string.h>
using namespace std;
int main() {
std::string str("Hello world!");
int pos1 = str.find_first_of('w');
cout<< "pos1: "<< pos1 <<endl;
int pos2 = strchr(str.c_str(), 'w') - str.c_str(); //*
//int pos2 = strchr(str.c_str(), 'w')
cout<< "pos2: "<< pos2 <<endl;
cout<< "str.c_str(): "<< str.c_str() <<endl;
if (pos1 == pos2) {
printf("Both ways give the same result.\n");
}
}
The output is
pos1: 6
pos2: 6
str.c_str(): Hello world!
Both ways give the same result.
I don't get the str.c_str() role in line * . I am substracting a string from an int, what is the meaning of that?
When I erase it, that is when I comment line * , and uncomment the following line I get an error: invalid conversion from 'char*' to 'int'. How come there is not error in the original code?
.c_str() returns the address to the start of the string. strchr the address to the first occurence of a specific character inside the given string or a nullptr, if the character is not found.
If you subtract one address from another, you get the distance of the to pointers, which is the offset of the character inside the string in this case.
The find_* functions of the string class all return the offset or std::string::npos, if the character is not found.
Reference:
strchr
c_str
find_first_of
First,strchr returns a pointer.Pointrer types require a forced cast.
Second,The data type of the pointer is related to the number of CPU bits.So you should use unsigned long type.
Related
I was trying to print the last character of a string, for example str[]="This is an example", I tried to print the 'e' of "example" with some functions, but none of them funct as I expected. I know it's more simple to write in the code the position number of the last character, but as in strrchr function, the code work by itself. Is there a function that works similar?
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
int main ()
{
char str[] = "This is an example";
char * pch;
pch=strrchr(str,'s');
cout<<str<<endl;
cout<<"Last time 's' was found was in position: "<<pch-str+1<<endl;
cout<<"Last character in this example is "<<str[X];
return 0;
}
From the documentation for strrchr:
The terminating null-character is considered part of the C string. Therefore, it can also be located to retrieve a pointer to the end of a string.
Thus, strrchr(str, '\0')[-1] will have the last character. Note that this is only safe if you're sure str isn't empty.
Simple: use the standard strlen function, as follows:
int main ()
{
char str[] = "This is an example";
char * pch;
pch=strrchr(str,'s');
cout<<str<<endl;
cout<<"Last time 's' was found was in position: "<<pch-str+1<<endl;
size_t X = strlen(str) - 1; // X will be the index of the last character!
cout<<"Last character in this example is "<<str[X];
return 0;
}
Or, just for fun, if you want to handle the case where the string could be empty:
size_t X = strlen(str); X -= !!X; // Non-zero: decrement, Zero: Leave as is
cout<<"Last character in this example is "<<str[X];
Then, for an empty string, cout << str[X] will show whatever the implementation does for a NULL character.
If you don't mind to use std::string this snippet would do the job.
#include <string>
#include <iostream>
int main() {
std::string str = "This is some text";
std::cout << str.back() << std::endl;
}
I assume you choose char[] to avoid allocation or something similar so am not going to discuss std::string as an option.
Three solutions, one in modern C++ using string_view, one using templates ;
and one using std::size and the index operator.
Solution 1.1:
I recommend you use this, its nearly optimal and is much more readable than the alternative. It also doesn't require as much boiler plate to handle empty strings, or strings without null termination.
#include <string_view>
#include <iostream>
int main()
{
std::string_view str = "This is an example";
auto X = str.find_last_of('s');
//
// Make sure the character exists in the string
if (X != std::string_view::npos)
{
std::cout<< str << std::endl;
std::cout<< "Last time 's' was found was in position: " << X << std::endl;
}
else
{
std::cout<<"Character did not exist in string.\n";
}
if (!str.empty()) std::cout<< "Last character in this example is " << str.back();
else std::cout << "Cannot get the last character in an empty string!";
return 0;
}
You can run the solution here:
https://onlinegdb.com/SJK2hjPEB
The same code will work with std::string.
Solution 1.2
This is a compile time only solution, it relies on the string being aggregate constructed or constructed as a string.
template <size_t N>
constexpr char LastCharacter(char (&input)[N])
{
static_assert(N >= 1, "A character array representing a string must have atleast 1 character AND a null terminator.");
return (input[N - 1] == '\0') ? input[N - 2] : input[N - 1];
}
Tests and examples shown here:
https://onlinegdb.com/HJ_IXEd4H
Solution 2
This has the required checks to avoid issues with empty strings.
In this version it is a compile time error to have an empty array. str[] = "" is not an empty array it has 1 character, a null. An empty string has no last character, this needs to be handled. It also should be handled for the strrchr.
If you must use strrchr(...) then consider checking whether the result is nullptr. If a nullptr is returned then the character wasn't found in the string:
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <cassert>
using namespace std;
int main ()
{
char str[] = {'h', 'e','l', 'l', 'o', '\0'};
//
// Prevent use with an empty array (1 character + 1 null character minimum)
if (std::size(str) > 1)
{
//
// Only allow null terminated strings.
assert( str[std::size(str) - 1] == '\0' );
//
// There skip the last null character and get the last character
// No null character, not compensation needed
cout<<"Last character in this example is "<< str[ std::size(str) - 2 ];
}
else
{
cout << "Cannot process empty string\n";
}
return 0;
}
https://onlinegdb.com/SkrP2Q_NB
Please note, defining strings as arrays enables strings to exist without null terminators. In that case the above solution does not function. If you want to handle that case you need to check for the existance of a null terminator and if it is present compensate in code. assert causes an error if there isn't a null terminator.
--
To elaborate on the problem with strrchr. The function requires a null terminated string.
The terminating null-character is considered part of the C string.
Therefore, it can also be located to retrieve a pointer to the end of
a string.
http://www.cplusplus.com/reference/cstring/strrchr/
This was quoted by the previous answer, but for completeness also here.
The datatype you are using allows a character array with no null termination:
char data[] = {'a', 'b', 'c'};
That is what the assert handles in the solution 2.
I am trying to limit user input into alphabet only, then sort all the character in ascending order.
build messages
error: no matching function for call to 'std::__cxx11::basic_string::basic_string(char&)'
This is my header
#include <iostream>
#include <string.h>
#include <conio.h>
#include <stdio.h>
#include <regex>
should i convert the char into string then convert back to char for my following code ?
string Sortstr (str[mlength]);
sort(Sortstr.begin(), Sortstr.end());
getting this 2 line error.
int mlength = 100;
int main() {
char str[mlength];
int length;
cout << "Please enter a c-string: ";
cin.getline(str,mlength,'\n');
regex pass1("^[a-zA-Z]+");
while(!regex_match(str,pass1)) {
cout<<"Error"<<endl;
cout << "Please enter a c-string: ";
cin.getline(str,mlength,'\n');
}
string Sortstr (str);
sort(str, str + strlen(str));
}
Why not just sort str?
sort(str, str + strlen(str));
There's no reason you can't sort an array directly. Just pass pointers to the first and one-past-the-end elements of your array to sort. In this case adding strlen gets a pointer to the effective end of your array.
In this line
string Sortstr (str[mlength]);
you are using the index operator on a char array which gives you one single char. So, you are passing one single char to the string constructor. This constructor does not exist, hence the error. Even if it existed, you do not want to pass one single char but the entire char array.
What you want is this:
string Sortstr (str);
I have a code that I'm trying to learn how to parse in C++. I understood everything I did, but I don't understand how to work with the likes of atoi(), atof (), strtod (). I know what it's supposed to do, but I don't understand why the compiler doesn't like it. My focus on the error is "scores[line_count] = strtod (score);"
#include <iostream>
#include <fstream>
#include <string>
#include <stdlib.h>
#include <iomanip>
using namespace std;
int readScores(string inputFile, string name[], float scores[], int array_size)
{
//delcare variables
ifstream infile;
int line_count = 0;
string line;
string named;
float score;
char character;
int word_index;
string names[array_size];
// open input file
infile.open(inputFile);
//Check if file opens succesfully.
if(infile.fail())
{
cout << "File cannot open!!" << endl;
return -1;
}
while(getline(infile, line))
{
cout << line << endl;
// PARSING GOES HERE
word_index = 0;
for(int i=0; i < (int)line.length(); i++)
{
character = line[i];
if (character == ',')
{
names[line_count] = named;
named = "";
word_index++;
}
else
{
if(word_index == 0)
{
named += character;
}
else if (word_index == 1)
{
score += character;
cout << character << " " << endl;
}
}
}
scores[line_count] = strtod (score);
line_count++;
}
//close file
infile.close();
//return line count
return line_count;
cout << line_count << endl;
}
int main(void)
{
int array_size = 50;
string inputFile = "Test.txt";
string name [array_size];
float scores [array_size];
readScores(inputFile, name, scores, array_size);
}
The function strtod() takes the form
double strtod (const char* str, char** endptr);
But you only give it the string.
As you can see it takes two parameters, the string you wish to convert to a double, and an "endptr". The endptr is described here as a
Reference to an already allocated object of type char*, whose value is set by > the function to the next character in str after the numerical value.
This parameter can also be a null pointer, in which case it is not used.
So you need to declare a char pointer to save the next character after the decimal, even if there wont be one. This allows you to pull multiple doubles from a single string, much like a tokenizer.
char * endPtr;
scores[line_count] = strtod(score, &endPtr);
Edit
As Alex Lop pointed out, you aren't even passing a string to strtod, you're passing a float. It appears you would like to cast the float to a double?
Of course the compiler doesn't like it. Please read the description of strtod.
double strtod (const char* str, char** endptr);
Convert string to
double.
Parses the C-string str interpreting its content as a floating
point number (according to the current locale) and returns its value
as a double. If endptr is not a null pointer, the function also sets
the value of endptr to point to the first character after the number.
The function first discards as many whitespace characters (as in
isspace) as necessary until the first non-whitespace character is
found. Then, starting from this character, takes as many characters as
possible that are valid following a syntax resembling that of floating
point literals (see below), and interprets them as a numerical value.
A pointer to the rest of the string after the last valid character is
stored in the object pointed by endptr.
And in your code you pass to strtod only one parameter which is of type float and store the returned result of double into an array of floats. If you want to move the value of float from one variable to another, you don't need any "convertion" function:
scores[line_count] = score;
NOTE: I didn't really review your code as you asked specifically about scores[line_count] = strtod (score);. But after I looked how you modify score, maybe it should have been string and not float. If so, then it is the another point to fix.
I have a problem, do not to compile this code but, to execute this program. When I run it in the terminal it prints the first 2 cout then the program stops working and the screen on the windows that tells you, i think the problem is to strcat.
I'm using DEVC++ and I have windows 7 pro.
#include <iostream>
#include <string>
#include <cstdlib>
#include <string.h>
using namespace std;
int main() {
char* cambia[] = {"ciao "};
char* c[] = {"mondo"};
cout << "*c: " << *c << endl;
cout << "*cambia: " << *cambia << endl;
strcat( *cambia, *c );
cout << "*cambia: " << *cambia << endl;
}
You don't use strcat() in C++ if you don't absolutely have to (e.g. when maintaining legacy code and touching as little stuff as possible).
Use std::string and its member functions like find or substr for simple tasks, string streams or Boost libraries for more complex string splitting.
At any rate, stay away from strcat().
The method strcat() adds the string from the second argument to the buffer of which you submit to the first argument.
First, the buffer has to be writable. In your example, you are passing a string literal as buffer. Naturally, string literals are read-only. But even then, the string literal has no spare space where the new string could be added.
Instead of fixing your code, let me show you some proper examples how to concat strings in C++ and in C.
This example is showing you how to concat two C++ strings:
#include <iostream>
#include <string>
int main(int argc, const char * argv[])
{
// Create a new C++ string with an initial text.
std::string result = "First string part ";
std::cout << "Result: " << result << std::endl;
// Add some text
std::string textToAppend = "and the second part";
result.append(textToAppend);
std::cout << "Result: " << result << std::endl;
return 0;
}
The following example is showing you how to concat two strings in C:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, const char * argv[])
{
// The two texts to concat
const char *firstText = "This is the first text ";
const char *secondText = "and this is the second one";
// A buffer which is large enough for the operation.
const int bufferSize = 1024;
char buffer[bufferSize];
// Copy the initial text into the buffer.
strncpy(buffer, firstText, bufferSize);
// Add the secon string
strncat(buffer, secondText, bufferSize-strlen(buffer));
// Output the string
printf("Result: %s\n", buffer);
return 0;
}
I suggest, you should use C++ strings if possible. They automatically manage the memory which prevent many memory related issues with C strings.
This line
char* cambia[] = {"ciao "};
creates a variable named cambia in a dynamically created part of memory, called 'stack'. The variable is an array with no declared size, and elements of that array are pointers to characters.
The size of the array follows from the initializer
{"ciao "}
which implies the array will have only one element, and that element is initialized with a value pointing at the first character of string "ciao ". However, the string "ciao " is placed in some completely different area of memory - it is in static block, initialized by a compiler with values found in the program's code. Compiler does not know how you use these values, in particular it doesn't know you will extend it with strcat, so it will not reserve any additional space after the string.
As a result when you concatenate "mondo" to "ciao ", you overwrite some data in memory, possibly some important data...
I'd suggest you to declare local variables for your string, with explicit size:
char cambia[ 20] = "ciao ";
char c[] = "mondo";
This will make a cambia variable long enough to keep 19-character string (plus implicit terminating zero byte '\0', ASCII NUL) and initialize its first 6 bytes with letters 'c', 'i', 'a', 'o', a space ' ' and NUL. Variable c is implicitly sized to 6 (the initializing string length 5 plus 1 for terminating NUL).
Then you can safely concatenate
strcat( cambia, c);
to obtain 11-character string "ciao mondo" and print it out
cout <<"cambia: "<<cambia<<endl;
The problem here is that you are trying to write to a read-only string storage.
These declarations:
char* cambia[] = {"ciao "};
char* c[] = {"mondo"};
declare two arrays, each with a constant string member. The "ciao " and "mondo" are located in read-only memory.
So when you call strcat(*cambia, *c), you are trying to write "mondo" onto the end of "ciao ". Not only does this write to read-only memory, but it also writes outside the memory space given for the string - there is only space for 6 char in the "ciao " string, and you are trying to add another 5 to the end of that.
The solution is to reserve some space for each string. There are various ways to do this. Here's a simple one:
char acambia[20] = "ciao "; // Space for 20 characters.
char* cambia[] = { acambia };
Of coruse, not using the extra level of indirection would make it simpler:
char cambia[20] = "ciao ";
char c[] = "mondo";
strcat(cambia, c);
would achieve the correct result.
First of all you need not headers
#include <string>
#include <cstdlib>
because neither declaration from them is used.
Aslo header
#include <string.h>
should be substituted for
#include <cstring>
In these statements
char* cambia[] = {"ciao "};
char* c[] = {"mondo"};
you defined two arrays each of them having one element of type const char *. The compiler should issue either an error or a warning because these definitions are not correct. It would be correctly to define the arrays the following way
const char* cambia[] = {"ciao "};
const char* c[] = {"mondo"};
These two statements define arrays of const pointers to string literals. It is undefined behaviour if there ia an attempt to change a string literal in a program. Programs are allowed to place string literals in a read-only memory.
You are right saying that the main problem is in statement
strcat( *cambia, *c );
Function strcat appends one character array to the end of another character array. So the second cjaracter array must reserve enough memory that accomodates the appended character array. If you even would define correctly array cambia as
char cambia[] = {"ciao "};
it had no enough memory to store also characters of array c.
So before using strcat you need to reserve enough memory where the concatenated result array would be placed.
You could do this for example the following way
char s[11];
strcpy( s, *cambia );
strcat( s, c );
cout << "s: " << s << endl;
Take into account that instead of character arrays you could use objects of standard class std::string
In this case to append one string to another is made very simply. For example
std::string cambia = "ciao ";
std::string c = "mondo";
cambia += c;
Or
cambia.append( c );
I have a string which actually contains a number and a string, separated by ,, for instance "12,fooBar".
I would like to put it into separated variables, i.e. the number into unsigned int myNum and the string into std::string myStr.
I have the following snipped of code:
size_t pos1=value.find(',');
std::cout << value.substr(0, pos1) << " and "
<< (value.substr(0, pos1)).c_str() << std::endl;
This yields 12 and 1. Anything I missed here? What happend to the 2 in the second part?
Note: I isolated the problem to this snipped of code. I need c_str() to pass it to atoi to get the unsigend int. Here I don't want to print the second part.
Update: I actually get the string from levelDB Get. If I put a test string like I put here, it works.
The posted code produces the same substring: value.substr(0, pos1). Note that std::string::substr() does not modify the object, but returns a new std::string.
Example:
#include <iostream>
#include <string>
int main ()
{
std::string value ="12,fooBar";
unsigned int myNum;
std::string myStr;
const size_t pos1 = value.find(',');
if (std::string::npos != pos1)
{
myNum = atoi(value.substr(0, pos1).c_str());
myStr = value.substr(pos1 + 1);
}
std::cout << myNum << " and "
<< myStr << std::endl;
return 0;
}
Output:
12 and fooBar
EDIT:
If the unsigned int is the only piece required then the following will work:
unsigned int myNum = atoi(value.c_str());
as atoi() will stop at the first non-digit character (excluding optional leading - or +), in this case the ,.
The cleanest C++ style solution to this problem is to use a stringstream.
#include <sstream>
// ...
std::string value = "12,fooBar";
unsigned int myNum;
std::string myStr;
std::stringstream myStream(value);
myStream >> myNum;
myStream.ignore();
myStream >> myStr;
Your second substr should be value.substr(pos1+1,value.length())
One more option is using std::from_chars function from the 17th standard (< charconv > header):
int x;
from_chars(&s[i], &s.back(), x); // starting from character at index i parse
// the nearest interger till the second char pointer
There are different overloads for different types of value x (double etc.).