C++ Error C2451 conditional String is illegal - c++

i'm fairly new to C++.
I want to write a Program/Function that checks a string input (from console or other source, not important here) if is already in an array. If it's not then it should be written into array. Otherwise do nothing.
My Problem is the for loop and if the if condition. What am I missing?
#include <iostream>
#include <string>
#include <fstream>
#include <stdio.h>
using namespace std;
typedef struct {
string id[10];
string foo1[10];
string type[10];
string func[10];
}Device;
int main() {
Device fooDevice;
string mystring;
int i = 0;
mystring = "foo";
ofstream temp;
temp.open("temp.txt", ios::out | ios::app);
for (fooDevice.id[i]; fooDevice.id[9]; i++) {
if (fooDevice.id[i] != mystring) {
fooDevice.id[i] = mystring;
temp << mystring << endl;
} else {
//do nothing
}
}
return 0;
}

The problem is the structure of your for loop. I'm not sure what you think your condition means, but here's how it should look:
for (std::size_t i = 0; i < 10; ++i) {
This increments the index value i from 0 to 9 (inclusive). You can then check the value of fooDevice[i].
At the moment, it seems you are trying to overwrite every element of the array with the new string. I'm not sure how you know how full the array is at any given time. Let's suppose you stop when you get to the first empty string:
for (std::size_t i = 0; i < 10; ++i) {
if (myString == fooDevice.id[i]) {
// already there, stop looping
break;
}
else if (fooDevice.id[i].empty()) {
// none of the currently set elements matches
fooDevice.id[i] = myString;
temp << myString << '\n';
break;
}
}
You could also replace this with a range-based-for:
for (auto& deviceId: fooDevice.id) {
if (myString == deviceId) {
// already there, stop looping
break;
}
else if (deviceId.empty()) {
// none of the currently set elements matches
deviceId = myString;
temp << myString << '\n';
break;
}
}
Better yet, use a std::vector with std::find from the <algorithm> header. (Warning: untested code):
struct Device {
// ...
std::vector<std::string> id;
// ...
};
// ...
auto foundId = std::find(fooDevice.id.begin(), fooDevice.id.end(), myString);
if (fooDevice.id.end() == foundId) {
// not already there
fooDevice.id.push_back(myString);
temp << myString << '\n';
}
It seems you are a bit confused about the difference between C and C++ as well:
The C++ version of <stdio.h> is <cstdio>, but you don't need it here at all (and you usually don't in a C++ program).
You don't need to typedef the name of a struct in C++, just do struct Device { ... };
And regarding C++ style, please reconsider your use of what are often considered bad practices: using namespace std; and endl.

for (fooDevice.id[i]; fooDevice.id[9]; i++) seems no scence. I think you want:
for(; i<9; ++i)

You can't use a string value as a loop condition. Only expressions that evaluate to booleans.
Also, you are also not initializing the device arrays before searching them.
Try something more like this:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
struct Device {
string id[10];
string foo1[10];
string type[10];
string func[10];
};
int main() {
Device fooDevice;
string mystring;
// fill fooDevice as needed...
mystring = "foo";
ofstream temp;
temp.open("temp.txt", ios::out | ios::app);
bool found = false;
int idx_available = -1;
for (int i = 0; i < 10; ++i) {
if (fooDevice.id[i] == mystring) {
//do nothing
found = true;
break;
}
if ((idx_available == -1) && fooDevice.id[i].empty())
idx_available = i;
}
if ((!found) && (idx_available != -1)) {
fooDevice.id[idx_available] = mystring;
temp << mystring << endl;
}
return 0;
}
Which would be better handled with some rewriting:
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <algorithm>
struct Device {
std::string id;
std::string foo1;
std::string type;
std::string func;
};
struct isDeviceId {
const std::string &m_id;
isDeviceId(const std::string &id) : m_id(id) {
}
bool operator()(const Device &device) {
return (device.id == m_id);
}
};
int main() {
std::vector<Device> devices;
std::string mystring;
// fill devices as needed...
mystring = "foo";
if (std::find_if(devices.begin(), devices.end(), isDeviceId(mystring)) == devices.end()) {
Device device;
device.id = mystring;
devices.push_back(device);
std::ofstream temp;
temp.open("temp.txt", std::ios::out | std::ios::app);
temp << mystring << std::endl;
}
return 0;
}
Alternatively, in C++11 and later:
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <algorithm>
struct Device {
std::string id;
std::string foo1;
std::string type;
std::string func;
};
int main() {
std::vector<Device> devices;
std::string mystring;
// fill devices as needed...
mystring = "foo";
if (std::find_if(devices.begin(), devices.end(),
[mystring&](const Device &device) { return (device.id == mystring); }
) == devices.end()) {
devices.emplace_back();
devices.back().id = mystring;
// or, in C++17:
// devices.emplace_back().id = mystring;
std::ofstream temp;
temp.open("temp.txt", std::ios::out | std::ios::app);
temp << mystring << std::endl;
}
return 0;
}

