Reading input from text file to array in c++ [duplicate] - c++

This question already has answers here:
Reading input from text file to array in c++
(2 answers)
Closed 4 years ago.
Alright, be gentle, since I'm very much a novice to programming. So far I've only studied C++ and I'm running Visual Studio 2010 as my compiler. For this program, I'm trying to read from a text input file and write the information to a set of three arrays. One array will handle a list of names, and the other two are for hours worked and hourly pay rate, respectively. I will use the latter two to calculate a set of earnings and output those calculations to another text file. My problem, however, is with acquiring input for the first array. The input file I'm using has text arranged like this:
J. Doe* 35 12.50
J. Dawn* 20 10.00
.........
The names are trailed by asterisks since I'm trying to use ifstream getline to acquire the names with the asterisks acting as delimiters, and writing the following two numbers into the other two arrays. The latter two values are separated by whitespaces, so I don't think they'll cause any problems. I'm sure there are other errors that need handling but I need to work through the first error before I can start debugging the rest. I encounter an error with the line where I call inFile.getline, which reads as follows:
error C2664: 'std::basic_istream<_Elem,_Traits> &std::basic_istream<_Elem,_Traits>::getline(_Elem *,std::streamsize,_Elem)' : cannot convert parameter 1 from 'std::string' to 'char *'.
From what I've read elsewhere, (I think) the problem stems from trying to write a string to a char array, which won't work since they are of different data types. I'm not sure if other feasible methods exist for acquiring the names since I need the delimiter to separate the names from the numerical values. Any advice on how to resolve this issue would be much appreciated.
Here is the source I've written:
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
using namespace std;
const int EMP_NUM = 5;
const int BASE_HOURS = 40;
const char N_SIZE = 8;
int main()
{
int i;
double rEarnings, oEarnings, tEarnings,
trEarnings, toEarnings, ttEarnings;
ifstream inFile;
ofstream outFile;
inFile.open("records.txt");
outFile.open("report.txt");
outFile << setprecision(2) << showpoint << fixed;
outFile << setw(50) << "Payroll Report" << "\n\n";
outFile << "EMPLOYEE NAME" << setw(25) << "REGULAR EARNINGS" << setw(25) << "OVERTIME EARNINGS" << setw(25) << "TOTAL EARNINGS" << endl;
string nameAr[EMP_NUM];
int hoursAr[EMP_NUM];
double hrateAr[EMP_NUM];
for (int i = 0; i < EMP_NUM; i++) // Get input from our input file.
{
inFile.getline(nameAr[i], EMP_NUM, "*");
inFile >> hoursAr[i] >> hrateAr[i];
}
for (int i = 0; i < EMP_NUM; i++) // Make the calculations to be sent to our report.
{
char nameAr[N_SIZE];
int hoursAr[N_SIZE];
double hrateAr[N_SIZE];
if (hoursAr[i] > 40) // For employees with overtime hours.
{
// double rEarnings, double oEarnings, double tEarnings,
// double trEarnings, double toEarnings, double ttEarnings;
// rEarnings = 0, oEarnings = 0, tEarnings = 0,
// trEarnings = 0, toEarnings = 0, ttEarnings = 0;
rEarnings = BASE_HOURS * hrateAr[i];
oEarnings = (hoursAr[i] - BASE_HOURS) * hrateAr[i] * 1.5;
tEarnings = rEarnings + oEarnings;
trEarnings += rEarnings;
toEarnings += oEarnings;
ttEarnings += tEarnings;
outFile << left << nameAr[i];
// << setw(25) << right << rEarnings << setw(25) << right << oEarnings << setw(25) << right << tEarnings << endl;
}
else // For employees without overtime hours.
{
double rEarnings, double oEarnings, double tEarnings,
double trEarnings, double toEarnings, double ttEarnings;
rEarnings = 0, oEarnings = 0, tEarnings = 0,
trEarnings = 0, toEarnings = 0, ttEarnings = 0;
rEarnings = hoursAr[i] * hrateAr[i];
oEarnings = 0;
tEarnings = rEarnings + oEarnings;
trEarnings += rEarnings;
toEarnings += oEarnings;
ttEarnings += tEarnings;
outFile << left << nameAr[i] << setw(25) << right << rEarnings << setw(25) << right << oEarnings << setw(25) << right << tEarnings << endl;
}
}
outFile << endl << endl;
outFile << setw(33) << trEarnings << " *" << setw(23) << toEarnings << " *" << setw(23) << ttEarnings << " *\n\n";
outFile << left << "TOTAL EMPLOYEES" << " " << (i - 1);
inFile.close(); outFile.close();
return 0;
}
I've included the entire program to give you an idea of where I plan to go with the coding. Thanks in advance for the help!

