Store texts in char array then compare the contents of array - c++

I'm trying to figure out how I can store to the char array the user input. For example user input: hello, then char array[0] = "hello"; then when he input again "hello" it will not insert to the char array since it's already on the array.
Input: hello
Output: char array[] = {"hello"};
Input: world
Output:
char array[] = {"hello","world"};
Input: hello
checks: array[i] == "hello"
Output: don't insert to char array
I need a sample program please

You might go with more C++-way using standard containers:
#include <iostream>
#include <set>
#include <string>
int main()
{
std::string buffer;
std::set<std::string> data;
std::cin >> buffer;
while (buffer != "quit")
{
if (data.find(buffer) == data.end())
{
auto res = data.insert(buffer);
if (! res.second)
std::cerr << "ERROR:: Could not insert string '" << buffer << "'." << std::endl;
}
else
std::cout << "WARNING:: String '" << buffer << "' already found." << std::endl;
std::cin >> buffer;
}
return 0;
}
Otherwise, you should do it in C-style of thinking:
store string into buffer
allocate new char array and put it into a list of arrays
traverse through the list to find if a string is already there using strcmp() function
don't forget to clean up any dynamically allocated memory at the end of your program - this would cause memory leaks

The sample code using c++ would be like this, because this is C++ not only C we can use the features C++ provide as std::string, std::vector and many other useful algorithms like std::find implemented in STL. Hope this is what you want.
#include <string> // for std::string
#include <vector> // for std::vector
#include <iostream> // for std::cout, std::cin, and std::endl;
#include <algorithm> // for std::find
int main() {
std::vector<std::string> array;
std::string line;
std::cout << "Input : ";
while(std::getline(std::cin, line)) {
if (std::find(array.begin(), array.end(), line) == array.end()) { // If we can't find the string in the array
array.push_back(line);
std::cout << "{ ";
for (std::string str: array) {
std::cout << str << ", ";
}
std::cout << "}" << std::endl;
} else {
std::cout << "Output : Don't Insert" << std::endl;
}
}
}

Related

To read FILE and store data in map<string, vector<string>> c++98