Related

How to read file into class in C++?

I am reading File that contains
Boss, level, Specials,
"FireMen", 3, "Flame,Thrower", Fire,Breath
"Medusa", 6, "Snake,Poison"
"Hype", 10, "One,punch,Knock", Fly,Kick, "Dragon,Breath"
I am trying to read it into class with objects boss, level and specials
I am having problem reading from file since I split each by words by comma but it read specials like Flame,Thrower as separate due to comma in between them. How can I combine specials rather then splitting by commas so that it read Flame Thrower rather then Flame and thrower separately.
Also some specials are in quotation others are not.
I have been stuck at reading this rather complicated file. If anyone has time to read through my code and fix 10s of errors that I am getting would greatly be appreciated, Thank You
(What I did doesn't make much sense since this is my one month into C++ so still newbie and progressing)
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <iomanip>
#include "Boss.h"
using namespace std;
vector <Boss*> Info;
Boss* parseLine(string str)
{
vector<string> store;
string smt = " ";
Boss* values = nullptr;
if (smt != "")
{
(store.push_back(smt));
}
for (int i = 0; i < (int)str.size(); i++)
{
char ch = str[i];
if (ch != ',')
{
smt = smt + ch;
}
else
{
store.push_back(smt);
smt = "";
}
}
values = new Boss(store[0], stoi(store[1]), store[2]);
Name = store[0];
Level = store[1];
Specials = store[2];
return values;
}
bool readFile()
{
std::ifstream myFile("Bosses.txt");
if (!myFile.is_open())
{
cout << "fAILED" << "\n";
return false;
}
string str;
int i = 0;
while (std::getline(myFile, str))
{
cout << str << endl;
if (str[0] != '/')
{
Boss* Boss = parseLine(str);
result.push_back(Boss);
}
}
return true;
}
int main()
{
std::cout << "Read file\n;";
bool data = readFile();
for (Boss* t : result)
{
delete t;
}
And Class
#include <string>
#include <vector>
class Boss {
std::string Name;
int Level;
std::vector<std::string> Specials;
Boss(std::string Name, int Level, std::vector<std::string> Specials);
~Boss();
Boss(Boss& b);
void setName(std::string Name);
void setLevel(int Level);
};
Boss::Boss(std::string Name, int Level, std::vector<std::string> Specials)
{
this->Name= Name;
this->Level = Level;
this->Specials = Specials;
}
Boss::~Boss() {}
Boss::Boss(Boss& b)
{
Name = b.Name;
Level = b.Level;
Specials = b.Specials;
}
void Boss::setName(std::string Name) {
this->Name = Name;
}
void Boss::setLevel(int Level)
{
this->Level = Level;
}
This code reads your file and stores the data in the std::vector Info using stringstreams and other things to parse.
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <iomanip>
#include <sstream>
using namespace std;
class Boss {
std::string Name;
int Level;
std::vector<std::string> Specials;
public:
Boss(std::string n, int l, std::vector<std::string> s)
{
this->Name = n;
this->Level = l;
this->Specials = s;
};
~Boss() {};
Boss(const Boss& b) {
this->Name = b.Name;
this->Level = b.Level;
this->Specials = b.Specials;
};
Boss() {};
Boss operator= (Boss b) {
this->Name = b.Name;
this->Level = b.Level;
this->Specials = b.Specials;
return b;
}
void setName(std::string n) { Name = n; };
void setLevel(int l) { Level = l; };
void setSpecials(std::vector<std::string> s) {Specials = s;}
std::string getName() const { return Name; }
int getLevel() const { return Level; }
std::vector<std::string> getSpecials() const { return Specials; }
};
vector <Boss> Info;
Boss parseLine(string str)
{
vector<string> store;
string smt;
stringstream evaluator;
Boss value;
evaluator << str; //put our string into evaluator
{
char double_quote_remover;
evaluator >> double_quote_remover; //remove the first double quote
getline(evaluator, smt, '"'); //get the name until the next double quote
char comma_remover;
evaluator >> comma_remover; //remove the comma
}
value.setName(smt); //put smt into the Boss's name
{
int Level;
evaluator >> Level; //get an int from our string
value.setLevel(Level); //put our int into our Boss
}
char curr;
while (evaluator >> curr && curr != ','); //get the comma after the int
smt = ""; //reset
curr = ' '; //reset
while (evaluator >> curr) { //while we read chars into curr
if (isalpha(curr)) { evaluator.putback(curr); curr = ','; } //if the char is a letter, put it back
if (curr == '\"') getline(evaluator,smt,'\"'); //if the char is a double quote, read until we reach another
else if (curr == ',') getline(evaluator,smt,','); //if the char is a comma, read until we get another
if (smt != "") //if the string is not null, put it in store
store.push_back(smt);
smt = ""; //reset
}
value.setSpecials(store); //put store into our Boss
return value; //return our boss
}
bool readFile()
{
std::ifstream myFile("Bosses.txt");
if (!myFile.is_open())
{
cout << "FAILED" << "\n";
return false;
}
string str;
getline(myFile, str); //for the first line, which we don't need
int i = 0;
while (std::getline(myFile, str))
{
Boss Boss = parseLine(str);
Info.push_back(Boss);
}
return true;
}
int main()
{
bool data = readFile();
}
This should work. I have tested it thouroughly. Inform me of any errors.
Note: There was no need for pointers that were in your original code.

converting strings to integers by using "stringstream "

I am trying to convert strings of data to integers, (to use it for some calculations ) by using stringstream , but it fails when there is a space.
#include <iostream>
#include <vector>
#include <sstream>
using namespace std;
int main() {
string line;
vector <string>data;
for (int i = 0; i < 10;i++) {
getline(cin,line);
data.push_back(line);
}
///converting digits to int
vector<int> values;
int n;
char ch=',';
for (int i = 0; i < data.size();i++) {
stringstream stream(data[i]);
while( stream >>n ) {
if(stream >> ch) {
values.push_back(n);
}
else {
values.push_back(n);
}
cout<<n<<" ";
}
cout<<endl;
}
return 0;
}
input : 1,182,08 51 15 --> output : 1 182 8 1 5
there are some digits lost after spaces.
so, what can I do to avoid it?
Complete working code based on seccpur's answer. Visual Studio 2017 Community:
#include <iostream>
#include <vector>
#include <sstream>
using namespace std;
#define BUFSZ 100 // Set max size of the numbers as a single string
int convertToIntegers(char *s, vector<int> &values);
int main()
{
int count;
int i;
char data[BUFSZ];
vector<int> values;
strcpy_s(data, "1,182,08 51 15");
count = convertToIntegers(data, values);
// for (auto val : values) // Show the result
// cout << val << '\n';
// *** OR ***
for (i = 0; i < count; i++)
cout << values[i] << '\n';
}
//////////////////////////////////////
// Convert a C string to integers
//
int convertToIntegers(char *s, vector<int> &values)
{
vector<string> numbers;
char *next_token;
char* ptr = strtok_s(s, " -.,;", &next_token);
while (ptr)
{
string str(ptr);
numbers.push_back(str);
ptr = strtok_s(NULL, " -.,;", &next_token); // Next number
}
//
// Convert the resulting strings to integers
//
for (auto str : numbers)
values.push_back(stoi(str));
return (int)values.size();
}
If you know you have exactly one character as a separator, either a space, either a comma, the following code will work:
#include <iostream>
#include <vector>
#include <sstream>
using namespace std;
int main() {
string line;
vector <string>data;
for (int i = 0; i < 10;i++) {
getline(cin,line);
data.push_back(line);
}
///converting digits to int
vector<int> values;
int n;
char ch=',';
for (int i = 0; i < data.size();i++) {
stringstream stream(data[i]);
while( stream >>n ) {
char c = stream.get();
//if(stream >> ch) {
// values.push_back(n);
//}
//else {
values.push_back(n);
//}
cout<<n<<" ";
}
cout<<endl;
}
return 0;
}
You are using multiple delimiters in the input ( like whitespace : , ; -) which complicates the matter. Here's a possible snippet using std::strtok:
//Enter a line
string line;
getline(cin, line);
// Convert string to char* so that std::strtok could be used later
char *cstr = new char[line.length() + 1];
std::strcpy(cstr, line.c_str());
vector<string> words;
// split line into multiple strings using multiple delimiters
char* ptr = std::strtok(cstr, " -.,;");
while (ptr)
{
string str(ptr);
words.push_back(str);
ptr = strtok(NULL, " -.,;");
}
delete[] cstr;
// Convert string to int
vector<int> values;
for (auto str : words){
values.push_back(std::stoi(str));
}
// Print the values
for (auto val : values){
cout << val << '\n';
}

How to insert an integer with leading zeros into a std::string?

In a C++14 program, I am given a string like
std::string s = "MyFile####.mp4";
and an integer 0 to a few hundred. (It'll never be a thousand or more, but four digits just in case.) I want to replace the "####" with the integer value, with leading zeros as needed to match the number of '#' characters. What is the slick C++11/14 way to modify s or produce a new string like that?
Normally I would use char* strings and snprintf(), strchr() to find the "#", but figure I should get with modern times and use std::string more often, but know only the simplest uses of it.
What is the slick C++11/14 way to modify s or produce a new string like that?
I don't know if it's slick enough but I propose the use of std::transform(), a lambda function and reverse iterators.
Something like
#include <string>
#include <iostream>
#include <algorithm>
int main ()
{
std::string str { "MyFile####.mp4" };
int num { 742 };
std::transform(str.rbegin(), str.rend(), str.rbegin(),
[&](auto ch)
{
if ( '#' == ch )
{
ch = "0123456789"[num % 10]; // or '0' + num % 10;
num /= 10;
}
return ch;
} // end of lambda function passed in as a parameter
); // end of std::transform()
std::cout << str << std::endl; // print MyFile0742.mp4
}
I would use regex since you're using C++14:
#include <iostream>
#include <regex>
#include <string>
#include <iterator>
int main()
{
std::string text = "Myfile####.mp4";
std::regex re("####");
int num = 252;
//convert int to string and add appropriate number of 0's
std::string nu = std::to_string(num);
while(nu.length() < 4) {
nu = "0" + nu;
}
//let regex_replace do it's work
std::regex_replace(std::ostreambuf_iterator<char>(std::cout),
text.begin(), text.end(), re, nu);
std::cout << std::endl;
return 0;
}
WHy not use std::stringstream and than convert it to string.
std::string inputNumber (std::string s, int n) {
std::stringstream sstream;
bool numberIsSet = false;
for (int i = 0; i < s; ++i) {
if (s[i] == '#' && numberIsSet == true)
continue;
else if (s[i] == '#' && numberIsSet == false) {
sstream << setfill('0') << setw(5) << n;
numberIsSet = true;
} else
sstream << s[i];
}
return sstream.str();
}
I would probably use something like this
#include <iostream>
using namespace std;
int main()
{
int SomeNumber = 42;
std:string num = std::to_string(SomeNumber);
string padding = "";
while(padding.length()+num.length()<4){
padding += "0";
}
string result = "MyFile"+padding+num+".mp4";
cout << result << endl;
return 0;
}
Mine got out of control while I was playing with it, heh.
Pass it patterns on its command line, like:
./cpp-string-fill file########.jpg '####' test###this### and#this
#include <string>
#include <iostream>
#include <sstream>
std::string fill_pattern(std::string p, int num) {
size_t start_i, end_i;
for(
start_i = p.find_first_of('#'), end_i = start_i;
end_i < p.length() && p[end_i] == '#';
++end_i
) {
// Nothing special here.
}
if(end_i <= p.length()) {
std::ostringstream os;
os << num;
const std::string &ns = os.str();
size_t n_i = ns.length();
while(end_i > start_i && n_i > 0) {
end_i--;
n_i--;
p[end_i] = ns[n_i];
}
while(end_i > start_i) {
end_i--;
p[end_i] = '0';
}
}
return p;
}
int main(int argc, char *argv[]) {
if(argc<2) {
exit(1);
}
for(int i = 1; i < argc; i++) {
std::cout << fill_pattern(argv[i], 1283) << std::endl;
}
return 0;
}
I would probably do something like this:
using namespace std;
#include <iostream>
#include <string>
int main()
{
int SomeNumber = 42;
string num = std::to_string(SomeNumber);
string guide = "myfile####.mp3";
int start = static_cast<int>(guide.find_first_of("#"));
int end = static_cast<int>(guide.find_last_of("#"));
int used = 1;
int place = end;
char padding = '0';
while(place >= start){
if(used>num.length()){
guide.begin()[place]=padding;
}else{
guide.begin()[place]=num[num.length()-used];
}
place--;
used++;
}
cout << guide << endl;
return 0;
}

C++ array string function

Can someone please show me how to create an array function that reads from file txt string data type
for example:
Read in the following files inside of a function:
colleges.txt
states.txt
Add the colleges/universities to a vector of strings.
Add the states to parallel arrays of strings.
Call the read function from your main function.
Thank you very much :D
Try the following code:
#include<iostream>
#include<string>
#include<fstream>
#include<vector>
void func()
{
std::ifstream fin;
fin.open("colleges.txt", std::ifstream::in);
std::vector<std::string> vec;
std::string line;
while(getline(fin, line))
{
vec.push_back(line);
}
fin.close();
int len = vec.size();
std::string *arr = new std::string[len];
int index = 0;
fin.open("states.txt", std::ifstream::in);
while(getline(fin, line))
{
arr[index++] = line;
}
fin.close();
for(auto e:vec) std::cout<<e<<" ";
std::cout<<"\n";
for(int i = 0; i < len; ++i)
std::cout<<arr[i]<<" ";
std::cout<<"\n";
delete [] arr;
}
int main()
{
func();
return 0;
}
use vectors, Carl!
#include <string>
#include <vector>
#include <fstream>
#include <iostream>
using namespace std;
struct TwoVectors {
vector<string> first ;
vector<string> second;
};
TwoVectors getSomeData() {
TwoVectors ret;
auto collegesReader = ifstream("colleges.txt");
auto statesReader = ifstream("states.txt");
string temp;
while (getline(collegesReader, temp))
ret.first.push_back(temp);
while (getline(statesReader, temp))
ret.second.push_back(temp);
collegesReader.close();
statesReader.close();
return ret;
}
int main() {
auto someData = getSomeData();
for (auto something : someData.first)
cout << something << endl;
for (auto something : someData.second)
cout << something << endl;
return 0;
}

Working with structs?

I'm having trouble working with strings (char*) in structs. I can't seem to call the right data I want too.
Under processFile it shows the struct member correctly; under main it does not.
Here is my code:
#include <iostream>
#include <io.h>
#include <string>
#include "dirent.h"
#include "Stream.h"
#include "Compression.h"
#include "Definitions.h"
using namespace std;
using namespace System::IO;
using namespace System::Funcs;
bool isRawfile(char* ext);
void ProcessDirectory(string directory);
void ProcessFile(char* file);
void ProcessEntity(struct dirent* entity);
typedef struct
{
char *name;
int usize;
int csize;
BYTE *data;
} rawfile;
string path = "";
string source;
int numrawfiles = 0, numstringtables = 0;
rawfile *rawfiles = new rawfile[0x400];
FILE * zone = fopen( "C:\\Users\\jake\\Desktop\\patch_mp.zone" , "wb" );
int main(int argc, char **args)
{
if(args[1] != NULL)
{
source = string(args[1]) + "\\"; //maybe move under else here..
if(strchr(args[1], '.') != NULL)
{
cout<<"Unable to compile files, please drag a folder to compile."<<endl;
cin.get();
return 0;
}
else
{
int header[] = {1,0,0x3B4,0,0,0,1,0,0x1000,0,0,0,-1};
for(int i=0; i<13; i++)
fwrite(Converter::Int32ToBytes(header[i]), 1 , 4 , zone );
ProcessDirectory(args[1]);
for(int i=0; i<numrawfiles; i++)
cout<<"Name: "<<rawfiles[i].name<<" Length: "<< rawfiles[i].usize << " - in main()"<<endl;
fclose(zone);
}
}
else
{
cout<<"No folder selected to compile. Press any Key to quit."<<endl;
cin.get();
return 0;
}
cin.get();
return 0;
}
void ProcessDirectory(string directory)
{
string dirToOpen = path + directory;
auto dir = opendir(dirToOpen.c_str());
path = dirToOpen + "\\";
if(NULL == dir)
{
cout << "could not open directory: " << dirToOpen.c_str() << endl;
return;
}
auto entity = readdir(dir);
while(entity != NULL)
{
ProcessEntity(entity);
entity = readdir(dir);
}
path.resize(path.length() - 1 - directory.length());
closedir(dir);
}
void ProcessEntity(struct dirent* entity)
{
if(entity->d_type == DT_DIR)
{
if(entity->d_name[0] == '.')
return;
ProcessDirectory(string(entity->d_name));
return;
}
if(entity->d_type == DT_REG)
{
string fullpath = path + entity->d_name;
ProcessFile(const_cast<char *>(fullpath.c_str()));
return;
}
cout << "Not a file or directory: " << entity->d_name << endl;
}
void ProcessFile(char* file)
{
char* extension = strrchr(file, '.');
if(isRawfile(extension))
{
rawfile raw;
raw.name = (char *)&file[source.length()];
raw.usize = File::getFileSize(file);
rawfiles[numrawfiles] = raw;
cout<<"Name: "<<rawfiles[numrawfiles].name<<" Length: "<< raw.usize << " - in ProcessFile()"<<endl;
fwrite(Converter::Int32ToBytes(0x23),1,4,zone);
fwrite(Converter::Int32ToBytes(-1),1,4,zone);
numrawfiles++;
}
}
bool isRawfile(char* ext)
{
char *exts[11] = {".gsc",".cfg",".txt",".news",".png",".vision",".rmb",".script",".arena",".atr",".csc"};
for(int i=0; i<10; i++)
if(strncmp(ext,exts[i],strlen(exts[i]))==0)
return true;
return false;
}
Here is an example picture:
What am I doing wrong?
Save yourself a lot of trouble by using an std::string:
#include <string>
struct thing
{
std::string name;
int age;
};
You can also avoid the dynamically allocated array:
#include <vector>
std::vector<thing> things(3);
You are outputting the memory address of "Ben" instead of the actual String. You should use
cout << things[1]->name << endl;
which is syntactic sugar for
cout << (*things[1]).name << endl;
To add to what scd said, you are not successfully dereferencing the name member. When you try and operate on things[1].name you are operating on a pointer, which is simply a memory location.
This is one of the trickiest things when learning to use pointers. Here is some more reading on the dereference operator, and syntax hints.
http://en.wikipedia.org/wiki/Dereference_operator#Other_syntax
Edit:
After compiling myself, I realized that I was on the wrong track with this one, and that std::cout will correctly handle the char pointer. You should be able to solve this with your code, just ensure that you give your struct array a size.
This worked for me:
#include <iostream>
#define MAXSIZE 3
typedef struct
{
char* name;
int age;
}Thing;
Thing *things = new Thing[MAXSIZE];
int _tmain(int argc, _TCHAR* argv[])
{
char* names[MAXSIZE] = { "Alice", "Ben", "Carlos" };
int ages[MAXSIZE] = { 24, 25, 26 };
for(int i=0; i<MAXSIZE; i++)
{
things[i].name = names[i];
things[i].age = ages[i];
}
std::cout << things[1].name << std::endl;
return 0;
}