Jump to content

C++ text to array to string to print help...

Sebastian Kurpiel

What's up guys,

I have an assignment where I have to get strings from an order.txt file and make them into an array then "iterate through to create an order object." How do I convert the first line,"7", from a string to int to use in myarray[num_order]? What does my professor mean by iterate through to create order object? 

This is what I have so far.

#include "order.h"
#include <fstream> 
#include <cstring>
#include <iostream>
#include <string>


using namespace std;

void count_msg_types(Order **& orders, int num_orders);

int main(){
  ifstream fin; //file stream
  char temp[200]; // use this in order to go through file reading
  int num_orders=0; //get the first line that has how many orders you have
  int quantity; // holds quantity for order object
  int orderid;  //holds orderid for order object
  char msg_type; //holds msg_type for order object
  char side; //holds b or a for bid or ask for order object
  double price; //holds price for order objects
  char * symbol; //holds symbol for order object
  Order ** orders; //dynamic array that holds dymanic order object

 // I started from here, the above is my professor's.

 ifstream fin("orders.txt");
  std::string;
  if (fin.is_open())
  {
	  string first= NULL;// creates a size of the array
	  getline(fin, first);// gets the first line which is the size of the array
	  cout << "Number of orders are" << first << endl; // prints the size of the array
  }
  if (fin.is_open())
  {
	  string num_orders = first + 1;
	  string myArray[num_orders + 1] 
	}
  fin.close();
  //open fileThis is what my professor wants us to do!
  //get the first line that has the size put it in num_orders
  //create the array that holds order objects
  //iterate through to create order object and add to array 
  //clear and close fin

  //write console
  //call count_msg_types
  //delete orders
  return 0;
}

void count_msg_types(Order **& orders, int num_orders){
    //Fill me in 
}

 

The orders.txt file,

7
A,YHOO,B,12.94,10,12345
A,YHOO,A,12.98,11,98709
A,YHOO,B,12.95,9,74658
M,YHOO,B,12.95,50,74758
A,YHOO,A,12.99,10,89097
M,YHOO,A,12.90,100,98709
D,YHOO,B,12.98,100,12345
 

 

Link to comment
Share on other sites

Link to post
Share on other sites

You need just go through those entries.

 

Read first line, then convert it to integer with atoi function and save to num_orders.

You need to allocate enough memory to store num_orders of orders, so allocate it using new operator, at first you need to allocate array of pointers, and then for each pointer allocate memory for one order object, you can allocate all now or allocate one by one as you read each line of text file.

 

I don't really know what your professor mean by using temp char array to read files, as getline method is simple enough, and to make use of temp you would need to use stream's read method which takes char array as argument, and length as second bout  you would need to know how many characters to read, so you would need to read file by one character and check if it is already \n or \r character, after you read line you need to parse it splitting by coma character , your professor prepared for you bunch of variables you probably need to read values to

int quantity; // holds quantity for order object
  int orderid;  //holds orderid for order object
  char msg_type; //holds msg_type for order object
  char side; //holds b or a for bid or ask for order object
  double price; //holds price for order objects
  char * symbol; //holds symbol for order object

I can only guess which referees to which. For example  M,YHOO,B,12.95,50,74758

M - message type

YHOO - symbol (symbol is array of chars and this is only value that is string and not single character, so it has to be symbol, if symbol is always 4 letters then youre good with allocating array of 4 chars once, but if it varry then you need to measure it and allocate as long array as needed, the same for order instance, it might be done internaly, idk)

B - side

12.96 - price

50 - quantity

74758 - orderid

 

When you read all of those you can populate one of order object in your orders array

 

After you done that in a loop you will have array of order instances. You can whatever you want with them but after you done you need to free memory by delete each order and then delete[] whole array of pointers.

 

I don't really know, but I guess you should not use std::string and std::getline just cstring functions for like strpos and substr. I'm also not sure if you should use new and delete operators or malloc and free.

 

BTW. there is floating point number in data, you can convert it form string to int by atof or std::stod

 

Link to comment
Share on other sites

Link to post
Share on other sites

@Mr_KoKa so I have re-edited my code and this what I have so far.  


#include "order.h"
#include <fstream> 
#include <cstring>
#include <iostream>
#include <string>


using namespace std;

void count_msg_types(Order **& orders, int num_orders);