I have file bird.lst, I need to read file contents and store data in map<string, vector>, here the idea is bird name is store in string and those having some attribute values that needs to be stored in vector. please help
eventually map<string, vector> looks like below,
ex:
parrot.sh ----> eat yes
fly yes
file contents below of bird.lst
parrot.sh
eat yes
fly yes
pigeon.sh
eat yes
fly yes
duck.sh
eat yes
fly no
flammingo.sh
eat yes
fly yes
eagle.sh
eat yes
flay yes
You need a nested loop.
The outside one reads the name of the bird (the key of the map)
The inside one reads the attributes of the bird (the values of the vector)
Here is what I came up with:
#include <fstream>
#include <iostream>
#include <map>
#include <string>
#include <vector>
typedef std::vector<std::string> attribute_vector;
typedef std::map<std::string,attribute_vector> bird_map;
int main()
{
std::ifstream file("bird.lst");
bird_map birds;
std::string key;
while(std::getline(file,key))
{
attribute_vector attributes;
std::string value;
while(std::getline(file,value))
{
// in case it has windows encoding with end-of-line = \r\n
if (!value.empty() &&
value[value.size()-1] == '\r')
{
value.erase(value.size() - 1);
}
// if we found the empty string
if(value.empty())
{
break;
}
// save the value into the vector
attributes.push_back(value);
}
// save the bird into the map
birds[key] = attributes;
}
// now print the data we collected
for(bird_map::iterator bird = birds.begin();
bird != birds.end();
bird++)
{
std::cout << bird->first << "\n";
for(attribute_vector::iterator attribute = bird->second.begin();
attribute != bird->second.end();
attribute++)
{
std::cout << " " << *attribute << "\n";
}
std::cout << "\n";
}
return 0;
}
Try it at https://onlinegdb.com/1TBobUxE2 (it says C++17 as the compiler type but in the config under "Extra Compiler Flags" I am passing -std=c++98)
If you want to split the attribute from the yes/no value then:
#include <fstream>
#include <iostream>
#include <map>
#include <sstream>
#include <string>
#include <vector>
#include <utility>
typedef std::pair<std::string,std::string> attribute_pair;
typedef std::vector<attribute_pair> attribute_vector;
typedef std::map<std::string,attribute_vector> bird_map;
int main()
{
std::ifstream file("bird.lst");
bird_map birds;
std::string key;
while(std::getline(file,key))
{
attribute_vector attributes;
std::string value;
while(std::getline(file,value))
{
// in case it has windows encoding with end-of-line = \r\n
if (!value.empty() &&
value[value.size()-1] == '\r')
{
value.erase(value.size() - 1);
}
// if we found the empty string
if(value.empty())
{
break;
}
// now split the value into an attribute and a flag
attribute_pair attribute;
std::istringstream ss(value);
ss >> attribute.first >> attribute.second;
// save the value into the vector
attributes.push_back(attribute);
}
// save the bird into the map
birds[key] = attributes;
}
// now print the data we collected
for(bird_map::iterator bird = birds.begin();
bird != birds.end();
bird++)
{
std::cout << bird->first << "\n";
for(attribute_vector::iterator attribute = bird->second.begin();
attribute != bird->second.end();
attribute++)
{
std::cout << " " << attribute->first
<< " = " << attribute->second
<< "\n";
}
std::cout << "\n";
}
return 0;
}
Try it at https://onlinegdb.com/Htlh4eHu9 (it says C++17 as the compiler type but in the config under "Extra Compiler Flags" I am passing -std=c++98)
(Issue) The problem is not very specific.
So I'll try to make a very general solution.
Define a function:
bool is_file(string s) {
return (s.substr((int)s.size() - 3, 3) == ".sh");
}
Telling you if a string is a bird file.
Because of (Issue), I'll asume each attribute of the bird is of the form: (attribute, yes/no), wich we'll transform to (attribute, 1/0).
Now, to read the file, you have several options. I'll name two of them.
Pass the file from console, i.e, if you .exe is called birds.exe, just do birds.exe<bird.lst. And just read with std::cin.
Use freopen("bird.lst", "r", stdin); and just read with std::cin.
Then, the main function should look like this:
int main () {
freopen("bird.lst", "r", stdin); // if you didnt read from console.
map<string, vector<pair<string, bool>>> birds;
string current_bird;
while (cin >> s) {
string s;
cin >> s;
if (is_file(s)) {
current_bird = s;
continue;
}
bool verdict;
cin >> verdict;
bird[current_bird].push_back(make_pair(s, verdict));
}
}
And to print the data:
for (auto it = birds.begin(); it != birds.end(); it++) {
cout << "Bird File: " << it.first << "\n";
cout << "Attributes:\n";
for (auto x : it.second) cout << x.first << " " << (x.second ? "YES" : "NO") << "\n";
}

Vector of strings works correctly before sorting, but afterwards it can't do anything

