c++, get phone number from txt file - c++

I'm trying input a phone number in the format: 555-555-5555 into a struct with three int's. I've tried using getline with a delimiter of "-", but I keep getting the error: "cannot convert parameter 1 from 'int' to 'char *'".
I tried creating a temp char* variable to store the number in and then type casting it to int, but that didn't work.
How should I go about doing this?
Thanks
edit:
here's some of the code:
void User::Input(istream& infile) {
char* phone_temp;
...
infile.getline(phone_temp, sizeof(phoneNum.areaCode), "-");
phoneNum.areaCode = (int)phone_temp;
...
}

Since you are posting this as a c++ question, and not a c question, Use istringstream
http://www.cplusplus.com/reference/iostream/istringstream/
From my head it your code would become something like:
std::string sPhoneNum("555-555-5555");
struct
{
int p1;
int p2;
int p3;
} phone;
char dummy;
std::istringstream iss(sPhoneNum);
iss >> phone.p1; // first part
iss >> dummy; // '-' character
iss >> phone.p2; // second part
iss >> dummy; // '-' character
iss >> phone.p2; // last part
EDIT:
now that you have posted example code, I see you already start with an istream, you can just use the >> operator directly, no need to create another istringstream operator. See examples: http://www.cplusplus.com/reference/iostream/istream/operator%3E%3E/
Also, stay away from c-style conversion methods with char * and atoi stuff if you don't have to, working with std::string and istreams is the "right" C++ way. It avoids memory leaks and other nasty problems.

Reading a phone number from a stream:
Assuming the number is well formatted:
void User::Input(istream& infile)
{
int part1;
int part2;
int part3;
char dash1;
char dash2;
infile >> part1 >> dash1 >> part2 >> dash2 >> part3;
/*
* !infile will return false if the file is in a bad state.
* This will happen if it fails to read a number from
* the input stream or the stream ran out of data.
*
* Both these conditions constitute an error as not all the values will
* be set correctly. Also check that the dash[12] hold the dash character.
* Otherwise there may be some other formatting problem.
*/
if ((!infile) || (dash1 != '-') || (dash2 != '-'))
{
throw int(5); // convert this to your own exception object.
}
}

if I understand correctly, try atoi() or stringstream to convert from char* to int

See this example on how you can tokenize the line. This question will also help.
Then use atoi to convert string to int.

You can't cast a char* to an int and expect a correct value. A char* is an address in memory, so when you cast it to int, you'll get a memory address in your int. You need to call a function, such as atoi() to algorithmically convert the data char* is pointing to into an integer.

Another viable option, although not quite C++, is:
char a[10],b[10],c[10];
scanf("%d-%d-%d", a, b, c);

It appears you're trying to convert a char to an integer, in which case you'd want to use the atoi function or a string stream.

rather than using infile.getline() use the free standing version with a std::string:
getfile(infile, buffer);
After that, if you'd like you can do an addition getline():
istringstream phonenumber(buiffer);
string areacode = getline(phonenumber, part1. '-');
or you can use the extractor >> (that's what it's for!)
int areacode;
phonenumber >> areacode;
Just a side note: if you're using char* do make sure you allocate space for it, or at least point to allocated space.

Related

How can I correctly convert this to hex?

I have an issue where I am trying to convert numbers to hex with the following code.
int numconvert(string hexnum)
{
stringstream converter(hexnum);
unsigned int value = 0;
converter >> hex >> value;
return value;
}
string hexconvert(int hexnum)
{
stringstream ss;
ss << hex << hexnum;
string n;
ss >> n;
return n;
}
I use the numconvert to change an input from string to int, then I use hexconvert, to change that into a hex and store it as a string.
Everything seems to work just fine but then for some reason, when I pass it 4096, it gives me back 4096. I was expecting 1000 but I am not sure why it is erroring out on me. I give it 4096 and I notice that it returns an int of 16534, then the program sends that over to the hexconvert and it returns 4096, which, technically is right, but not what I wanted.
It seems to handle other numbers just fine. What am I doing wrong here?
I think you got an logic error there. If you write:
int n = numconvert("4096");
std::string s = hexconvert(n);
you basically tell it to interpret "4096" already as hex number because you got converter >> hex >> value; inside numconvert, translating it back to hex would always lead to the same getting returned.
What you want is probably
int n = std::stoi("4096");
std::string s = hexconvert(n);
This will interpret "4096" as a normal base 10 number and then convert that to a hex string again using your hexconvert.
That said your numconvert can be written shorter and probably a bit more efficient using std::stoi too, it's basically just:
int numconvert(const std::string& str)
{
return std::stoi(str, nullptr, 16);
}
we don't need the second argument so we pass nullptr, the 3rd argument is the base.
Try using the str member instead of the extract operator, to eject the string from the stringstream. Besides being more direct, you don't have to worry about how the extractor further interprets things.

C++ Adapting sscanf code to istringstream with error checking

So I've got some code that splits a string into some other variables with sscanf that looks like this.
if(sscanf(input_line.c_str(), "%s %s %lf %lf %lf", &string1, &string2, &point1, &point2, &point3) != 5) {
//does stuff
throw;
}
I use the return value of sscanf to validate the input string.
I would use
istringstream ss(input_line);
ss >> string1 >> string2 >> point1 >> point2 >> point3;
if( ??????? ){
//does stuff
throw;
}
But I don't know how to verify if there were exactly 5 things populated. I'd love to get rid of the legacy C code as I loath char arrays but I don't want to lose the error checking. I'd very much appreciate any advice to adapt this istringstream code or use entirely different c++ style code to get rid of the char arrays but keep the existing functionality.
Thanks in advance,
Max
First of all remember that all input operator functions (>>) returns the input stream, and secondly remember that a stream can be used as a boolean condition.
This means you can do e.g.
std::string string1, string2;
double point1, point2, point3;
if (some_input_stream >> string1 >> string2 >> point1 >> point2 >> point3)
{
// All is okay
}
else
{
// One of the input operations failed
}
To know exactly which input operation failed, you can do them one at a time.