int main(){
  ifstream fin; //file stream
  char temp[200]; // use this in order to go through file reading
  int num_orders=0; //get the first line that has how many orders you have
  int quantity; // holds quantity for order object
  int orderid;  //holds orderid for order object
  char msg_type; //holds msg_type for order object
  char side; //holds b or a for bid or ask for order object
  double price; //holds price for order objects
  char * symbol; //holds symbol for order object
  Order ** orders; //dynamic array that holds dymanic order object

  fin.open("orders.txt");//opens orders.txt    
  fin.getline(temp, 200, '\n');//gets the first line of text which is the number of orders
  fin >> num_orders; // creates num_orders
  cout << "Number of Orders: " << num_orders << endl;// prints the number of orders in a text file
  
  orders = new Order *[num_orders];//creates the array
  if (fin.is_open()) { //if the file stream is open
      for (int n = 0; n < num_orders; n++) { //iterates through the array
          symbol = 0;
          fin.getline(symbol, 200, ',');//gets the symbol
          cout << "Symbol: " << symbol << endl;// prints symbol

          side ="0";
          fin.getline+(side, 200, ',');//gets the side
          cout << "Side: " << side << endl;// prints side

          quantity = 0;
          fin.getline(quantity, 200, ',');//gets the quantity
          cout << "Quantity: " << quantity << endl;// prints quantity

          price = 0;
          fin.getline(symbol, 200, ',');//gets the price
          cout << "Price: " << symbol << endl;// prints price

          orderid = 0;
          fin.getline(orderid, 200, ',');//gets the orderid
          cout << "Orderid: " << symbol << endl;// prints orderid
            
      }
  }
  //open file
  //get the first line that has the size put it in num_orders
  //create the array that holds order objects
  //iterate through to create order object and add to array
  //clear and close fin

  //write console
  //call count_msg_types
  //delete orders
  return 0;
}

/*void count_msg_types(Order **& orders, int num_orders){
    A = add_msg
    M = mod_msg
    D = del_msg
    C = clear_msg
    cout << "Add Msg" << A << "Modify Msg" << M << "Delete Msg" << D << "Clear Msg:" << C >> endl;
    //Fill me in 
} */ 

Receiving errors with the getline(side,200,","); code

Link to comment
Share on other sites

Link to post
Share on other sites

I think you get error by trying ot assign "0" to sign, sign is char and "0" is cstring (null terminated char array), it looks like:

{48, 0} or {'0', '\0'}

 

Despite that, you assign 0 to symbol which is pointer (technically it is ok, but I bet it is not what you mean).

symbol must be allocated first, as I said, if symbols are always 4 characters length you just new char[5]; so you can keep all 4 characters of a symbol and a terminating null character to make it valid cstring.

 

quantity and orderid are integers, you cannot use those as char array pointers in getline, similar with price, it is a double.

 

At the end, you read orderid until ',' but there is no coma at the end of lines, there should be '\n' instead.

 

fin.getline(temp, 200, '\n');//gets the first line of text which is the number of orders
  fin >> num_orders; // creates num_orders

notice that you read first line to temp, it is the line with number of orders, and then you're reading from file to integer, and since first line has been read, the stream is gonna try to read "A,YHOO,B,12.94,10,12345" which will fail. Instead of this, just use what you read with geline and convert what you have in your temp to integer with eg. itoa function.

 

Don't forget to delete[] your orders array at the end. This is actually array of potiners, so if you want to store data there you would need allocate order for each orders index

So your orders variable is:

//You read first line and num_orders = 7
//by invoking this code:
Order **orders;
orders = new Order*[num_orders];
// You have created array of Order* (pointer at Order object), which would look like {Order*, Order*, Order*, Order*, Order*, Order*, Order*}
// But you cannot store data in those orders, cause those pointers are not point at anything, you will need to allocate memory for those pointers
// So they will point at Order object instance. In your foor loop:
orders[n] = new Order();

// Then when you are done with all reading, processing - when those orders and it's data is not needed anymore, you need to free that allocated
// memory by, again, delete every order, and then by delete orders array, so in loop you're doing: (it is new loop, not your reading loop)
for(int i = 0; i < num_orders; i++){
  delete orders[i]; // single pointer delete operator
}
delete[] orders; // array of pointers delete operator

 

 

Link to comment
Share on other sites

Link to post
Share on other sites