I was working on a problem which required me to sort vector of strings at certain point. It caused me a lot of problems so I decided to extract the problematic part and I can't figure out what seems to be the problem.
#include<iostream>
#include<vector>
#include<algorithm>
#include<string>
using namespace std;
bool myComp(string a, string b){
return a<b;
}
int main(){
vector<string> students(50000);
int i = 0;
while(true){
string input;
getline(cin, students[i]);
if(!students[i].empty()){
i++;
}
else{
break;
}
}
cout << students[2] << endl << students[1] << endl;
sort(students.begin(), students.end());
cout << students[2] << endl << students[1];
return 0;
}
At first I thought that input was wrong (problem specifically requests to read until empty line), but it turned out that program works correctly up to moment of sorting. I would be very grateful if anyone was to clear this out for me I am banging my head for more than an hour.
The obvious issue with your code is that you have a vector of 50000 strings. You then try an sort that vector of 50000 strings. It seems obvious that you really want the size of the vector to equal the number of strings input. The easy way to do that is to grow the vector as you input strings. Use the push_back method for that.
Here's some code
vector<string> students; // initial size of vector is zero
int i = 0;
while(true){
string input;
getline(cin, input); // read into the input variable
if (input.empty()) // break if input is empty
break;
students.push_back(input); // add the input to the vector
}
Now with the vector sized correctly you should find sorting it to be no problem
cout << students[2] << endl << students[1] << endl;
sort(students.begin(), students.end());
cout << students[2] << endl << students[1];
The problem is using incorrect arguments in the call of std::sort.
sort(students.begin(), students.end());
The vector students contains 50000 elements
vector<string> students(50000);
It seems you mean
#include <iterator>
//...
sort(students.begin(), std::next( students.begin(), i ));
or
sort(students.begin(), std::next( students.begin(), i ), myComp );
where myComp should be defined at least like
bool myComp( const string &a, const string &b){
return a<b;
}
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>
int main()
{
std::vector<std::string> students;
students.reserve(50000); // want to avoid `students` reallocation for first
// 50'000 entries but size is still zero (`0`)
std::string line;
// read until end-of-input or empty line
while(std::getline(std::cin, line) && !line.empty())
students.push_back(line); // no reallocation for first 50'000 entries!
if(students.size() < 3)
{
std::cerr << "Need at least three students for example\n";
return EXIT_FAILURE;
}
std::cout << students[2] << '\n' << students[1] << '\n';
std::partial_sort( // Only pick out three "smallest" strings for example
students.begin(), // no need to sort more than necessary with 50'000 :-)
std::next(students.begin(), 3),
students.end());
std::cout << students[2] << '\n' << students[1] << std::endl;
return EXIT_SUCCESS;
}
You have written a comparator function myComp() but you haven't used it. I'd suggest using it as the third parameter for sort() and see if things get better. i.e.;
#include<iostream>
#include<vector>
#include<algorithm>
#include<string>
using namespace std;
bool myComp(string a, string b){
return a<b;
}
int main(){
vector<string> students(50000);
int i = 0;
while(true){
string input;
getline(cin, students[i]);
if(!students[i].empty()){
i++;
}
else{
break;
}
}
cout << students[2] << endl << students[1] << endl;
sort(students.begin(), students.end(), myComp);
cout << students[2] << endl << students[1];
return 0;
}

Passing C-Style string char * to function argument

