C File Handling - Trouble using Strings with Char - c++

Good day, I'm having some trouble with my code. I just started with file handling last week and I'm currently stuck with adding Strings to the program. I would like to add the names in the main program from the file, but I've tried pretty much everything. Any help would be highly appreciated. Also, this is my first time on Stack Overflow, so sorry if I missed posting any information.
The picture includes the Input.txt file as well as the current output. I added console output to test the problem and it seems to have something to do with the characters. I've tried using String itself, but that was still a fail. Also, I'm not allowed to use the C++ way of file handling (if that makes sense). [I am allowed to use C++ though] - Doing this whole program for practice for my upcoming exams.
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string>
using namespace std;
int ReadFile(char*,int*,double*);
int main()
{
char names[128];
int ages[128];
double salaries[128];
int size = ReadFile(names, ages, salaries);
for(int i = 0; i < size; i++)
{
printf("My name is %s, and I am %d years old. My salary is $%.2lf\n", *(names+i), *(ages+i), *(salaries+i));
}
return 0;
}
int ReadFile(char *namesArr, int *ageArr, double *salaryArr)
{
FILE *IN = fopen("Input.txt", "r");
int i = 0;
if(IN == NULL)
{
cout << "Error! Can't open file.";
exit(1);
}
else
{
char name[20];
int age = 0;
double salary = 0.00;
while(fscanf(IN, " %c,%d,%lf", &name, &age, &salary) != EOF)
{
*(namesArr + i) = *name;
*(ageArr + i) = age;
*(salaryArr + i) = salary;
cout << *(namesArr+i) << " ";
i++;
}
}
fclose(IN);
return i;
}
Input.txt:
Kazu,21,2250.00 Anonymous,34,3500.25 John,31,2750.00 Paul,25,3125.25
Jin,19,1750.00

Save time, enable all compiler warnings
My name is %s --> My name is %c
If you want to read in the name, and not just the first letter, many more changes needed too such as:
char name[20];
int age = 0;
double salary = 0.00;
while(fscanf(IN, " %19[A-Za-z'] ,%d ,%lf", &name, &age, &salary) == 3)
{
*(namesArr + i) = *name; // This only copies the first `char`
strcpy(TBD, name); // Need something like this.
// TBD is a pointer to an `char` array
*(ageArr + i) = age;
*(salaryArr + i) = salary;
cout << TBD << " ";
i++;
}

Related

Read from the file from different functions

