i have taken all txt from file and place line by line into array of string. I am trying to split this string so that i can save word by word in separate array. Kindly just tell me how shell i convert the array of string into char.
for example
string line[15]; // line[0] has : was there before
// line[1] has : then after
char * pch;
char *c = line.c_str(); // string to char (i am getting error here. Any body know?)
pch = strtok (c," ");
while (pch != NULL)
{
printf ("%s\n",pch);
pch = strtok (NULL, " ");
}
error: C2228: left of '.c_str' must have class/struct/union
string line[15]; is an array of strings. So when you have line.c_str(); line is a pointer to a string and not a string itself. A pointer doesn't have a .c_str() method and that's why the compiler is complaining. (Pointers don't have any methods and hence the compiler tells you that the left hand side of the expression must be a class/struct/union type). To fix this you want to index into the array to get a string. You can do this with something like: line[0].c_str();
Additionally you can't write to anything returned by c_str() as it returns a const pointer. So you'll need to copy the results from c_str first before you then operate on it if you are going to change it in place.
Also it might be worth mentioning that there's c++ ways of doing tokenizing, you might find some examples here Split a string in C++? . The last time I did this I was already using boost so I made use of the boost::tokenizer library.
There are simpler ways to accomplish this in C++. The strtok function is a C function and cannot be used with std::string directly since there is no way to get writable pointer access to the underlying characters in an std::string. You can use iostreams to get individual words separated by spaces from a file directly in C++.
Unfortunately the standard library lacks a simple, flexible, efficient method to split strings on arbitrary characters. It gets more complicated if you want to use iostreams to accomplish splitting on something other than whitespace. Using boost::split or the boost::tokenizer suggestion from shuttle87 is a good option if you need something more flexible (and it may well be more efficient too).
Here's a code example reading words from standard input, you can use pretty much the same code with an ifstream to read from a file or a stringstream to read from a string: http://ideone.com/fPpU4l
#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
using namespace std;
int main() {
vector<string> words;
copy(istream_iterator<string>{cin}, istream_iterator<string>{}, back_inserter(words));
copy(begin(words), end(words), ostream_iterator<string>{cout, ", "});
cout << endl;
}
Related
Many topics have discussed the difference between string and char[]. However, they are not clear to me to understand why we need to bring string in c++? Any insight is welcome, thanks!
char[] is C style. It is not object oriented, it forces you as the programmer to deal with implementation details (such as '\0' terminator) and rewrite standard code for handling strings every time over and over.
char[] is just an array of bytes, which can be used to store a string, but it is not a string in any meaningful way.
std::string is a class that properly represents a string and handles all string operations.
It lets you create objects and keep your code fully OOP (if that is what you want).
More importantly, it takes care of memory management for you.
Consider this simple piece of code:
// extract to string
#include <iostream>
#include <string>
main ()
{
std::string name;
std::cout << "Please, enter your name: ";
std::cin >> name;
std::cout << "Hello, " << name << "!\n";
return 0;
}
How would you write the same thing using char[]?
Assume you can not know in advance how long the name would be!
Same goes for string concatenation and other operations.
With real string represented as std::string you combine two strings with a simple += operator. One line.
If you are using char[] however, you need to do the following:
Calculate the size of the combined string + terminator character.
Allocate memory for the new combined string.
Use strncpy to copy first string to new array.
Use strncat to append second string to first string in new array.
Plus, you need to remember not to use the unsafe strcpy and strcat and to free the memory once you are done with the new string.
std::string saves you all that hassle and the many bugs you can introduce while writing it.
As noted by MSalters in a comment, strings can grow. This is, in my opinion, the strongest reason to have them in C++.
For example, the following code has a bug which may cause it to crash, or worse, to appear to work correctly:
char message[] = "Hello";
strcat(message, "World");
The same idea with std::string behaves correctly:
std::string message{"Hello"};
message += "World";
Additional benefits of std::string:
You can send it to functions by value, while char[] can only be sent by reference; this point looks rather insignificant, but it enables powerful code like std::vector<std::string> (a list of strings which you can add to)
std::string stores its length, so any operation which needs the length is more efficient
std::string works similarly to all other C++ containers (vector, etc) so if you are already familiar with containers, std::string is easy to use
std::string has overloaded comparison operators, so it's easy to use with std::map, std::sort, etc.
String class is no more than an amelioration of the char[] variable.
With strings you can achieve the same goals than the use of a char[] variable, but you won't have to matter about little tricks of char[] like pointers, segmentation faults...
This is a more convenient way to build strings, but you don't really see the "undergrounds" of the language, like how to implement concatenation or length functions...
Here is the documentation of the std::string class in C++ : C++ string documentation
The problem is simple, the code below does not work. it says Process finished with exit code -1073740940 (0xC0000374). Removing ampersand does not change anything.
int main(){
string x;
scanf("%s",&x);
cout << x;
}
scanf() with the %s format specifier reads bytes into a preallocated character array (char[]), to which you pass a pointer.
Your s is not a character array. It is a std::string, a complex object.
A std::string* is not in any way the same as a char*. Your code overwrites the memory of parts of a complex object in unpredictable ways, so you end up with a crash.
Your compiler should have warned about this, since it knows that a char* is not a std::string*, and because compilers are clever and can detect mistakes like this despite the type-unsafe nature of C library functions.
Even if this were valid via some magic compatibility layer, the string is empty.
Use I/O streams instead.
You cannot pass complex objects through the ... operator of printf/scanf. Many compilers print a warning for that.
scanf requires a pointer of type char* pointing to sufficient storage for an argument of %s. std::string is something completely different.
In C++ the iostream operators are intended for text input and output.
cin >> x;
will do the job.
You should not use scanf in C++. There are many pitfalls, you found one of them.
Another pitfall: %s at scanf is almost always undefined behavior unless you you really ensure that the source stream can only contain strings of limited size. In this case a buffer of char buffer[size]; is the right target.
In any other case you should at least restrict the size of the string to scan. E.g. use %20s and of course a matching char buffer, char buffer[21];in this case. Note the size +1.
You should use cin. But if you want to use scanf() for whatever reason and still manipulate your strings with std::string, then you can read the C-string and use it to initialize your C++ string.
#include <iostream>
#include <cstdio>
#include <string>
using std::cout;
using std::string;
int main()
{
char c_str[80];
scanf("%s", c_str);
string str(c_str);
cout << str << "\n";
}
If you want to use strings, use cin (or getline).
string s;
cin>>s; //s is now read
If you want to use scanf, you want to have a char array (and don't use &):
char text[30];
scanf("%s", text); //text is now read
You can use char[] instead of string
include <iostream>
using namespace std;
int main()
{
char tmp[101];
scanf("%100s", tmp);
cout << tmp;
}
I was doing a relatively simple string problem in UVa's online judge to practice with strings since I've been having a hard time with them in C. The problem basically asks to check if a string B contains another string A if you remove the 'clutter' and concatenate the remaining characters, for example if "ABC" is contained in "AjdhfmajBsjhfhC" which in this case is true.
So, my question is how can I efficiently allocate memory for a string which I don't know its length? What I did was to make a string really big char Mstring[100000], read from input and then use strlen(Mstring) to copy the string the a properly sized char array. Something like :
char Mstring[100000];
scanf("%s",Mstring);
int length = strlen(Mstring);
char input[length+1]={0};
for(int i = 0; i<length;i++){
input[i]=Mstring[i];
}
Is there a better/standard way to do this in C? I know that C does not has a great support for strings, if there is not a better way to do it in C maybe in C++?
If you have the option of using C++ (as you mentioned), that is going to make your life a lot easier. You can then use a STL string (std::string) which manages dynamically sized strings for you. You can also drop the old scanf() beast and use std::cin.
Example:
#include <iostream>
#include <string>
void main()
{
std::string sInput;
std::getline(std::cin, sInput);
// alternatively, you could execute this line instead:
// std::cin >> sInput;
// but that will tokenize input based on whitespace, so you
// will only get one word at a time rather than an entire line
}
Describing how to manage strings that can grow dynamically in C will take considerably more explanation and care, and it sounds like you really don't need that. If so, however, here is a starting point: http://www.strchr.com/dynamic_arrays.
I'm trying create simple application in C++. This application has to read from file and displays data. I've written function:
std::vector <AndroidApplication> AndroidApplication::getAllApp(){
std::vector<AndroidApplication> allApp;
std::fstream f;
f.open("freeApps.txt");
std::string line;
if(f.is_open()){
while(getline(f, line)) {
std::string myLine = "";
char * line2 = line.c_str();
myLine = strtok(line2,"\t");
AndroidApplication * tmpApp = new AndroidApplication(myLine[1], myLine[2], myLine[4]);
tmpApp->Developer = myLine[0];
tmpApp->Pop = myLine[3];
tmpApp->Type = myLine[5];
allApp->pushBack(tmpApp);
}
}
return allApp;
}
It throws me an error in line:
myLine = strtok(line2,"\t");
An error:
cannot convert from 'const char *' to 'char *'
Could you tell me how can I deal with it?
Don't use strtok. std::string has its own functions for string-scanning, e.g., find.
To use strtok, you'll need a writeable copy of the string. c_str() returns a read-only pointer.
You can't just "convert it" and forget about it. The pointer you get from .c_str() is to a read-only buffer. You need to copy it into a new buffer to work with: ideally, by avoiding using antiquated functions like strtok in the first place.
(I'm not quite sure what you're doing with that tokenisation, actually; you're just indexing into characters in the once-tokenised string, not indexing tokens.)
You're also confusing dynamic and automatic storage.
std::vector<AndroidApplication> AndroidApplication::getAllApp()
{
std::vector<AndroidApplication> allApp;
// Your use of fstreams can be simplified
std::fstream f("freeApps.txt");
if (!f.is_open())
return allApp;
std::string line;
while (getline(f, line)) {
// This is how you tokenise a string in C++
std::istringstream split(line);
std::vector<std::string> tokens;
for (std::string each;
std::getline(split, each, '\t');
tokens.push_back(each));
// No need for dynamic allocation here,
// and I'm assuming you wanted tokens ("words"), not characters.
AndroidApplication tmpApp(tokens[1], tokens[2], tokens[4]);
tmpApp.Developer = tokens[0];
tmpApp.Pop = tokens[3];
tmpApp.Type = tokens[5];
// The vector contains objects, not pointers
allApp.push_back(tmpApp);
}
return allApp;
}
I suspect the error is actually on the previous line,
char * line2 = line.c_str();
This is because c_str() gives a read-only pointer to the string contents. There is no standard way to get a modifiable C-style string from a C++ string.
The easiest option to read space-separated words from a string (assuming that's what you're tying to do) is to use a string stream:
std::vector<std::string> words;
std::istringstream stream(line);
std::copy(std::istream_iterator<std::string>(stream),
std::istream_iterator<std::string>(),
back_inserter(words));
If you really want to use strtok, then you'll need a writable copy of the string, with a C-style terminator; one way to do this is to copy it into a vector:
std::vector<char> writable(line.c_str(), line.c_str() + line.length() + 1);
std::vector<char *> words;
while (char * word = strtok(words.empty() ? &writable[0] : NULL, " ")) {
words.push_back(word);
}
Bear in mind that strtok is quite difficult to use correctly; you need to call it once for each token, not once to create an array of tokens, and make sure nothing else (such as another thread) calls it until you've finished with the string. I'm not sure that my code is entirely correct; I haven't tried to use this particular form of evil in a long time.
Since you asked for it:
Theoretically you could use const_cast<char*>(line.c_str()) to get a char*. However giving the result of this to strtok (which modifies its parameter) is IIRC not valid c++ (you may cast away constness, but you may not modify a const object). So it might work for your specific platform/compiler or not (and even if it works it might break anytime).
The other way is to create a copy, which is filled with the contents of the string (and modifyable):
std::vector<char> tmp_str(line.begin(), line.end());
myLine = strtok(&tmp_str[0],"\t");
Of course as the other answers tell you in great detail, you really should avoid using functions like strtok in c++ in favour of functionality working directly on std::string (at least unless you have a firm grasp on c++, high performance requirements and know that using the c-api function is faster in your specific case (through profiling)).
I have a task to implement "void makeAmbigram(char*)" that will print on screen ambigram of latin string or return something like 'ambigram not possible'. Guess it's just about checking if string contains only of SNOXZHI and printing string backwards. Or am I wrong ?
I'm a complete noob when dealing with cpp so that's what I've created :
#include <iostream>
using namespace std;
char[]words;
char[]reversed;
char[] ret_str(char* s)
{
if(*s != '\0')
ret_str(s+1);
return s;
}
void makeAmbigram(char* c)
{
/* finding chars XIHNOZS and printing ambigram */
}
int main()
{
cin>>words;
reversed = ret_str(words);
makeAmbigram(reversed);
return 0;
}
I can reverse string but how to check if my reversed string contains only needed chars ?
I've found some function but it's hard or even imposible to implement it for greater amount of chars : www.java2s.com/Code/C/String/Findcharacterinstringhowtousestrchr.htm
You need to allocate space in your arrays or use std::vector. The arrays word and reversed are just pointers and no space is allocated. The C++ language does not support dynamic arrays; however, the STL provides std::vector which dynamically allocates space as required.
Change:
char[]words;
char[]reversed;
To:
#define MAX_LETTERS 64
char words[MAX_LETTERS + 1]; // + 1 for terminating nul character ('\0')
char reversed[MAX_LETTERS + 1];
Or:
#include <string>
std::string words;
std::string reversed;
Or:
#include <vector>
std::vector<char> words;
std::vector<char> reversed;
As far as the ambigram rules go, you need to talk to your instructor. Also, if this is homework, add a tag indicating so.
Hint: The std::string data type has some reverse iterators which may be of use to you.
std::string has an entire family of member functions along the lines of find_first_of. You can pass in a string containing all the letters your ambigram test requires, and they'll find whether any of those letters are present in the source string.
The complete list of string functions is available here.
As for the definition of ambigrams, given the wiki page you've included in the question...you need to check if a letter is legible if viewed upside down, for eg. u/n, w/m, d/p, q/b and so on. There are of course more complex rules was well, for eg. 'ui' can resemble 'm' if viewed upside down.
However, if you're only required to check if your string contains only SNOXZHI, you can look into a regular expression (regex) for the same, and compare input string character-wise to your regex.