I want to change the characters in a string passed by user, converted into a C-style string and passed as an argument to a function with a char * argument:
#include <string>
#include <cstring>
#include <iostream>
#include <stdlib.h>
void functoupper(char *myString)
{
int i=0;
char z;
do {
z= myString[i];
myString[i]=toupper(z);
++i;
} while(myString[i]!=0);
}
int main() {
std::string name;
std::cout << "Please, enter your full name in small caps: ";
std::getline (std::cin,name);
const char *myString = name.c_str();
std::cout << "Hello, " << functoupper(myString) << "!\n";
return 0;
}
I get error error: invalid conversion from 'const char*' to 'char*' [-fpermissive] when calling function functoupper(myString) in main().
The std::string::c_str() method returns a pointer to const char data, but your function expects a pointer to non-const char data. That is why you are getting an error.
You could use const_cast to cast away the const (but that is not really advisable):
char *myString = const_cast<char*>(name.c_str());
functoupper(myString);
std::cout << "Hello, " << name << "!\n";
You could use the non-const std::string::operator[] to access the string's underlying character data (just be careful because prior to C++11, characters were not required to be stored contiguously in memory, but most std::string implementations did):
functoupper(&name[0]);
std::cout << "Hello, " << name << "!\n";
In C++17 and later, you can use the non-const std::string::data() method instead:
functoupper(name.data());
std::cout << "Hello, " << name << "!\n";
That being said, heed this warning when using toupper():
Like all other functions from <cctype>, the behavior of std::toupper is undefined if the argument's value is neither representable as unsigned char nor equal to EOF. To use these functions safely with plain chars (or signed chars), the argument should first be converted to unsigned char ... Similarly, they should not be directly used with standard algorithms when the iterator's value type is char or signed char. Instead, convert the value to unsigned char first
With that said, try something more like this:
#include <string>
#include <iostream>
#include <cctype>
void functoupper(char *myString)
{
for (int i = 0; myString[i] != '\0'; ++i) {
unsigned char z = static_cast<unsigned char>(myString[i]);
myString[i] = static_cast<char>(std::toupper(z));
}
}
int main() {
std::string name;
std::cout << "Please, enter your full name in small caps: ";
std::getline(std::cin, name);
functoupper(&name[0]); // or name.data()
std::cout << "Hello, " << name << "!\n";
return 0;
}
That being said, you should just pass the entire std::string as-is into your function instead, and then you can manipulate it as needed, for instance with the std::transform() algorithm:
#include <string>
#include <iostream>
#include <algorithm>
#include <cctype>
void functoupper(std::string &myString)
{
std::transform(myString.begin(), myString.end(), myString.begin(),
[](unsigned char ch){ return std::toupper(ch); }
);
}
int main() {
std::string name;
std::cout << "Please, enter your full name in small caps: ";
std::getline(std::cin, name);
functoupper(name);
std::cout << "Hello, " << name << "!\n";
return 0;
}
Alternatively:
#include <string>
#include <iostream>
#include <algorithm>
#include <cctype>
std::string functoupper(std::string myString)
{
std::transform(myString.begin(), myString.end(), myString.begin(),
[](unsigned char ch){ return std::toupper(ch); }
);
return myString;
}
int main() {
std::string name;
std::cout << "Please, enter your full name in small caps: ";
std::getline(std::cin, name);
std::cout << "Hello, " << functoupper(name) << "!\n";
return 0;
}
As #Someprogrammerdude and #RemyLebeau comment, why not simply:
std::transform(std::begin(name), std::end(name), std::begin(name),
[](const unsigned char c)
{
return std::toupper(c);
});
But if you must do it via a char*, then you'll need to copy the data over first, something like:
char myString* = new char[name.size() + 1];
strcpy(myString, name.c_str());
EDIT: Thanks to the helpful comments by #RemyLebeau
Better still avoid all the memory management issues with the above by simply coping your std::string into a std::vector:
std::vector<char> myVec(std::begin(name), std::end(name));
myVec.push_back(`\0`);
and then call your char* function with:
functoupper(myVec.data());

Store input values into array while reading them in, c++