I'm trying to read from the same file from another function but it doesn't work.
I guess the problem is that I'm trying to read from ifstream &input but I don't know the other way to implement that
#include <iostream>
#include <fstream>
using namespace std;
class Student{
public:
char name[40]; // i cant use string
int age;
void Input(ifstream &input)
{
input.getline(name, 40);
input >> age;
}
};
void Read(Student *students, int &numberOfStudents)
{
ifstream input("test.txt");
input >> numberOfStudents;
students = new Student[numberOfStudents];
for (int i = 0; i < numberOfStudents; ++i)
students[i].Input(input);
input.close();
}
int main()
{
int size = 0;
Student *students = NULL;
Read(students, size);
for (int i = 0; i < size; ++i)
cout << students[i].name << endl << students[i].age << endl;
return 0;
}
I made my input file
3
1
2
3
4
5
6
(if the program was working correctly i should've get 1 - name age - 2 etc)
but what i got is no names with ages = 1 2 3 respectively
The program does not work because you define:
void Read(Student *students, int &numberOfStudents)
And then
int size = 0;
Student *students = NULL;
Read(students, size);
The students pointer is passed-by value so Read() can not change the memory address outside the function.
To fix this simply pass the the pointer by-reference:
void Read(Student *& students, int &numberOfStudents)
Lastly as I commented you need to account white space e.g. '\n' line ending
In the file when using >> operator to extract data:
void Input(ifstream &input)
{
input.getline(name, 40);
input >> age;
input.ignore(1);
}
Same for reading the number of students in the file.

get function returns invalid value

I'm working on a code for a school project which I can't use strings.
I'm having problems getting the value for hourlyPay.
The program's output:
5 Christine Kim 4.94066e-324
Although, the file contains the following:
5 Christine Kim 30.00
#include <iostream>
#include <iomanip>
#include <fstream>
#include <cstring>
using namespace std;
//Class decleration
class Employee
{
private:
int id; //Employee ID.
char name[21]; //Employee name.
double hourlyPay; //Pay per hour.
public:
Employee(int initId=0, char [] =0, double initHourlyPay=0.0); //Constructor.
bool set(int newId, char [], double newHourlyPay);
int getId() { return id; }
const char * getName() { return name;}
double getHourlyPay() { return hourlyPay;}
};
Employee::Employee( int initId, char initName[], double initHourlyPay)
{
bool status = set( initId, initName, initHourlyPay);
if ( !status )
{
id = 0;
strcpy(name, "");
hourlyPay = 0.0;
}
}
bool Employee::set( int newId, char newName[], double newHourlyPay)
{
bool status = false;
if ( newId > 0)
{
status = true;
id = newId;
strcpy(name, newName);
hourlyPay = newHourlyPay;
}
return status;
}
const int MAX_SIZE = 100;
int main()
{
int id; //Employee ID.
char newName[21];
double hourlyPay; //Pay per hour.
Employee list[15]; //Array to store
ifstream masterFile; //Opens master file.
masterFile.open("master10.txt");
int count = 0;
if (masterFile)
{
for (count; count < 2; count++)
{
masterFile >> id;
masterFile.ignore();
masterFile.getline(newName, 21);
masterFile >> hourlyPay;
list[count].set(id, newName, hourlyPay);
}
}
masterFile.close(); //Close master file.
cout << list[0].getId() << " " << list[0].getName() << " " << list[0].getHourlyPay();
}
The original file contains more lines, but I narrowed it down in order to figure out my error.
What am I doing wrong?
I have figured it out.
#include <iostream>
#include <iomanip>
#include <fstream>
#include <cstring>
using namespace std;
//Class decleration
class Employee
{
private:
int id; //Employee ID.
char name[21]; //Employee name.
double hourlyPay; //Pay per hour.
public:
Employee(int initId=0, char [] =0, double initHourlyPay=0.0); //Constructor.
bool set(int newId, char [], double newHourlyPay);
int getId() { return id; }
const char * getName() { return name;}
double getHourlyPay() { return hourlyPay;}
};
Employee::Employee( int initId, char initName[], double initHourlyPay)
{
bool status = set( initId, initName, initHourlyPay);
if ( !status )
{
id = 0;
strcpy(name, "");
hourlyPay = 0.0;
}
}
bool Employee::set( int newId, char newName[], double newHourlyPay)
{
bool status = false;
if ( newId > 0)
{
status = true;
id = newId;
strcpy(name, newName);
hourlyPay = newHourlyPay;
}
return status;
}
const int MAX_SIZE = 100;
int main()
{
int id; //Employee ID.
char newName[21];
double hourlyPay; //Pay per hour.
Employee list[15]; //Array to store
ifstream masterFile; //Opens master file.
masterFile.open("master10.txt");
int count = 0;
if (masterFile)
{
for (count; count < 2; count++)
{
masterFile >> id;
masterFile.ignore();
masterFile.get(newName, 21);
masterFile >> hourlyPay;
list[count].set(id, newName, hourlyPay);
}
}
masterFile.close(); //Close master file.
cout << list[0].getId() << " " << list[0].getName() << " " << list[0].getHourlyPay();
}
I only changed getline to get and now it can read in the middle of a line with a limit of 20 chars.
I appreciate everyone's attention and help.
Data from the file is not correctly entered into the variables in your code. Here's a solution which is self explainatory.
for (count; count < 1; count++)
{
char secondname[11];
masterFile >> id;
masterFile.ignore();
masterFile >> newName;
masterFile >> secondname;
masterFile >> hourlyPay;
strcat(newName, " ");
strcat(newName, secondname);
list[count].set(id, newName, hourlyPay);
}
It's not a good idea to contain a name with blank space in the line, if you insist to do this, I think we can read the line and split the name and the hourlyPlay. The better way is that not contain blank space in the name, but use character like _, and replace the character with blank space after reading, the you can simple use >> to read each field
I modified a little to support multiline reading & printing, check the source:
#include <iostream>
#include <iomanip>
#include <fstream>
#include <cstring>
#include <vector>
using namespace std;
//Class decleration
class Employee
{
private:
int id; //Employee ID.
char name[21]; //Employee name.
double hourlyPay; //Pay per hour.
public:
Employee(int initId = 0, const char* = 0, double initHourlyPay = 0.0); //Constructor.
bool set(int newId, const char*, double newHourlyPay);
int getId() { return id; }
const char * getName() { return name; }
double getHourlyPay() { return hourlyPay; }
};
Employee::Employee(int initId, const char* initName, double initHourlyPay)
{
bool status = set(initId, initName, initHourlyPay);
if (!status)
{
id = 0;
strcpy(name, "");
hourlyPay = 0.0;
}
}
bool Employee::set(int newId, const char* newName, double newHourlyPay)
{
bool status = false;
if (newId > 0)
{
status = true;
id = newId;
strcpy(name, newName);
hourlyPay = newHourlyPay;
}
return status;
}
int main()
{
int id; //Employee ID.
double hourlyPay; //Pay per hour.
vector<Employee> list; //Array to store
ifstream masterFile; //Opens master file.
char line[256];
masterFile.open("master10.txt");
if (masterFile)
{
while (!masterFile.eof())
{
masterFile >> id;
masterFile.getline(line, sizeof(line));
char* last_word = strrchr(line, ' ');
line[last_word - line] = 0;
hourlyPay = atof(last_word + 1);
list.push_back(Employee(id, line, hourlyPay));
}
}
//Close master file.
masterFile.close();
for (size_t i = 0; i < list.size(); ++i)
cout << list[i].getId() << " " << list[i].getName() << " " << list[i].getHourlyPay() << endl;
}
So.. you really want to do this with a plain old array of Employee and plain old character arrays and cstring?
There is absolutely nothing wrong with doing it that way -- and it will sure make you appreciate the convenience of using string and vector. But, that said, there is a wealth of valuable learning that can be gained from walking a pointer (or couple of pointers) through each line of data to parse the id, name & hourlyPay from each line of data.
The fly-in-the-ointment of the entire parsing process is not knowing how many spaces may be contained in name (it could have none, one, two, three, ...). Though, things are not as dire as they may appear. You know you have an int that begins the line of data and a double at the end -- everything left in between the whitespace after the int and before the double is your name.
The key here is really to read each line of data into a buffer (character array) as a cstring. Then you can use the standard tool strtol to read the id and advance a pointer to 1-past the last digit in id. You can then simply iterate forward on a character-by-character basis checking if (isspace(*p)) and continuing to advance until a non-whitespace character is found (or you hit the nul-terminating character at the end). Once you find your non-whitespace character -- you have a pointer set to the beginning of name.
Now you have to work on the other end and back up until you find the space before hourlyPay. Not that difficult. You will need strlen (buf), but at least using masterFile.getline(..) you are saved the need of trimming the '\n' from the end of the buffer by overwriting with a nul-terminating character. Simply set your end-pointer to buf + len - 1 and you are sitting on the last digit of hourlyPay. Then in similar manner, it is just a matter up backing up while (ep > sp && !isspace (*p)) (you know if your end-pointer ever reaches your start-pointer sitting at the beginning of name the parse has failed)
Now remember, here you are 1-character before the beginning of hourlyPay, so when you go to convert hourlyPay using strtod, you must remember to use p + 1 as the start of the cstring-segment for converting hourlyPay. As with any strtoX conversion, you have two primary tests (1) that following the conversion the start-pointer is not equal to the endptr parameter indicating that digits were actually converted to a number and (2) errno was not set during conversion -- indicating a failure in the actual conversion. (and when converting to a smaller type than the conversion -- e.g. to int using strtol -- you must check that the value converted is within the range of int before assigning to your value.
Now you have your id and hourlyPay -- all that is left is backing up from the beginning of hourlyPay to the end of name. You do this in like manner checking isspace() until it is no longer true, and that your pointer to the end of name is still greater than your pointer to the start of name. Now you can use strncpy to copy the name to your variable for newName by copying p - sp + 1 characters (remember you are sitting on the last character with p so you will need to add 1 to get all characters in name.
Putting it altogether and providing comments inline below, you could do something like the following (noting that your original class and member functions were left unchanged -- only the parse of the id, name & hourlyPay in main() was dramatically affected) As always -- the key is to validate each step -- then you can have confidence in the data you are processing.
#include <iostream>
#include <iomanip>
#include <fstream>
#include <cstring>
#include <cctype>
#include <limits>
#define MAXLIST 16 /* if you need constants, define one (or more) */
#define MAXNM 64
#define MAXBUF 1024
#define FNAME "dat/master10.txt"
using namespace std;
//Class decleration
class Employee
{
private:
int id; //Employee ID.
char name[MAXNM]; //Employee name.
double hourlyPay; //Pay per hour.
public:
Employee (int initId=0, char [] =0, double initHourlyPay=0.0);
bool set (int newId, char [], double newHourlyPay);
int getId() { return id; }
const char *getName() { return name;}
double getHourlyPay() { return hourlyPay;}
};
Employee::Employee (int initId, char initName[], double initHourlyPay)
{
bool status = set(initId, initName, initHourlyPay);
if (!status)
{
id = 0;
strcpy(name, "");
hourlyPay = 0.0;
}
}
bool Employee::set (int newId, char newName[], double newHourlyPay)
{
bool status = false;
if (newId > 0) {
status = true;
id = newId;
strcpy(name, newName);
hourlyPay = newHourlyPay;
}
return status;
}
int main (void) {
int id, //Employee ID.
count = 0;
long tmp; /* tmp for strtol conversion */
char newName[MAXNM] = "",
buf[MAXBUF] = ""; /* line buffer */
double hourlyPay; //Pay per hour.
Employee list[MAXLIST]; //Array to store
ifstream masterFile (FNAME); //Opens master file.
if (!masterFile.is_open()) { /* validate file open for reading */
cerr << "error: file open failed '" << FNAME << "'\n";
return 1;
}
/* read each line in masterFile into buf */
while (count < MAXLIST && masterFile.getline (buf, sizeof buf))
{
size_t len = strlen (buf); /* get length */
char *sp = buf, /* start pointer */
*p = buf + len - 1, /* working pointer */
*ep = NULL; /* end pointer for strtod conversion */
/* parse and convert id, leaving sp 1-past last digit */
errno = 0; /* zero errno before strtol conversion */
tmp = strtol (buf, &sp, 0); /* store conversion in tmp */
if (buf == sp) { /* validate characters were converted */
cerr << "error: no digits converted in id.\n";
return 1;
}
if (errno != 0) { /* validation errno not set */
cerr << "error: failed converstion for id.\n";
return 1;
}
/* validate tmp within range of integer */
if (tmp < numeric_limits<int>::min() ||
numeric_limits<int>::max() < tmp) {
cerr << "error: id not within integer range.\n";
return 1;
}
id = (int)tmp; /* assign tmp to id */
/* advance sp to 1st char in name */
while (*sp && isspace (*sp))
sp++;
/* parse hourlyPay */
/* work backward with p until space before hourlyPay found
* always validate p > sp so you don't back up beyond the start of
* name (or the beginning of buf).
*/
while (p > sp && !isspace (*p))
p--;
if (p > sp && !isdigit(*(p + 1))) { /* validate next char is digit */
cerr << "error: failed to parse hourlyPay.\n";
return 1;
}
errno = 0; /* zero errno before strtol conversion */
hourlyPay = strtod (p+1, &ep); /* convert hourlyPay to double */
if (p + 1 == ep) { /* validate characters were converted */
cerr << "error: no digits converted in hourlyPay.\n";
return 1;
}
if (errno != 0) { /* validation errno not set */
cerr << "error: failed converstion for hourlyPay.\n";
return 1;
}
/* continue working backwards to end of name */
while (p > sp && isspace (*p))
p--;
if (p <= sp) { /* validate chars between sp & p */
cerr << "error: failed to find end of name.\n";
return 1;
}
len = p - sp + 1; /* get number of chars in name */
if (len > MAXNM - 1) { /* validate it will fit in newName */
cerr << "error: name exceeds" << len << "characters.\n";
return 1;
}
strncpy (newName, sp, len); /* copy name to newName */
/* set values in list[count], on success, increment count */
if (list[count].set (id, newName, hourlyPay))
count++;
}
masterFile.close(); //Close master file.
/* outoput all employee id and hourlyPay information */
for (int i = 0; i < count; i++)
cout << list[i].getId() << " " << list[i].getName() <<
" " << list[i].getHourlyPay() << '\n';
}
(now you see why string and the other C++ tools make things much nicer?)
Example Input File
The only data you posted was used as the input file, e.g.
$ cat dat/master10.txt
5 Christine Kim 30.00
Example Use/Output
$ ./bin/employeepay
5 Christine Kim 30
Look things over and let me know if you have further questions.

Shifting an array of structs C++

I am quite new to c++ programming and data structures and really need some help. I am working on an assignment where I have a text file with 100 lines and on each line there is an item, a status(for sale or wanted), and a price. I need to go through the text file and add lines to an array of structs and as I add lines I need to compare the new information with the previously submitted information. If there is a line that is wanted and has a price higher than a previously input item that is for sale then the item would be removed from the struct and the array of structs shifted.
The place that I am having trouble is in actually shifting all the structs once a line that satisfies the condition is found.
My issue is that when I try to shift the array of structs using the second for loop nothing happens and I just get null structs and nothing seems to move.
Please if you guys can offer any help it would be greatly appreciated.
Below is the code of the text file and my current code.
#include<iostream>
#include<fstream>
#include <string>
#include <algorithm>
#include <sstream>
using namespace std;
struct items
{
string type;
int status;
int price;
} itemArray [100];
int main(int argc, char *argv[]) {
int x = -1;
//int chickenCount = 0;
int counter = 0;
int itemsSold = 0;
int itemsRemoved = 0;
int itemsForSale = 0;
int itemsWanted = 0;
string itemType;
int itemStatus = 0;
int itemPrice = 0;
int match = 0;
ifstream myReadFile( "messageBoard.txt" ) ;
std::string line;
//char output[100];
if (myReadFile.is_open()) {
while (!myReadFile.eof()) {
getline(myReadFile,line); // Saves the line in STRING.
line.erase(std::remove(line.begin(), line.end(), ' '), line.end());
//cout<<line<<endl; // Prints our STRING.
x++;
std::string input = line;
std::istringstream ss(input);
std::string token;
while(std::getline(ss, token, ',')) {
counter++;
//std::cout << token << '\n';
if (counter>3){
counter =1;
}
//cout << x << endl;
if (counter == 1){
itemType = token;
//cout<< itemType<<endl;
}
if (counter == 2){
if (token == "forsale"){
itemStatus = 1;
//itemsForSale++;
}
if (token == "wanted"){
itemStatus = 0;
//itemsWanted++;
}
//cout<< itemStatus<<endl;
}
if (counter == 3){
itemPrice = atoi(token.c_str());
//cout<< itemPrice<<endl;
}
//cout<<"yo"<<endl;
}
if (x >= 0){
for (int i = 0; i<100;i++){
if (itemArray[i].type == itemType){
//cout<<itemType<<endl;
if(itemArray[i].status != itemStatus){
if (itemArray[i].status == 1){
if(itemPrice>=itemArray[i].price){
itemsSold++;
match =1;
//itemArray[i].type = "sold";
for (int j=i; j<100-1;j++){
//cout<<j<<endl;
itemArray[j].type = itemArray[j+1].type;
itemArray[j].status = itemArray[j+1].status;
itemArray[j].price = itemArray[j+1].price;
}
i =i-1;
break;
}
}
if (itemArray[i].status == 0){
if(itemArray[i].price>=itemPrice){
itemsSold++;
match = 1;
//itemArray[i].type = "sold";
for (int j=i; j<100-1;j++){
//cout<<j<<endl;
itemArray[j].type = itemArray[j+1].type;
itemArray[j].status = itemArray[j+1].status;
itemArray[j].price = itemArray[j+1].price;
}
i=i-1;
break;
}
}
}
}
}
}
if (counter == 3 && match == 0){
itemArray[(x)].type = itemType;
itemArray[(x)].status = itemStatus;
itemArray[(x)].price = itemPrice;
}
match = 0;
// cout << itemArray[x].type << " " << itemArray[x].status<<" "<<itemArray[x].price<<endl;
}
for(int i=0;i<100;i++){
cout<<itemArray[i].type<< " "<<itemArray[i].status<<" "<<itemArray[i].price<<endl;
}
//cout<<itemArray[1].price<<endl;
cout << itemsSold<<endl;
}
myReadFile.close();
return 0;
}
text file: https://drive.google.com/file/d/0B8O3izVcHJBzem0wMzA3VHoxNk0/view?usp=sharing
Thanks for the help
I see several issues in the code, but without being able to test it, I think the main problem is that you always insert new elements at position 'x' which correspond to the currently line read from the file, without taking into account any shift of elements done. You should insert the new element at the first empty slot (or just overwrite the old element instead of shifting everything).
An other issue is that you do not initialize the status and price in your array.
The best way would be to rewrite the code by using more standard C++ features, for example:
replace the items structure by a class with a constructor defining default values
use object copy (there is no need to copy a struct element by element)
use standard C++ containers like a list (see http://www.cplusplus.com/reference/list/list/) which has insert and erase methods

Finding a string element in an array C++

I have found other topics like this, but none of them are working, it keeps returning -1 regardless what I type. Idk why, thanks!
#include <iostream>
#include <string>
using namespace std;
int find(string arr[], int len, string seek)
{
for (int i = 0; i < len; ++i)
{
if (arr[i].find(seek) != string::npos) {
return i;
}
return -1;
}
}
int main() {
string info[] = { "Becky Warren, 678-1223","Joe Looney, 586-0097","Geri Palmer , 223-887","Lynn Presnell, 887-1212","Holly Gaddis, 223-8878","Bob Kain, 586-8712","Tim Haynes, 586-7676","Warren Gaddis, 223-9037", "Jean James , 678-4939","Ron Palmer, 486-2783" };
cout<<"Please enter a name and you will be returned a phone number"<<endl;
string name;
cin>>name;
//for (int i = 0; i<sizeof(info)/sizeof(info[i]);i++) {
int x = find(info,10,name);
cout<<x;
//cout<<info[x]<<endl;
//}
system("pause");
}
Your problem is that your return - 1 should be after for loop. When you check whether your string is somewhere in your array you do it only one time, because of the fact that after an if statement the program sees return - 1 which means "oh I should exit the function now and return -1".
for (int i = 0; i < len; ++i)
{
if (arr[i].find(seek) != string::npos)return i;
}
return -1;
When you got such a simple problems I recommend you to use debugger which will tell you exactly what you are doing in your program.
You can use the function std::string::find available in the standard C++. See this link for an example on how to use it.
In particular it is needed to develop two main steps:
in the function find that you have written you find the index of the array (or vector as in the following example) containing that name;
Then you need to find inside the string found the position of the comma (through find function of standard library) and then extract the substring containing the number which is located two positions after the comma. You can do this using substr function.
Below a sample code using vector instead of array.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int find(vector<string> arr, string seek)
{
for (int i = 0; i < arr.size(); ++i)
{
if (arr.at(i).find(seek) != string::npos) {
return i;
}
return -1;
}
}
int main()
{
vector<string> info;
info.push_back("Becky Warren, 678-1223");
info.push_back("Joe Looney, 586-0097");
info.push_back("Geri Palmer , 223-887");
info.push_back("Lynn Presnell, 887-1212");
info.push_back("Holly Gaddis, 223-8878");
info.push_back("Bob Kain, 586-8712");
info.push_back("Tim Haynes, 586-7676");
info.push_back("Warren Gaddis, 223-9037");
info.push_back("Jean James , 678-4939");
info.push_back("Ron Palmer, 486-2783" );
cout<<"Please enter a name and you will be returned a phone number"<<endl;
string name;
cin>>name;
// x is the string in the array containing the name written by the user
int x = find(info, name);
// Check if at least one was found
if(x == -1)
{
cout << "Name " << name << " not found." << endl;
return -1;
}
// extract number from the found string (find comma position and then take a substring starting from that position until the end
int commaPosition = info.at(x).find(",");
string phoneNumber = info.at(x).substr(commaPosition+2);
cout<<"Phone number found: " << phoneNumber<< endl;
system("pause");
return 0;
}

Cutting a string into pieces

How can I extract pieces from this string?
I have a file that contains:
0065445 APPLE$456
089464 MANGO$489
0012389 GUAVA$744
What I want to do is input the file line by line, then cut the string into some pieces.
0065455 Will go in a struct a[0].num
APPLE will go in struct a[0].name
456 will go in struct a[0].dollar
And similarly for other lines.
Everything is working fine, but it's not successfully getting the dollar part into its variable.
Here's the code:
#include<cstdlib>
#include<iostream>
using namespace std ;
int main(){
FILE *fp;
fp = fopen("input.txt","r");
char str[80] ;
struct abc{
int num;
char name[20];
int dollar;
};
int i = 0;
while(fgets(str,79,fp)!=NULL){
struct abc a[i] ;
sscanf(str,"%d %[^$]s$%d\n",&a[i].num,a[i].name,&a[i].dollar);
cout <<i+1 <<") Number : "<<a[i].num<<" Name : "<< a[i].name <<" Dollar : "<< a[i].dollar << endl ;
i++;
}
return 0 ;
}
/* These didn't work too.
sscanf(str,"%d %[^$]s %d\n",&a[i].num,a[i].name,&a[i].dollar);
sscanf(str,"%d %[^$]s%d\n",&a[i].num,a[i].name,&a[i].dollar);
sscanf(str,"%d %s$%d\n",&a[i].num,a[i].name,&a[i].dollar);
*/
There's 1 more problem: the first part of string is an int that starts with 0, but the zero is not being accepted in the int. How to do it?
This is working as I want now but still after parasing the string into an int I am not getting the zeroes:
#include<cstdlib>
#include<iostream>
#include<cstring>
using namespace std ;
int main(){
FILE *fp;
fp = fopen("input.txt","r");
char str[80] ;
char temp[80] ;
struct abc{
int num;
char name[20];
int dollar;
};
int i = 0;
int j = 0 ;
while(fgets(str,79,fp)!=NULL){
i = 0;
j = 0 ;
struct abc a[i] ;
char* ptr = 0; // this is used as a helper variable to strtok
ptr = strtok(str, " $\n"); // we specify the delimiters here
while (ptr != NULL)
{
if (j == 0){
strcpy(temp, ptr);
a[i].num = atoi(temp);
}
if (j == 1)
strcpy(a[i].name, ptr);
if (j == 2){
strcpy(temp, ptr);
a[i].dollar = atoi(temp);
}
ptr = strtok(NULL, " $\n");
j++;
}
cout <<i+1 <<") Number : "<<a[i].num<<" Name : "<< a[i].name <<" Dollar : "<< a[i].dollar << endl ;
i++;
}
return 0 ;
}
/* These didn't work either.
sscanf(str,"%d %[^$]s %d\n",&a[i].num,a[i].name,&a[i].dollar);
sscanf(str,"%d %[^$]s%d\n",&a[i].num,a[i].name,&a[i].dollar);
sscanf(str,"%d %s$%d\n",&a[i].num,a[i].name,&a[i].dollar);
*/
Based on the C++ tag, I'd do things a little differently. First I'd overload the stream extractor operator for your abc type:
std::istream &operator>>(std::istream &is, abc &a) {
is >> a.num;
std::getline(is, a.name, '$');
return is >> a.dollar;
}
Then you can use that to read in a file of records, such as:
abc temp;
std::vector<abc> a;
std::ifstream in("input.txt");
while (in >> temp)
a.push_back(temp);
Or, you can use an istream_iterator to initialize a vector directly from the stream:
std::vector<abc> a((std::istream_iterator<abc>(in)),
std::istream_iterator<abc>());
The easiest way to keep the leading zeros on the first number is probably to change it from an int to a std::string.
Use strtok:
Here is a simple code (C only) that prints your strings separately (I recommended a similar solution in another post).
#include <stdio.h>
#include <string.h> // for strcpy and strtok
#include <stdlib.h> // for atoi
int main()
{
char input [25] = "0065445 APPLE$4056"; // input string
// storage for the separate parts of the string
char line[10];
char fruit[10];
char number[10];
char* ptr = 0; // this is used as a helper variable to strtok
ptr = strtok(input, " $\n"); // we specify the delimiters here
int i = 0;
// I'm using i here as a control variable so that during each iteration different part
// of the string is saved
while (ptr != NULL)
{
if (i == 0)
strcpy(line, ptr);
if (i == 1)
strcpy(fruit, ptr);
if (i == 2)
strcpy(number, ptr);
ptr = strtok(NULL, " $\n");
i++;
}
printf("%s %s %s\n", line, fruit, number);
return 0;
}
Some sample output:
$ ./a.out
0065445 APPLE 4056
Is this what you need?
the 0's will not show up when you print the integer a[i].num.
You could make a[i].num a string (char[]) or an integer array. to make the 0's show up. you can parse it as an integer (via atoi(str)), if you need it to be used otherwsie.
#include <iostream>
#include <fstream>
#include <sstream>
struct abc{ int num; std::string name; int dollar; };
int main(int argc, char* argv[]) {
std::ifstream file("input");
abc st1;
std::string l;
while (file >> st1.num >> l) {
if (size_t p = l.find_first_of('$')) {
st1.name = l.substr(0, p);
std::istringstream(l.substr(p+1)) >> st1.dollar;
std::cout << st1.num << " : "
<< st1.name << " : " << st1.dollar << std::endl;
}
}
return 0;
}