Using strtok in C++

I'm trying to read a file which has input(time and price) as: 12:23:31
67 12:31:23 78 [...] I created a struct which holds values of hour,
minutes and seconds. I used strtok to tokenize the individual values
and use atof to store them. However, I'm getting an error when I try
to tokenize the time: cannot convert std::string' to 'char*' for argument 1 to 'char*'
struct time
{
int hours;
int minutes;
int seconds;
double price;
};
int main()
{
string file, input;
time* time_array;
char* tok;
cout << "Enter a file name to read input: ";
cin >> file;
ifstream file_name(file.c_str());
file_name >> input;
file_name >> input;
//while(!file_name.eof())
for(int i = 0; i < 4; i++)
{
time_array = new time;
file_name >> input;
tok = strtok(input, ":"); //ERROR HERE
while(tok != NULL)
{
*time_array.hours = atof(tok[0]);
*time_array.minutes = atof(tok[1]);
*time_array.seconds = atof(tok[2]);
}
file_name >> input;
*time_array.prine = atof(input);
}
}
I would not use strtok for this job at all1. If you want to use C-like tools, then read the data with fscanf:
// note there here `file_name` needs to be a FILE * instead of an ifstream.
fscanf(file_name, "%f:%f:%f %f", &hours, &minutes, &seconds, &price);
Most people writing C++ would prefer something more typesafe though. One possibility would be to use essentially the same format string to read the data using Boost.format.
Another possibility would be to use stream extractors:
char ignore1, ignore2;
file >> hours >> ignore1 >> minutes >> ignore2 >> seconds >> price;
As to what this does/how it works: each extractor reads one item from the input stream. the extractors for float each read a number. The extractors for char each read one character. In this case, we expect to see: 99:99:99 99, where 9 means "a digit". So, we read a number, a colon, a number, a colon, a number and another number (the extractor skips whitespace automatically). The two colons are read into char variables, and can either be ignored, or you can check that they really are colons to verify that the input data was in the correct format.
Here's a complete, compileable demo of that technique:
#include <iostream>
int main() {
float hours, minutes, seconds, price;
char ignore1, ignore2;
std::cin >> hours >> ignore1 >> minutes >> ignore2 >> seconds >> price;
std::cout << "H:" << hours
<< " M:" << minutes
<< " S:" << seconds
<< " P:" << price << "\n";
return 0;
}
There are certainly a lot more possibilities, but at least those are a few reasonable ones.
To be honest, I'm not sure there's any job for which I'd use strtok, but there are some where I might be at least a little tempted, or wish strtok weren't so badly designed so I could use it. In this case, however, I don't even see much reason to use anything similar to strtok at all.
strtok doesn't take a string as its argument - it takes a char*. Like all functions in the cstring header it's a C function that works with C strings - not C++ strings - and should generally not be used in C++.
Use the methods of the string class instead.
The short answer is that you cannot directly use a std::string with strtok, as strtok wants a string it can modify. Even if you use c_str() to get a C-style string from a std::string, it is still read only.
If you really want to use strtok, you need to duplicate the string into a modifiable buffer, for example by:
char* str = strdup(input.c_str());
If you do this, make sure you call free(str) at the end of the function, else you will get a memory leak!
Your simple case can easily be built using the string::find method. However, take a look at Boost.Tokenizer.
strtok will not work with std::string.c_str() because it returns const char*. strtok does not take a string as an argument, but rather a char*.

Extract arbitrary data values from a std::string C++

I have strings like this
10z45
9999i4a
Basically int-char-int-optionalchar
I want to do this function prototype
void process(std::string input, int &first, char &c, int &last, bool &optional)
Only thing is I'm not sure the best way to iterate over the string to extract these values. Would rather not use regex library, seems like can be done simply?
Use a string stream:
#include <sstream>
...
std::istringstream iss(input);
iss >> first >> c >> last >> optional;
If there's no final character, the value of optional won't be touched, so I'd recommend setting it to 0 beforehand.
Use std::istringstream, read int, char, int, then try next char:
std::istringstream is(input);
is >> first >> c >> last;
char c2;
optional = (is >> c2);
I'm not sure this is 100% what you want -but I'd do it in this way.

Get size of input in console

How would you get the size input string to console or size of valid characters in buffer?
char buffer[100];
cin >> buffer;
I'm looking to put the '\0' where the input ends.
Prefer using std::string, instead of char* or char[]. That makes such things easy! The problem with char buffer[100] is that if the size of input string is more than 100, then your cin >> buffer would invoke undefined behavior, as it would attempt to write beyond the array. This problem can easily be avoided if you use std::string.
std::string input;
cin >> input; //this can read string of any unknown size!
cout << "length of input string : " << input.size()<< endl;
You can also use input.length() instead of input.size(). They return the same value.
Online Demo : http://www.ideone.com/Wdo31
The question is moot. When the user types more than 100 characters, you have a buffer overrun. You may crash. If not, you got a security issue at best. You shouldn't do this. Read the input a character at a time, or use a safer string library. gets_s comes to mind if it's supported on your platform.
But in answer to your question, this might be what you need:
char buffer[100] = {}; // zero-init the entire array
int length = 0;
cin >> buffer;
length = strlen(buffer); // length is the length of the string
You don't need to (and quite possibly, can't). Instead, use a std::string instead of a char buffer.