Hello C++ new programmer! Welcome to the awesomeness of coding in C/C++.
I know you just started C++. But to fix your problem, we have to touch a bit of C. C++ so happens to be a superset of C. Meaning everything that can be done in C will work in a C++ program.
Ok enough words, code time. Replace the code you use to get input from your input file with this:
char tmp[256];
memset(tmp, '\0', sizeof tmp);
inFile.getline(tmp, EMP_NUM, '*');
nameAr[i] = tmp;
inFile >> hoursAr[i] >> hrateAr[i];
Let's walk through it.
char tmp[256]; will create a temporary array for reading in the values. The size of this array may vary with the average length of names you receive.
Strings in C are like high maintenance chics. You have to specify a NULL character '\0' at the end or they may crash your program with not-so-obvious Segmentation faults. However, Memset is a little man that works down in the mines of a computer; he's gonna help us fix this. When called in this form memset(tmp, '\0', sizeof tmp), memset starts at the address of tmp, walks through all the bits of the array - the size id specified as sizeof tmp - and sets these bits to the character specified - in this case NULL. This way we would not have to remember to append the NULL character every-time we read in a C string; provided the size of tmp is sufficiently large. Convenient!
inFile.getline(tmp, EMP_NUM, '*'); reads the input [string] from your file as expected and stores it in tmp.
nameAr[i] = tmp; puts the input read into the names array.
and finally, inFile >> hoursAr[i] >> hrateAr[i]; reads the hours and hourly rates as before.
Hope this helps.
Cheers!
Happy Learning.

I would not use getline in this way, because you have two separate separator chars to deal with - space and asterisk. Here's what I would do instead:
Use getline to get the FULL line into a string called line.
Find the asterisk using line.find('*');
Extract the name as a new string using line.substr up to the position just found
Take another substr beyond the asterisk into a stringstream called remainder.
Read the int and double directly from it using operator>>: remainder >> hours >> rate;

Related

Stringing together multiples of the same string (an asterisk) determined by an input file. C++