@Mr_KoKaWhat is an atoi function I have been trying to figure out how to implement that in my code.


  orders = new Order *[num_orders];//creates the array
  if (fin.is_open()) { //if the file stream is open
      for (int n = 0; n < num_orders; n++) {//iterates through the array
          orders[n] = new Order();
          fin.getline(temp, 200, ',');
          fin >> msg_type;
          fin.getline(symbol, 200, ',');//gets the symbol
          fin >> symbol;
          cout << "Symbol: " << symbol << endl;// prints symbol
          fin.getline(side, 200, ',');//gets the side
          fin >> side;
          cout << "Side: " << side << endl;// prints side
          fin.getline(quantity, 200, ',');//gets the quantity
          fin >> quantity;
          cout << "Quantity: " << quantity << endl;// prints quantity
          fin.getline(symbol, 200, ',');//gets the price
          fin >> price;
          cout << "Price: " << symbol << endl;// prints price
          fin.getline(orderid, 200, '\n');//gets the orderid
          fin >> orderid;
          cout << "Orderid: " << symbol << endl;// prints orderid
            
      }
  }

So is this correct?

 

Link to comment
Share on other sites

Link to post
Share on other sites

First, atoi is a function that converts cstring to integer.

 

Second. You have to understand that when tou do fin.getline and fin >> variable, this is two read operations.

 

You should do more like:

bool res;

res = static_cast<bool>(fil.getline(temp, 2, ',')); //There is 2 because you have to have space for 1 character for msg_type and one char for terminating NULL
if(res){    
  //getline successfuly read 1 character and encounter ',' sign
  //our temp array contains now msg_type
  msg_type = temp[0]; //We copy that one character, and we can now read other, thing, I will skip to price and quantity so I can show you atof and atoi

  //read symbol and side

  res = static_cast<bool>(fil.getline(temp, 200, ','));
  if(res){
    price = atof(temp); //We can use strtod instead, to handle errors better.
    
    res = static_Cast<bool>(fil.getline(temp, 200, ','));
    if(res){
      quantity = atoi(temp); //as strtod, we can use strtoi here
    	
      //read orderid - similar to quantity
    }	
  }  
}/* else {
  //',' didn't occured after first character (or other read error occurred)
}*/

if(!res){
  std::cout << "There was problem with data" << std::endl;
  return 1;
}
                        
                        

 

 

Link to comment
Share on other sites

Link to post
Share on other sites

Quote

//You read first line and num_orders = 7
//by invoking this code:
Order **orders;
orders = new Order*[num_orders];
// You have created array of Order* (pointer at Order object), which would look like {Order*, Order*, Order*, Order*, Order*, Order*, Order*}
// But you cannot store data in those orders, cause those pointers are not point at anything, you will need to allocate memory for those pointers
// So they will point at Order object instance. In your foor loop:
orders[n] = new Order();

// Then when you are done with all reading, processing - when those orders and it's data is not needed anymore, you need to free that allocated
// memory by, again, delete every order, and then by delete orders array, so in loop you're doing: (it is new loop, not your reading loop)
for(int i = 0; i < num_orders; i++){
  delete orders[i]; // single pointer delete operator
}
delete[] orders; // array of pointers delete operator

 

OT but had to chime in.

The above code is not exception safe and any decent professor should deduct serious points for this. When any of the memory allocations in the for loop fail and throw "std::bad_alloc", all already sucessfully allocated memory is leaked. Use RAII to wrap the pointers (for example: std::unique_ptr) or use std::vector for the array to avoid using new.

Link to comment
Share on other sites

Link to post
Share on other sites

@Mr_KoKa hey, i am stuck on the same problem, is there any more input you could give me, i am trying to search the letters in each line: this is the logic i used:


void count_msg_types(Order **& orders, int num_orders) {
    int x =0;
    int y = 0;
    int z = 0;
    int c= 0;
    for (int i = 0; i < num_orders; i++)
    {
        if (*num_orders[i] == 'A')
        {
            for (int a = 0; a < num_orders; a++)
                z = a;
        }
        if (*num_orders[i] == 'M')
        {
            for (int a = 0; a < num_orders; a++)
                x = a;
        }
        if (*num_orders[i] == 'D')
        {
            for (int a = 0; a < num_orders; a++)
                y = a;
        }
        if (*num_orders[i] == 'D')
        {
            for (int a = 0; a < num_orders; a++)
                c = a;
        }
    }

    cout << "Add Msg" << z << "Modify Msg" << x << "Delete Msg" << y << "Clear Msg:" << c >> endl;
    //Fill me in
}

Link to comment
Share on other sites

Link to post
Share on other sites

