stream buffer (cin, getline, etc) - c++

Is there a way to have the user input a line of characters to the stream buffer and then store them in different variables (of different types)?
For example, the user writes this sum of fractions:
1/5 + 2/7
I have 5 variables:
int numerator1, denominator1, numerator2, denominator2; char operat;
and after doing a fancy piece of code that i don't know, in the end, the variables will have stored the following
numerator1 = 1
denominator1 = 5
operat = +
numerator2 = 2
denominator2 = 7
Any suggestions?

You should definitely use the ASTs as they would help you parse the errors. But if you are looking for a simple parsing capabilities you can consider using sscanf. PS: Posting it as an answer due to reputation problem.
#include<cstring>
#include<cstdio>
#include<iostream>
using namespace std;
int main()
{
char s[1024];
scanf("%s", s);
int n1, n2, dn1, dn2;
char op1, op2, op3;
sscanf(s, "%d%c%d%c%d%c%d", &n1, &op1, &dn1, &op2, &n2, &op3, &dn2);
cout<<"\n"<<n1<<" "<<op1<<" "<<dn1<<" "<<op2<<" "<<n2<<" "<<op3<<" "<<dn2<<endl;
}

Well, I am not sure of the specific algorithms, to attain this functionality, But i can suggest the following.
instead of using multiple variables, Take an integer array and a character array.
Take the input from the user in a string.
Loop through the character string and perform the following.
If, the value at current index is a num, Iterate counter until you
find a space or an operator (+/-*)
Extract the sub sting of it and store it in int array at the
corresponding index.
if the value at an index is an operator, store it in char array.

Related

Unable to ignore the escape characters from a text file stream & store in a wchar_t [ ] in C++

