converting string vectors to int - c++

I have to make a program that reads information for a student from a file, and I made a couple of vectors to keep all that information. But then I need to sum up the absences of all the students, so I need to convert them to integer, however when I try to the program runs, but crashes immediately when it reaches the atoi part.
while(!read.eof()) {
if(i==4){
i=0;
}
read>>b;
if(i==0){ names.push_back(b); }
if(i==1){ last_name.push_back(b); }
if(i==2){ absences.push_back(b); }
if(i==3){ unatoned.push_back(b); }
i++;
}
int a = atoi(absences[0].c_str());

If absences remains empty then the behaviour of absences[0] is undefined.
Using absences.at(0) when absences is empty forces the compiler to throw an exception so is easier to work with.
Either way, for the number of absences, use simply
auto a = absences.size();

You should change you absences vector to be a vector of int:
std::vector<int> abscences;
// rest of the code...
The read >> var instruction will take care of the conversion.
Of course, the >> operator will not write into the integer if it's invalid.

Related

cout doesn't works properly on my program, can somebody help me?

enter image description hereI am using the STL in c++ and inside a bucle the cout doesn't prints correctly a float.
my program ads values to a vector and then passes it to a function to see if the condition exist, actually it works perfectly but just the cout doesn't word, I already tried using printf() but it gave the same result.
note:please algo give me feedback on my question is the first time i do one and English is not my natal language
my code:
#include<bits/stdc++.h>
#include<vector>
using namespace std;
void isthereanumber(vector<float> array);
int main(){
string ans;vector<float> array;float number;
do{
fflush(stdin);
cout<<"insert a value for the vector: "<<endl;
cin>>number;
array.push_back(number);
fflush(stdin);
cout<<"would you like to keep adding values to the vector? "<<endl;
getline(cin,ans);
}while(ans.compare("yes")==0);
isthereanumber(array);
return 0;
}
void isthereanumber(vector<float> array){
float suma =0;
for(vector<float>::iterator i=array.begin();i!=array.end();i++){
for(vector<float>::iterator j=array.begin();j!=array.end();j++){
if(i!=j){
suma = suma+array[*j];
}
}
if(suma=array[*i]){
cout<<"there is a number that the addition of every number in the array except the number is equal to the number \n";fflush(stdin);
cout<<"the number is: "<<suma;/*here is the cout that doesnt works properly or perhabs is something else i don't know*/
return;
}
}
cout<<"there is not a number with such a condition: ";
return;
}
As stated by cleggus already there are some issues present. Those need to be adressed first. After that there's a logical error in that suma just keeps growing.
Given the input 5,5,10 once we test for 10 we would like suma to be set to 0 again for it to work but it will be something like 30 now instead.
That can be solved by moving suma inside the outer loop.
Working example for input 5,5,10: https://godbolt.org/z/gHT6jg
I think you may have a couple of issues...
In your for loops you are creating iterators to the vector, but rather than just dereferencing them to access the indexed element you are dereferencing them and then using that as an index to the same vector.
Also Your last if statement has an assignment = rather than a comparison ==.
I believe this is closer to what you are trying to achieve (sorry I haven't had time to compile and check):
for(vector<float>::iterator i=array.begin();i!=array.end();i++){
for(vector<float>::iterator j=array.begin();j!=array.end();j++){
if(i!=j){
suma = suma+*j;
}
}
if(suma==*i){
cout<<"there is a number that the addition of every number in the array except the number is equal to the number \n";fflush(stdin);
cout<<"the number is: "<<suma;/*here is the cout that doesnt works properly or perhabs is something else i don't know*/
return;
}
}

Unable to get output for multiplication

#include<iostream.h>
int main()
{
int n[50],p=0;
double g=1;
char c;
cout<<"\n press a for addition";
cout<<"\n press m for multiplication";
cin>>c;
if(c=='a')
{
for(int i=0;n[i]=!'=',i<50;i++)
{
cin>>n[i];
p+=n[i];
}
cout<<p;
}
else if(c=='m')
{
for(int j=0;n[j]=!'=',j<50;j++)
{
cin>>n[j];
g*=n[j];
}
cout<<g;
}
else cout<<"wrong input";
}
I have wrote this code, it works perfectly fine when addition part is used but when multiplication is done it isn't giving the final product. Whenever I click '=' it doesn't give any final product during multiplication but while addition the same logic works fine.
You have multiple problems:
The array n isn't initialized so its contents will be indeterminate, and using indeterminate values lead to undefined behavior.
Fortunately (for you) the loop "condition" expression n[j]=!'=',j<50 doesn't do what you probably think it does... The part n[j]=!'=' is actually equal to n[j] = !'='. That is you assign the result of !'=' to n[j].
And about the loop "condition", the result of n[j]=!'=',j<50 is the result of j<50 only, because that's how the comma operator works.
With cin>>n[j] you can't read arbitrary characters, as n[j] is an int and you only read int values. The only way to get a '=' from the input is if the user inputs the value 61 which happens to be the ASCII encoded value for '='.
Your loop "condition" also have another flaw, because you increase j before you check n[j], so in the condition n[j] will always be an element of the array that you haven't read into.
And building on the previous point, because the value of j will be wrong in the "condition" you will go out of bounds of the array which also leads to undefined behavior.

grabbing data sets from a file with an arbitrary amount of spaces

**No direct answers or code examples please, this is my homework which i need to learn from. I'm looking for help concerning the algorithm i need to develop.
I seem to be having a logic error in coming up with a solution for a portion of my class work, the program involves multiple files, but here is the only relevant portion:
I have a file PlayerStats that holds the stats for a basketball player in:
rebounds
points
assists
uniform #
my initial reaction would be to create a while loop and read these into a temporary struct that holds these values, then create a merge function that merges the values of the temp struct with the inital array of records, simple enough?
struct Baller
{
//other information on baller
int rebounds;
int assists;
int uniform;
int points;
void merge(Baller tmp); //merge the data with the array of records
}
//in my read function..
Baller tmp;
int j = 0;
inFile << tmp.uniform << tmp.assists << tmp.points << tmp.rebounds
while(inFile){
ArrayRecords[j].merge(tmp);
j++;
//read in from infile again
}
The catch:
The file can have an arbitrary number of spaces between the identifiers, and the information can be in any order(leaving out the uniform number, that is always first). e.g.
PlayerStats could be
11 p3 a12 r5 //uniform 11, 3 points 12 assists 5 rebounds
//other info
OR
11 p 3 r 5 a 12 //same exact values
What I've come up with
can't seem to think of an algorithm to grab these values from the file in the correct order, i was thinking of something along these lines:
inFile << tmp.uniform; //uniform is ALWAYS first
getline(inFile,str); //get the remaining line
int i = 0;
while(str[i] == " ") //keep going until i find something that isnt space
i++;
if(str[i] == 'p') //heres where i get stuck, how do i find that number now?
else if(str[i] == 'a')
eles if(str[i] = 'r'
If you're only going to check one letter, you could use a switch statement instead of if / else, that would make it easier to read.
You know where the number starts at that point, (hint: str[i+1]), so depending on what type your str[] is, you can either use atoi if its a char array, or std::stringstream if it's an std::string.
I'm tempted to give you some code, but you said not too. If you do want some, let me know and I'll edit the answer with some code.
Instead of using a 'merge' function, try using an std::vector so you can just push_back your structure instead of doing any 'merging'. Besides, your merge function is basically a copy assignment operator, which is created by the compiler by default (you don't need to create a 'merge' function), you just need to use = to copy the data across. If you wanted to do something special in your 'merge' function, then you should overload the copy assignment operator instead of a 'merge' function. Simples.
Do something like that:
int readNumber () {
while isdigit (nextchar) -> collect in numberstring or directly build number
return that number;
}
lineEater () {
Read line
skip over spaces
uniform=readNumber ();
haveNum=false;
haveWhat=false;
Loop until eol {
skip over spaces
if (isdigit)
number=readNumber ();
skip over spaces
haveNum=true;
else
char=nextChar;
haveWhat=true;
if (haveChar and haveNum) {
switch (char) {
case 'p' : points=number; break;
...
}
haveNum=false;
haveWhat=false;
}
}
or, if you are more ambitous, write a grammar for your input and use lex/yacc.

Making an array of pointers to structs or objects in C++

So I'm basically just trying to take in some file input, and then take that data and put it into several structs. The only issue I'm having is with the naming of the pointers to the structs. The struct's themselves are supposed to represent students and I wanted to set each pointer as one of their names rather than an arbitrary variable. I tried to do this in a way that I'm assuming is syntactically wrong for it didn't work. In the code below, I increment the for loop with the temp array because each 4th position is a new student. Any ideas on how I could go about this?
#include<iostream>
#include<iomanip>
#include"student.h"
#include"creditcard.h"
#include<fstream>
using namespace std;
int main ()
{
string creditcards[20];
int i;
int x;
int amount;
string temp[20];
ifstream infile;
string filename;
int count;
int numstudents;
string newstring="";
string pointers[20];
cout<<"enter the file name of which you've stored your"<<endl
<<"credit card infomation"<<endl;
getline(cin,filename,'\n');
infile.open(filename.c_str());
count=0;
getline(infile,temp[count],'\n');
while(! infile.eof())
{
count++;
getline(infile,temp[count],'\n');
numstudents= (count/4);
if(numstudents < 1 || count%4 != 0)
{
cout<<"incorrect data file"<<endl;
}
}
cout<<numstudents<<endl;
for(i=0,x=0; i<numstudents;i++,x+4)
{
student *temp[x];
temp[x] = new student;
pointers[i] = temp[x];
}
for(i=0;i<numstudents;i+4)
{
cout<<temp[i]<<endl;
}
return 0;
}
Ok, let's start from the top.
Your code was (before I reformatted it) a mess. Messy code is harder to read and more likely to have bugs.
You have 3 arrays, each containing 20 strings. Why do you need so many?
One of them is named temp; having to use that as a variable name is a good indicator that you're mishandling data somewhere.
You're declaring int count relatively early on, then initializing it to 0 later. While not necessarily a bad thing, that's not the best method (do both at once, when needed).
You can declare local variables more than one in a line, but you don't need to declare them all at the top of the function. That's not necessary in C++.
int main ()
{
string creditcards[20];
int i = 0, x = 0, amount = 0;
(legal, but might not be needed)
It's typically better to declare and initialize a variable at the same time, just before you need it:
int count = 0;
getline(infile, temp[count], '\n');
I remember seeing that reading until you hit eof isn't recommended, although I'm not entirely sure on that. You may want to change this:
while ( !infile.eof() )
{
Now, the first actual mistake I see here is that you read a line, increment count, then read another line before acting. Is that intentional, and if so, why is it necessary? Doing the getline and increment inside the loop would be more readable and potentially more reliable.
count++;
getline(infile, temp[count], '\n');
This line is a bug, I think:
for(i=0,x=0; i<numstudents;i++,x+4)
The last section does i++, x+4. It does not change x.
The next loop after that handles i in the same way this loop uses x, so you can probably combine those two.
Now, on top of all that, massive temp arrays are not the solution to this problem (or any other that I can think of).
To store this kind of data, you'll want to look into a std::map<std::string, student*> or std::vector<student*>. The vector will allow you to push the new student struct to the back when necessary, and the map will allow you to key them based on name and retrieve that later, something like so:
typdef map<string, student*> studentmap;
studentmap students;
studentmap::iterator iter = students.find("Bob");
if ( iter != students.end() )
{
student * bob = iter->second;
// Work with data
}
It's a much better way of handling this, and will take a lot of the guess work out of what you're doing now.
If you want to be able to reference the students by name, consider using a map<string, student> or map<string, student*>.
This will allow you to refer to individual students via students["Jack"] or students["Jill"].

dynamically created arrays

My task consists of two parts. First I have to create globbal char array of 100 elements, and insert some text to it using cin. Afterwards calculate amount of chars, and create dedicated array with the length of the inputted text. I was thinking about following solution :
char[100]inputData;
int main()
{
cin >> inputData >> endl;
int length=0;
for(int i=0; i<100; i++)
{
while(inputData[i] == "\0")
{
++count;
}
}
char c = new char[count];
Am I thinking good ?
Second part of the task is to introduce in the first program dynamically created array of pointers to all inserted words. Adding a new word should print all the previous words and if there is no space for next words, size of the inputData array should be increased twice. And to be honest this is a bit too much for me. How I can create pointers to words specifically ? And how can I increase the size of global array without loosing its content ? With some temporary array ?
Regardless of the rest of your question, you appear to have some incorrect ideas about while loops. Let's look at this code.
for(int i=0; i<100; i++) {
while(inputData[i] == "\0") {
++count;
}
}
First, "\0" is not the NUL character. It is a pointer to a string containing only the terminating NUL byte. You want '\0' instead. Assuming this change, there are still problems. Let's work through what will happen:
How does a while loop work? It executes the body repeatedly, as long as the condition is true.
When does a while loop finish? When the condition is finally made false by executing the body.
What's the condition of your loop? inputData[i] == '\0', after correction.
What's the body? ++count.
Can ++count ever change the value of the condition? No, because it doesn't change i.
So, if inputData[i] is not the NUL byte, the while loop never executes.
But, if inputData[i] is the NUL byte, the while loop executes forever.
Assuming you've read a proper string into inputData, then at some point inputData[i] will be NUL, and you'll have an infinite loop.
To count the length of a standard C string, just do this
count = strlen(inputData);
If for some reason you really have to write a loop, then the following works:
int len = 0,
while (inputData[len] != '\0') {
len++;
}
After the loop, len holds the length of the string.
#include <iostream>
#include <string>
int main()
{
std::string input;
std::getline(std::cin, input);
}
Global arrays can't have the size changed dynamically unless they are a pointer to an array, in which case you can erase them and reallocate them.
Perhaps what you're after is an automatically resizing array, like a std::vector. You can see how many letters you have in the array by calling size() on the vector, and you can increase the size of the array by calling resize().
While not the most elegant solution, it might be a bit easier to use for the moment.