num_orders is integer and you're using it as some kind of pointer, or even array of pointers. Tell me what exactly you want to do, do you want to count messages by msg_type?

(I have never seen your order.h - it may help if you paste its contents here)  You probably should go through orders.

 

(Just noticed you're not op, but I guess you have the same assignment)

Link to comment
Share on other sites

Link to post
Share on other sites

@Mr_KoKa this is the output that I want:

MsgType: A Symbol: YHOO Side: B Quantity: 10 Price: 12.94 OrderId: 12345

MsgType: A Symbol: YHOO Side: A Quantity: 11 Price: 12.98 OrderId: 98709

MsgType: A Symbol: YHOO Side: B Quantity: 9 Price: 12.95 OrderId: 74658

MsgType: M Symbol: YHOO Side: B Quantity: 50 Price: 12.95 OrderId: 74758

MsgType: A Symbol: YHOO Side: A Quantity: 10 Price: 12.99 OrderId: 89097

MsgType: M Symbol: YHOO Side: A Quantity: 100 Price: 12.9 OrderId: 98709

MsgType: D Symbol: YHOO Side: B Quantity: 100 Price: 12.98 OrderId: 12345

Add Msg: 4 Modify Msg: 2 Delete Msg: 1 Clear Msg: 0

the order.h


#ifndef Order_h
#define Order_h

class Order {

   private:
       char * sym; //symbol of the order
       char side; //B for Bid A for Ask
       double price; //decimal points
       int quantity; //full number
       char message_type;//A for Add, M for Modify, D for Remove, C for Clear, will explain later
       int order_id; //full integer
   public:
       Order(); //default constructor, default private variables to respective defaults, 0's for nums, NULL for char arrays, NULL terminator for char
       Order(char * s, char bs, double p, int q, char mp, int oid); //assign variables with parameters given by the user
       ~Order(); //if there is any variables that are made dynamically release there memory look at rectangle_example_dynamic.cp for assistance
       bool set_symbol(char * s); //look at Examples/Week2/rectangle_example_dynamic.cpp for assistance
       bool set_side(char s); //set to new side
       bool set_orderid(int oid);//set to new orderid
       bool set_message_type(char mp); //set to new message_type
       bool set_quantity(int q); //make sure if quantity is <= 0 print a statement saying 'Can Not be less or equal to 0' return false otherwise set it return true
       bool set_price(double p); //make sure if price is <= 0.0 print a statement saying Can not be less or equal to 0.0 return false other set it return true
       char * get_symbol(); //return said var
       char get_side(); //return said var
       double get_price(); //return said var
       int get_quantity(); //return said var
       void write_console(); //make sure ALL variables are present, meaning they are not 0, 0.0, NULL, or \0 print a statment that looks like example
       //MsgType: A Symbol: AAPL Side: B Quantity: 200 Price: 238.90 OrderId: 123345
       //else print not all data points are available can't print!
        char get_message_type(); //return said variable
        char get_order_id(); //return said variable
};
#endif 

 

Link to comment
Share on other sites

Link to post
Share on other sites

Ok, so I assume you already read orders and populated that array of orders (Order **orders).

 

so now you know how many orders you have (num_orders) and you have your orders array, to go trough it you need a loop

f

int count[4] = {0, 0, 0, 0};
for(int i = 0; i < num_orders; i++){
  switch(orders[i]->get_message_type()){
    case 'A':
      count[0]++;
      break;
      
    case 'M':
      count[1]++;
      break;
      
    case 'D':
      count[2]++;
      break;
      
    case 'C':
      count[3]++;
      break;
      
    default:
      std::cout << "Unknown message type: " << orders[i]->get_message_type() << std::endl;
  }
}

So since you have 4 types of message, you need 4 integers to count each of them. I defined array of 4 integers, each initialized with 0, then just iterating through orders and adding one to counter it belongs. You can make yourself enum with constants that MESSAGE_TYPE::MT_A = 0, MESSAGE_TYPE::MT_M = 1, and so on, and use it as indexes, so you don't need to remember which index is count of what type of message, you just access it by "name".

Link to comment
Share on other sites

Link to post
Share on other sites

@Mr_KoKa

thank you, this helps so much, one more question i keeep getting a 'sym' error with one of my variables. 


int main() {
    ifstream fin; //file stream
    char temp[200]; // use this in order to go through file reading
    int num_orders = 0; //get the first line that has how many orders you have
    int quantity; // holds quantity for order object
    int orderid;  //holds orderid for order object
    char msg_type; //holds msg_type for order object
    char side; //holds b or a for bid or ask for order object
    double price; //holds price for order objects
    char * sym; //holds symbol for order object
    Order ** orders; //dynamic array that holds dymanic order object
    bool res;

    fin.open("orders.txt");//opens orders.txt    
    fin.getline(temp, 200, '\n');//gets the first line of text which is the number of orders
    fin >> num_orders; // creates num_orders
    cout << "Number of Orders: " << num_orders << endl;// prints the number of orders in a text file

    orders = new Order *[num_orders];//creates the array
    if (fin.is_open()) { //if the file stream is open
        for (int n = 0; n < num_orders; n++) {//iterates through the array
            res = static_cast<bool>(fin.getline(temp, 2, ',')); //There is 2 because you have to have space for 1 character for msg_type and one char for terminating NULL
            if (res) {
                //getline successfuly read 1 character and encounter ',' sign
                //our temp array contains now msg_type
                msg_type = temp[0]; 

                res = static_cast<bool>(fin.getline(temp, 2, ','));
                if (res) {
                    *sym = temp['\0'];
    
                res = static_cast<bool>(fin.getline(temp, 2, ','));
                if (res) {

                    side = temp[0]; 
                res = static_cast<bool>(fin.getline(temp, 200, ','));
                if (res) {
                    price = atof(temp);

                    res = static_cast<bool>(fin.getline(temp, 200, ','));
                    if (res) {
                        quantity = atoi(temp);
                    res = static_cast<bool>(fin.getline(temp, 200, ','));
                    if (res) {
                        orderid = atoi(temp);
                            }
                        }                
                    }
                }
            }/* else {
             //',' didn't occured after first character (or other read error occurred)
             }*/

            if (!res) {
                std::cout << "There was problem with data" << std::endl;
                return 1;
            }
            for (int i = 0; i < num_orders; i++) {
                delete orders[i]; // single pointer delete operator
            }
            delete[] orders; // array of pointers delete operator

            return 0;
        }

        
    }
    
}

Link to comment
Share on other sites

Link to post
Share on other sites

res = static_cast<bool>(fin.getline(temp, 2, ','));
                if (res) {
                    *sym = temp['\0'];

This part doesn't look too good, (beside your indentation is odd, and code isn't easy to read). sym is char poitner, and since it was declared here

    char * sym; //holds symbol for order object

It hasn't been nowhere defined, which means it doesn't points to anything or it contains some garbage data and points randomly, so when you do *sum = you assigning somthing to memory that sym points to (it points nowhere, or randomly so it means troubles).

 

Second thing is that symbol is at least (or exactly) 4 characters (eg. "YHOO"), and you're getline 2 characters which means 1 character and terminating null of returned cstring, You would need to increase this one to 5.

 

Third thing, that weird contraption of yours temp['\0'] is equal to temp[0]; cause '\0' is null character - so 0. So you're copying first character. What you would need to do is to define sym as 

sym = new char[5];

and then after you successfully read 4 characters of a symbol and encounter coma sign, which means getline will return true (not exactly, it returns stream but casted its operator overload makes it return failbit state, so in boolean context it is true for no error, and false for error when reading). then you can copy that 4 characters from temp to sym with memcpy function, like:

memcpy(sym, temp, 5);

It will copy all 4 characters with null terminating that makes valid cstring.

 

Despite all of above, you still have no single order allocation. And you are not populating those orders, so you cannot iterate trough them yet.

 

You want to allocate each order pointer in your orders array. so at the beginning your for(int n = 0 ... loop you want to add allocation, like so:

for (int n = 0; n < num_orders; n++){
   
  // Reading to variables;
  
  // Your Order class has constructor that accepts all data you read from file as arguments
  // Order(char * s, char bs, double p, int q, char mp, int oid);
  // But I would need order.cpp (or order.c) file to make sure what bs and mp is, I guess bs is side, and mp is msg_type
  // I also wonder if that class takes care of symbol allocation, deallocation and assignment. I can tell after I see the code.
  orders[n] = new Order(sym, side, price, quantity, msg_type, orderid); //You would wrap it with try catch block to handle bad_alloc exception
  
  // If anything goes wrong you would need free only what has ben allocated to this point before you terminate it.
  // But Iwould focus on making porgram work at first.
}
  

 

 

Link to comment
Share on other sites

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×