I am pretty new to c++. I am trying to read a file in line by line and store the input into several arrays.
Because I don't know the size of input file, I have this to get the number of lines in the file
while (std::getline(inputFile, line)){
++numOfLines;
std::cout << line << std::endl;
}
Now I want to use the numOfLines as the size of arrays, but i cannot get it run by having this
std::string *firstName= new std::string[numOfLines];
std::string *lastName= new std::string[numOfLines];
for (int i = 0; i < numOfLines; ++i)
{
line >> firstName[i];
}
I guess it is because it has reached the end of the file after the while loop. But I do not know how to solve this problem. Is there a way to scan the input file in and store the value into array at the same time?
If you use std::vector you don't need to know ahead the lines count. You can use vector method push_back to insert new elements into it. Try use something like this:
#include <fstream>
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main()
{
std::vector<std::string> first_names;
std::string line;
ifstream input_file;
while (std::getline(input_file, line)){
first_names.push_back(line);
}
for (size_t i = 0; i < first_names.size(); i++) {
std::cout << first_names[i] << std::endl;
}
return 0;
}
I don't know if you have ever taken a course related to Data Structures & Algorithms,
in which you will learn to use Containers (such as:
vector,
deque,
list, etc.) instead of Primitive Data Structures.
Please notice that although the follow example chooses vector as its container, it could vary according to different contexts. Say you are handling gigantic mount of data, you might want to use list instead`1,2,3.
#include <fstream>
#include <iostream>
#include <vector>
#include <string>
// alias long type
// #see: https://en.cppreference.com/w/cpp/language/type_alias
using NameVector = std::vector<std::string>;
int handleLine(std::string line, NameVector &firstNames)
{
// TODO implement your line handler here
firstNames.push_back(line);
return 0;
}
int handleFile(std::ifstream inputFile, NameVector &firstNames)
{
std::string line;
for (int lineNum = 1;
// invoke `good` to check if there is any error
inputFile.good()
&&
std::getline(inputFile, line);
lineNum++)
{
std::cout << "Current line number : (" << lineNum << ")" << std::endl;
std::cout << "Current line content: (" << line << ")" << std::endl;
handleLine(line, &firstNames);
}
return 0;
}
int main()
{
std::string path; // = R"(HERE GOES YOUR FILE PATH)";
// Using **Raw string**
std::ifstream inputFile { path }; // Initialize `inputFile`
NameVector firstNames;
handleFile(inputFile, firstNames);
for (auto firstName : firstNames)
{
std::cout << firstName << std::endl;
}
return 0;
}

Read and print a csv file with more than 2 column in c++ using multimap

I'm a beginner in c++ and required to write a c++ program to read and print a csv file like this.
DateTime,value1,value2
12/07/16 13:00,3.60,50000
14/07/16 20:00,4.55,3000
May I know how can I proceed with the programming?
I manage to get the date only via a simple multimap code.
I spent some time to make almost (read notice at the end) exact solution for you.
I assume that your program is a console application that receives the original csv-file name as a command line argument.
So see the following code and make required changes if you like:
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <map>
#include <string>
std::vector<std::string> getLineFromCSV(std::istream& str, std::map<int, int>& widthMap)
{
std::vector<std::string> result;
std::string line;
std::getline(str, line);
std::stringstream lineStream(line);
std::string cell;
int cellCnt = 0;
while (std::getline(lineStream, cell, ','))
{
result.push_back(cell);
int width = cell.length();
if (width > widthMap[cellCnt])
widthMap[cellCnt] = width;
cellCnt++;
}
return result;
}
int main(int argc, char * argv[])
{
std::vector<std::vector<std::string>> result; // table with data
std::map<int, int> columnWidths; // map to store maximum length (value) of a string in the column (key)
std::ifstream inpfile;
// check file name in the argv[1]
if (argc > 1)
{
inpfile.open(argv[1]);
if (!inpfile.is_open())
{
std::cout << "File " << argv[1] << " cannot be read!" << std::endl;
return 1;
}
}
else
{
std::cout << "Run progran as: " << argv[0] << " input_file.csv" << std::endl;
return 2;
}
// read from file stream line by line
while (inpfile.good())
{
result.push_back(getLineFromCSV(inpfile, columnWidths));
}
// close the file
inpfile.close();
// output the results
std::cout << "Content of the file:" << std::endl;
for (std::vector<std::vector<std::string>>::iterator i = result.begin(); i != result.end(); i++)
{
int rawLen = i->size();
for (int j = 0; j < rawLen; j++)
{
std::cout.width(columnWidths[j]);
std::cout << (*i)[j] << " | ";
}
std::cout << std::endl;
}
return 0;
}
NOTE: Your task is just to replace a vector of vectors (type std::vector<std::vector<std::string>> that are used for result) to a multimap (I hope you understand what should be a key in your solution)
Of course, there are lots of possible solutions for that task (if you open this question and look through the answers you will understand this).
First of all, I propose to consider the following example and to try make your task in the simplest way:
#include <iostream>
#include <sstream>
#include <vector>
#include <string>
using namespace std;
int main()
{
string str = "12/07/16 13:00,3.60,50000";
stringstream ss(str);
vector<string> singleRow;
char ch;
string s = "";
while (ss >> ch)
{
s += ch;
if (ss.peek() == ',' || ss.peek() == EOF )
{
ss.ignore();
singleRow.push_back(s);
s.clear();
}
}
for (vector<string>::iterator i = singleRow.begin(); i != singleRow.end(); i++)
cout << *i << endl;
return 0;
}
I think it can be useful for you.