Essentially, the objective is to read an input file (hence inFile and inFileName) and output a population growth with asterisks representing each 1000 people using an ID (ex. 1375892), going from the year 1900 to 2020 in 20-year increments.
So, 1 asterisk for 1000 people, 3 asterisks for 3000 people, etc. The input file has numbers like 5000 and 7000 that I need to use to calculate the number of asterisks I need (by dividing by 1000). Even with that, I'm trying to figure out the final step in converting asteriskNum (the number of asterisks I need to use) and have it output the string of asterisks, not an integer of how many asterisks I need.
I definitely know I'm missing SOMETHING, but even after asking my teacher and scouring through my textbook and notes, I can't figure out how to solve this specific issue.
#include<iostream>
#include<iomanip>
#include<string>
#include<fstream>
using namespace std;
int main(){
string asterisk = "*";
string firstName;
int PopNum{0};
int year{1900};
int asteriskNum{};
const string INTROLINE{"POPULATION GROWTH \n(each * represents 1000 people)"};
cout << INTROLINE << "\n";
string inFileName="DL8_L5_Morrison.txt";
ifstream inFile{inFileName};
if (inFile){
cout << inFileName << " opened for reading. \n";
inFile >> firstName;
while (not inFile.eof()){
inFile >> PopNum;
asteriskNum = PopNum/1000;
cout << year << " " << asteriskNum << " " << << "\n";
year+=20;
inFile.close();
}
else {
cout << inFileName << " did not open for reading. \n";}
cout<<"Goodbye!\n";
return EXIT_SUCCESS;
}
}
You can use a std::string object and use the constructor that takes a count and character as arguments (constructor version #2 here). This will work with an int for the count argument, but it is better to cast it to a size_t type (or just have the calculated value as a size_t in the first place):
//...
asteriskNum = PopNum/1000;
cout << year << " " << std::string(static_cast<size_t>(asteriskNum), '*') << std::endl;
//...

C++ program if statements in function not executing. Seems Logically errored

I am making a program in C++, that takes the user entered time in U.S. standard time and converts it to military time. The body of the main code is executing fine, but the problem comes in the body of my function beginning with the if statements. I am wondering why this is occurring; am fairly new with c++. Here's my code if you have question feel free to ask or need explanation of what the program is supposed to be doing.
#include <iostream>
#include <string>
using namespace std;
void militaryConversion(string am_pmPart_st, string firstPartofTime, string secondPartofTime){
// Converts they obtained strings, but first we must concatenate the two parts into one string
string concatenatedTime;
int militaryTime;
cout << "test1" << endl;
concatenatedTime = firstPartofTime + secondPartofTime;
if(firstPartofTime == "12")
{
cout << "Corresponding military time is: " << concatenatedTime << " hours" << endl;
}
else if(am_pmPart_st == " am")
{
if (concatenatedTime.length() < 4){
cout << "Corresponding military time is: " << concatenatedTime << " hours"<< endl;
}
}
else if(am_pmPart_st == " pm")
{
int castedTime;
castedTime = stoi(concatenatedTime); //This is where we convert the string to int because its the only place it matters
militaryTime = castedTime + 1200;
cout << "Corresponding military time is: " << militaryTime << " hours" << endl;
}
}
int main()
{
char DELEMETER = ':';
char DELEMETER_sp = ' ';
string time, firstPartofTime, secondPartofTime, am_pmPart_st, loweredAM_PM;
cout << "Enter the time in the format of: HH:MM AM/PM ";
getline(cin, time);
firstPartofTime = time.substr(0, time.find(DELEMETER));
cout << "The first digits of time " << firstPartofTime << endl;
secondPartofTime = time.substr(time.find(DELEMETER) + 1, time.find(DELEMETER_sp)-1);
cout << "The second set of digits " << secondPartofTime << endl;
am_pmPart_st = time.substr(time.find(DELEMETER_sp), time.size());
cout << "The am/pm part is:" << am_pmPart_st << endl;
for(int i=0; am_pmPart_st[i]; i++) am_pmPart_st[i] = tolower(am_pmPart_st[i]); //Converts am/pm to lowercase
cout << am_pmPart_st << endl;
militaryConversion(am_pmPart_st, firstPartofTime, secondPartofTime);
}
First, your question is vague because it does say what is happening that should not be happening. However, I think I can see what is happening. When you check for the hour part of the time in the first condition, you check for "12" first. However, you never correct for am or pm within that 12. My recommendation would be to check for 12 inside the am (12 am == 0000 hours) and pm (12 pm == 1200 hours). In am you will need to check for 12 and subtract 1200 from the time, in pm you will need to check for 12 and not add 1200 to the time.
substr takes two parameters. The first is the start position and the second is the length. When you call secondPartofTime = time.substr(time.find(DELEMETER) + 1, time.find(DELEMETER_sp)-1); you are mistakenly passing the second parameter as the end position, not the length.
Instead, you can do:
int startPos = time.find(DELEMETER) + 1;
int endPos = time.find(DELEMETER_sp) - 1;
secondPartofTime = time.substr(startPos, endPos - startPos + 1);
Ideally, you should check the return values of find and handle the case when npos is returned so you don't crash on invalid user input.
Input which doesn't follow the HH:MM AM/PM form is creating a problem. (Exactly 5 characters for HH:MM (including colon))
You have an if-else based decision tree, where one if is not accompanied by an else. The lack of else is why your program is not giving any output
string.substr() has some issues as explained by MFisherKDX

Reading bytes from a P6 PPM file into a character array (C++) [duplicate]

This question already has answers here:
uint8_t can't be printed with cout
(8 answers)
Closed 7 years ago.
Here is the relevant code:
string s;
int width, height, max;
// read header
ifstream infile( "file.ppm" ); // open input file
infile >> s; // store "P6"
infile >> width >> height >> max; // store width and height of image
infile.get(); // ignore garbage before bytes start
// read RGBs
int size = width*height*3;
char * temp = new char[size]; // create the array for the byte values to go into
infile.read(temp, size); // fill the array
// print for debugging
int i = 0;
while (i < size) {
cout << "i is " << i << "; value is " << temp[i] << endl;
i++;
}
Then, the output that I get says that the values in the array are either blank, or "?". I guess this means the bytes were not converted into chars properly?
i is 0; value is
i is 1; value is
i is 2; value is
i is 3; value is ?
i is 4; value is ?
...etc.
It looks like you want it to print a BYTE value, not a character. Try this:
cout << "i is " << i << "; value is " << (int)(temp[i]) << endl;
By casting the char to an int, cout will print the value, not the ASCII code.

Cannot find the end of an array when opening a file

So I want to open a file and display the contents. Thing is, I don't know how many elements are used and how many elements are empty. So, when I try to display the elements the first few are shown but the rest are random numbers. How do I find and display the exact number of elements?
file:
10011 Ali Doha 12355555 11-5-14 3434 7890
10015 Ahmed Al-Khor 51244444 13-6-14 3425 4455
10014 Mohammed Al-Wakra 53344333 17-7-14 5566 1234
10012 Omar Doha 56666666 10-8-14 1234 5678
10013 Youssef Al-Khor 7555512 5-5-14 88000 4532
10019 Hamad Al-Wakra 81234567 8-6-14 3125 1265
10018 Jassim Doha 86753541 9-7-14 9875 5566
code:
#include<iostream>
#include<fstream>
#include<string>
using namespace std;
int main()
{
const int isize=10;
ifstream datafile;
datafile.open("D:\customers.txt");
int customer_number[isize];
string customer_name[isize];
string customer_address[isize];
long contact[isize];
string Due_date[isize];
int water_consumption[isize];
int electricity_consumption[isize];
double total_bill[isize];
if (!datafile)//to know if the file is exist or not
cout << "error" << endl;
else
{
for(int i=0; i<1000; i++)
{
datafile >> customer_number[i];
datafile>> customer_name[i];
datafile>> customer_address[i];
datafile>> contact[i];
datafile>> Due_date[i];
datafile>> water_consumption[i];
datafile>> electricity_consumption[i];}
}
for(int i=0; i<isize; i++)
{
if(customer_number[i] == '\0')
break;
else
cout << customer_number[i] << "\t" << customer_name[i] << "\t" << customer_address[i] << "\t" << contact[i] << "\t"
<< Due_date[i] << "\t" << water_consumption[i] << "\t" << electricity_consumption[i] << "\t" << endl;
}
datafile.close();
return 0;
}
Looks like each text line is a record, thus use std::getline with std::string to read a record.
When the number of records is unknown, you need a dynamic container, such as std::vector, std::list or std::map, not a fixed size array.
You will need to research the std::string methods and also std::istringstream for parsing the text line into native format fields. There are lots of examples on StackOverflow on how to do this.
So stop using fixed size arrays and use std::vector instead.

Converting ascii substr to int

first year college having problem converting ascii into int.
The problem is this piece of code
unsigned short iminutes = ((minutes[3]-48)*10) + (minutes[4]-48);
When I run this on codeblocks at home it returns an incorrect value, when I run it again I get a different incorrect value.
When I run it at on Borlands at college, the screen just ups and disappears before I can read it, so I can't use the system clock here either.
It's Easter hols now so even though I'm at college, I can't annoy my tutors because they're not.
#include <iostream.h>
#include <conio.h>
#include <string>
//#include <time.h>
//#include <ctype.h>
using namespace std;
int main() {
bool q = false;
do {
// convert hours to minutes ... then total all the minutes
// multiply total minutes by $25.00/hr
// format (hh:mm:ss)
string theTime;
cout << "\t\tPlease enter time " << endl;
cout <<"\t\t";
cin >> theTime;
cout << "\t\t"<< theTime << "\n\n";
string hours = theTime.substr (0, 2);
cout <<"\t\t"<< hours << endl;
unsigned short ihours = (((hours[0]-48)*10 + (hours[1] -48))*60);
cout << "\t\t"<< ihours << endl;
string minutes = theTime.substr (3, 2);
cout <<"\t\t"<< minutes << endl;
unsigned short iminutes = ((minutes[3]-48)*10) + (minutes[4]-48);
cout << "\t\t" << iminutes << endl;
cout << "\n\n\t\tTotal Minutes " <<(ihours + iminutes);
cout << "\n\n\t\tTotal Value " <<(ihours + iminutes)*(25.00/60) << "\n\n";
}
while (!q);
cout << "\t\tPress any key to continue ...";
getch();
return 0;
}
You set minutes to be a substring of theTime. So minutes has 2 characters. The first one starting at position 0 within minutes.
So this
unsigned short iminutes = ((minutes[3]-48)*10) + (minutes[4]-48);
is wrong as it accesses characters 3 and 4 in minutes which don't exist, because minutes is only two characters long. It only has characters as positions 0 and 1.
should be this
unsigned short iminutes = ((minutes[0]-48)*10) + (minutes[1]-48);
or you could use this:
unsigned short iminutes = ((theTime[3]-48)*10) + (theTime[4]-48);
The problem is that even though you get the characters at position 3 and 4 from the original string, the new string is just two characters (i.e. only have index 0 and 1).
istringstream iss(theTime.substr(0, 2));
iss >> ihour;