I am trying to read data from a text file using C++ & store the strings at each line into wchar_t [] or LPCWSTR.
(These 2 datatypes are the constraints of the application on which I am working. That's why I have to store the data in these datatypes)
The format of data in the .txt file is, for example:
abc\\def\\ghi 10
jkl\\mnopq\\rstq 20
aqq\\sdsds\\qc 30
I am trying to read data line by line & save each line as a map's key-value pair, where key is of type LPCWSTR or wchar_t[] type & value is of int type
There is no issue in extracting int, but the issue comes in reading the strings
Here is my code:
#include<iostream>
#include<fstream>
#include<windows.h>
#include<cstdlib>
using namespace std;
int main()
{
wchar_t test1[260];
const char* s = "Hello\\ABC\\DEF";
mbstowcs(test1, s, strlen(s));
wcout<<test1<<endl;
wchar_t gr[260];
string gr_temp;
int percentage;
ifstream ifs;
ifs.open("data.txt", ifstream::in);
if (ifs.is_open()) {
while (ifs >> gr_temp >> percentage){
const char* source = gr_temp.c_str();
mbstowcs(gr, source, strlen(source));
wcout<<gr<<L" ";
cout<<percentage<<endl;
}
ifs.close();
}
return 0;
}
However, it is giving the following output:
Hello\ABC\DEFa
abc\\def\\ghi 10
jkl\\mnopq\\rstq 20
aqq\\sdsds\\qc 30
I did not understand why that tiny 'a' appeared out of nowhere in the first line of output
I want the code to instead automatically process those double slashes, i.e. I want the output as:
Hello\ABC\DEF
abc\def\ghi 10
jkl\mnopq\rstq 20
aqq\sdsds\qc 30
It would be even best if I could instead write the entries in the .txt file without double slashes & they get automatically processed without checking for any escape sequences. However, since the issue as in point no. 1) above is there, so I am not sure if it is even possible
Even if add cout<<gr_temp<<endl; as the first line in the while loop, even that also outputs the string with double backward slashes.
What am I missing or doing wrong?
Update:
Also, when I add these key-value pairs to a std::map<LPCWSTR,int> m1 using the statement m1[gr] = percentage; at the end of each while loop, then with the print statement, it only shows one single element in the map.
My updated code is:
#include<iostream>
#include<fstream>
#include<windows.h>
#include<cstdlib>
#include<map>
using namespace std;
std::unordered_map<LPCWSTR, int> m1;
int main()
{
wchar_t test1[260];
const char* s = "Hello\\ABC\\DEF";
mbstowcs(test1, s, strlen(s));
wcout<<test1<<endl;
wchar_t gr[260];
string gr_temp;
int percentage;
ifstream ifs;
ifs.open("data.txt", ifstream::in);
if (ifs.is_open()) {
while (ifs >> gr_temp >> percentage){
const char* source = gr_temp.c_str();
mbstowcs(gr, source, strlen(source));
m1[gr] = percentage;
}
ifs.close();
}
for (auto i = m1.begin(); i != m1.end(); i++) {
wcout<< i->first << L" ";
cout<< i->second << endl;
}
return 0;
}
This code is only adding 1 element in the map & that is the most recent added element.
I edited the code to use unordered_map, but still the same issue.
I further tried to print the size() of the map. In both these cases, size of map m1 was displayed as 1.
Miles Budnek already stated your problems.
If you look at the documentation of your function (http://www.cplusplus.com/reference/cstdlib/mbstowcs/), you will see that the third parameter does not expect the number of bytes to translate to wchar_t, but much rather the maximum number of characters the buffer you are pointing to can hold.
It will stop once it finds a \0 (which just happens to be what strlen is also looking for).
So just replace the third parameter of your first mbstowcs call with 260 (or sizeof(test1)/sizeof(wchar_t) and you're good on that stray 'a'.
As has also already been stated, there are no 'escape parameters' while reading from a file.
These only exist in source code and represent ASCII codes you cannot type. (https://www.asciitable.com/)
\n for example represents the codesign for 'new line' 0x0A.
So escaping the backslashes in the file is unnecessary and can be skipped.
If you know that your input file will have 'double backslashes' and need to 'unescape' them, you could look at the std::string functions 'find' and 'replace'.
Find "\\\\" (two backslashes in a row) and replace with "\\".
In response to your updated question (which is basically another question):
The problem is the key you chose for the map.
Each map, unordered or not, requires unique keys and in your scenario, you keep using the same key.
LPCWSTR expands to 'Pointer to Wide Char String', so while you probably think you are using 'abc\def\ghi' as key, you are actually using &gr[0], which remains the same during all iterations.
As an additional result, once the program leaves the scope of gr, its content becomes invalid and accessing the map (which maintains the pointer but not the content), will access freed memory which tends to crash your program.
The solution as such is simple enough though: You need to use the content as key, instead of the pointer, for example by using a container object like std::wstring.

12 hour to 24 hour time conversion

I am trying to write this c++ program from hackerrank but in my output all I am getting is a blank space.
The input string is in the form of HH:MM:SSpp where HH is an hour on two digits with leading zero, MM the minutes, SS the seconds and pp is either AM or PM.
#include <bits/stdc++.h>
#include<iostream>
#include<string>
using namespace std;
string timeConversion(string s)
{
string p;
int i,j;
if(s[8]==80){ // checking if it is AM or PM
int x = s[0]*10 + s[1] +12;
int y = x%10;
int z = x/10;
s[0]= z;
s[1]= y;
for(i=0;i<10;i++){
p[i]=s[i];
}
}
string newt= p.substr(0, p.size()-2); //removing last two characters
return newt;
}
int main()
{
ofstream fout(getenv("OUTPUT_PATH"));
string s;
getline(cin, s);
string result = timeConversion(s);
fout << result << "\n";
enter code here
fout.close();
return 0;
}
Is there some logical error? I know the other approach for this question but it would be great if anyone could help me with it.
The problem is with treating character digits (e.g. s[0]) as integer digits.
If you are certain you are dealing with digits, the way to do arithmetic with the characters is by subtracting the value of the character '0', like so: s[0] - '0'. The result will be the integral digit.
The main problem
In your timeConversion() function, you define a string p, which is initialized by the string default constructor to "".
Now for AM times, you skip the if and go directly to string newt= p.substr(0, p.size()-2);, which on an empty p will just create an empty newt string. So you return an empty value. Every time !
For PM times, you go into the if to do some transformations. Unfortunately p[i]=s[i]; doesn't do what you think. In fact it is out of bound access in the empty p string. And in the end, the length of p will still be 0 which will cause an empty value to be returned (in the best case).
The start of a solution
Initialize p at construction:
string p=s;
The code will then immediately work for AM strings. For PM strings, you still need to take into account uv_ 's answer related to ascii vs. binary math.
Here the result:
string timeConversion(string s)
{
string p=s;
int i,j;
if(s[8]=='P'){ // checking if it is AM or PM
int x =(s[0]-'0')*10 + (s[1]-'0') +12;
p[0]= x/10 +'0';
p[1]= x%10 +'0';
}
return p.substr(0, p.size()-2); //removing last two characters
}
Note: this assumes that the entry format will always be valid, and no space will be used instead of a leading 0.
Important Note: This code will fail on hackerrank, because it transforms 12:15:00pm into 24:15:00 and not in 12:15:00. Furthermore 12:00:00am will be tranformed in 12:00:00 instead of 00:00:00. More on wikipedia. Online demo about how to address these special cases
This code will work considering all test cases, just added two more conditions.
string timeConversion(string s)
{
string ans=s;
if(ans[8]=='P')
{
int x = (ans[0]-'0')*10+(ans[1]-'0')+12;
//cout<<x;
if(x!=24)
{
ans[0]=x/10+'0';
ans[1]=x%10+'0';
}
}
if(ans[8]=='A')
{
int y=(ans[0]-'0')*10+ans[1]-'0';
if(y==12)
{
ans[0]='0';
ans[1]='0';
}
}
return ans.substr(0, ans.size()-2);
}

Null terminator carrying through when indexing string

I am trying pull specific characters from a string array, and assign them to defined indices in a new variable. I am having issues with what I expect is the null terminator, as there appear to be random assortment of undefined characters at the end of my strings.
I am new to coding in C++, and lower level programming in general. Note that the function "charBi" works perfectly, but it no longer works when assigning the output of "charBi" to the variable "binar" in the "strBi" function. I realize the code is probably not great, but any help is welcome, especially as it relates to getting rid of the random characters at the end of my "binar" string.
Thanks!
#include <iostream>
#include <array>
using namespace std;
//Program meant to output a string of binary for an input word or phrase
//library of letter and binary pairs
char letterNumber[27][10]={"A01000001","B01000010","C01000011","D01000100","E01000101","F01000110","G01000111",
"H01001000","I01001001","J01001010","K01001011","L01001100","M01001101","N01001110",
"O01001111","P01010000","Q01010001","R01010010","S01010011","T01010100","U01010101",
"V01010110","W01010111","X01011000","Y01011001","Z01011010"," 01011111"};
//finds binary number associated with input character. One character input
string charBi(char inputVar){ //WHY DOES THIS ONLY WORK IF THE FUNCTION IS A STRING?
//loop setup
int n=0;
int last=sizeof(letterNumber)/sizeof(letterNumber[0]); // equal 27
//loops through each of the strings in letterNumber
while (n!=last) {
if (letterNumber[n][0]==inputVar){ // if the letter is equal to input letter
char bina[8]; //number of numbers following a letter
for(int i=1;i<9;i++){ // writes the number associated with the letter to bina
bina[i-1]=letterNumber[n][i]; // assigns number to specific index
}
return bina; //BINA DEFINED AS CHAR, BUT OUTPUTTING AS STRING
}
n++;
}
}
//forms binary string of numbers for input phrase
string strBi(string strg){ //WHY DOES THIS ONLY WORK IF THE FUNCTION IS A STRING?
char binar[8*strg.length()]; //binary for each character is 8 numbers long
for(int i=0;i<strg.length();i++){ // for every letter in the input phrase
string chbi=charBi(strg[i]); //gets binary for individual letter from charBi function
cout<<"charbi sends: "<<chbi<<endl; //for debugging
for(int n=0;n<8;n++){ //for every 1 or 0 in the binary for an idividual letter
binar[(8*i)+n]=chbi[n]; // assign in order to string binar
}
cout<<"binar updates to: "<<binar<<endl; //for debugging
getchar(); //for debugging
}
return binar; //BINAR DEFINED AS CHAR, BUT OUTPUTTING AS STRING
}
int main(){
cout<<"final string is: "<<strBi("HELLO WORLD");
return 0;
}
Since you didn't properly terminate your arrays, the program is undefined.
In order to store a k-letter string, you need to use a k+1-element array and terminate it – char bina[9] = {}; and char binar[8*strg.length() + 1] = {}; should do the trick.
But you can simplify things a bit by leaving C behind:
std::map<char, std::string> letterNumber =
{{'A', "01000001"},
{'B', "01000010"},
// ...
{' ', "01011111}"}};
//forms binary string of numbers for input phrase
std::string strBi(const std::string& strg)
{
std::string binar;
binar.reserve(8 * strg.size());
std::for_each(strg.begin(), strg.end(), [&binar](char c) { binar += letterNumber[c]; });
return binar;
}
Make binar one character longer (char binar [8 * strg.length() + 1];) and set the last character to NUL (just before returning, do binar[8 * strg.length()] = '\0';)

make user enter a string of integers and output a different string

hi i am having trouble starting this program as i am new and have no idea how to use loops to construct this thanks
here are the directions:
For this assignment, write a program named assignment2 (source is the same name with .cpp extension) to
prompt the user for an integer value (ignore negative values) and then output this value using the following rules:
Each digit within the integer value is to be displayed the same number of times as the value of the digit
itself, with one exception...the digit 0 will be displayed once, like the digit 1.
Separate each string of digits using a single dash character.
For example:
If the input value is 120473, the display should look like:
1-22-0-4444-7777777-333
If the input value is 5938061, the display should look like:
55555-999999999-333-88888888-0-666666-1
In addition, ask the user if they would like to retry using another integer value. If so, repeat the above. End the
program when the user chooses to quit (does not want to retry).
This assignment is an exercise in using the following:
Unary Operators:
! ++ --
Binary Operators:
+ - * / % && ||
Data types:
bool
char
int
enum
Flow control:
if-else
switch
do-while loop
while loop
for loop
In addition, you are allowed to use any necessary functions provided by the Math library. To include the Math
library, add the following line to your list of include statements:
#include <cmath>
For most digit manipulation assignments, I recommend treating the number as a string of characters rather than as a number.
The Foundation
Let's start with the foundation:
#include <iostream>
#include <string>
#include <cstdlib>
using std::cout;
using std::cin;
using std::getline;
int main(void)
{
cout << "Paused. Press Enter to continue.\n";
cin.ignore(100000, '\n');
return EXIT_SUCCESS;
}
The above program will hopefully keep the console (terminal) window open until the Enter key is pressed.
Getting The Input
We'll ask the User for a number, this is also known as prompting:
// The prompt text doesn't change so it's declared as const.
// It's declared as static because there is only one instance.
static const char prompt[] = "Enter a number: ";
cout.write(prompt, sizeof(prompt) - 1U); // Subtract 1 so the terminating nul is not output.
// Input the number as text
string number_as_text;
getline(cin, number_as_text);
Printing The Digits
Really, before this step, you should verify that the text only contains numbers. Repeat the prompting until the User inputs nothing or valid data.
A string can be accessed as an array. So we'll set up a loop:
const unsigned int length = number_as_text.length();
for (unsigned int index = 0U;
index < length;
++index)
{
// Extract the digit.
const char c = number_as_text[index];
// Verify it is a digit.
if (!isdigit(c))
{
continue;
}
unsigned int quantity = c - '0'; // Convert to a number.
if (quantity == 0) quantity = 1; // The requirements lie, for zero there is a quantity of 1.
// Use "quantity" to print copies of the character.
}
cout << "\n";
Stuff
I'm not going to write the entire program for you, as you haven't paid for my services. So you will have to figure out when to print the '-' and how to print many copies of the digit.
If this answer is not correct, please update your question with some clarifications or restrictions.

Want to read important double value at the end of line of istream C++

I'm trying to read in a large matrix calculated from a text file for a finite element code. The matrix is spatially dependent though and thus I need to be able to conveniently organize the data. The outside source that calculated the values for the matrix was kind enough to put the following lines at the top of the text file
No. activity levels : 3
No. pitch-angles : 90
No. energies : 11
No. L-shells : 10
Which basically tell me the number of positions the matrix is known at. I want to be able to easily pick out these values because it will allow me to preallocate the size of the matrix, as well as know immediately how much I need to interpolate for values not given by this text file. I am trying to do that with the following code
#include<iostream>
#include<fstream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<vector>
using namespace std;
int main(){
string diffusionTensorFileName = "BAS_drift_averaged_chorus_kp.txt";
string sline;
int alphaSize=0;
ifstream diffusionTensorFile(diffusionTensorFileName.c_str());
while(getline(diffusionTensorFile,sline)){
if(strncmp(sline.c_str(),"No. pitch-angles : 90",sline.size()-1)==0 && sline.size()-1 != 0){
alphaSize = atoi(sline.c_str());
printf("alphaSize %d \n", alphaSize);
vector<double> alpha(alphaSize);
}
}
}
atoi of course doesn't work very well, and I can't seem to get strtod or any of those functions to work either. Any thoughts? I'm also open to this being the completely wrong way to do this and alternate suggestions on how to proceed.
I think the easiest way would be to use the scan_is method of the std::ctype facet imbued in the streams locale. Its job is to search for first character that matches a given classification and return a pointer to it. We'll take the result of that call and use std::stoi (C++11) to parse it into an integer.
std::locale loc(diffusionTensorFile.getloc());
auto& f = std::use_facet<std::ctype<char>>(loc);
while (std::getline(diffusionTensorFile, sline))
{
const char* begin = sline.front(),
end = sline.back() + 1;
const char* result;
if ((result = f.scan_is(f.digit, begin, end)) != end)
{
alphaSize = std::stoi(result);
// do something with alphaSize
}
}
Live Demo