Strings and user input C++ - c++

I'm supposed to read an integer n from the user, which is the followed by n words, and then what follows after that is a sequence of words and punctuation terminated by the word END. For example:
2 foo d
foo is just food without the d . END
The n words are to be "redacted" from the second line. So it would show up as:
*** is just food without the * .
I think I can figure out the redacting part. I just cannot seem to figure out how to read the words in... any help is much appreciated!
#include <iostream>
#include <string>
using namespace std;
int main()
{
int n;
cin >> n;
string *redact = new string[n]
for(int i = 0; i < n; ++i)
cin >> redact[i] // this part works!
return 0;
}

Following code will cater the purpose.
#include <iostream>
#include <string>
#include <set>
int main()
{
int n;
std::cin >> n;
std::set<std::string> redact;
std::string word;
for(int i = 0; i < n; ++i)
{
std::cin >> word;
redact.insert(word);
}
while( std::cin>> word && word != "END" )
{
if ( redact.find(word) == redact.end() )
std::cout<<word<<' ';
}
std::cout<<'\n';
return 0;
}
I believe you are a learning C++, please note a point use typesafe, bound-safe and scope-safe C++.
So, no new delete unless you can call yourself an adept. Use the algorithms and containers provided by C++, instead of inventing your own.

Related

How to know the number of digits in an integer

I'm new to programming, and I'm wondering, how can I know the number of digits in an integer that the user enters? For example: the user enters a number like 123456, how can I know that the user enters 6 digits? I don't want to use a for loop to get user input because I don't want the user to enter each digit after a space or enter.
Right now, I'm converting a number to an array of digits so I can have control over them, but the issue is that I don't know how many digits I should loop over, because I don't know how many digits are in the number.
Can I get the user's input as a string and then use string.length and convert it to an array of digits?
#include <iostream>
using namespace std;
int main()
{
int N;
cin >> N;
while(N--)
{
int num;
cin >> num;
int arr[1000];
for (int i=0 ;i<???;i++)
{
arr.[i]=num%10;
num = num /10;
}
}
}
an easier way to do this is to convert it to a string then count the length of said string
#include <iostream>
#include <string>
using namespace std;
int main() {
int n;
cin >> n;
string str = to_string(n);
cout <<"the length of" <<str << "is:" <<str.length() <<"\n";
}
typing in a 41 will print out.
the length of 41 is 2
while (num != 0)
{
arr.[i]=num%10;
num = num /10;
}
is a common pattern that's close to what you already have.
Although you can do what you mentioned in your question and someone suggested in the comments and get the input as a string and use string.length.
Yes, you can read in the user's input as a std::string instead of as an int, and then you can use std::string::size() (or std::string::length()) to get the number of characters in the string, eg:
#include <iostream>
#include <string>
int main()
{
std::string S;
std::cin >> S;
int arr[1000] = {};
for (size_t i = 0; i < S.size(); ++i)
{
arr[i] = (S[i] - '0');
}
return 0;
}
Alternatively:
#include <iostream>
#include <string>
#include <algorithm>
int main()
{
std::string S;
std::cin >> S;
int arr[1000] = {};
std::transform(S.begin(), S.end(), arr, [](char ch){ return int(ch - '0'); });
return 0;
}
Either way, if needed, you can check if the std::string represents a valid integer using std::stoi() or std::strtol() or other similar function, or by putting the std::string into a std::istringstream and then reading an integer from it.
Otherwise, you can read the user's input as an int and then convert it to a std::string for processing:
#include <iostream>
#include <string>
int main()
{
unsigned int N;
std::cin >> N;
std::string S = std::to_string(N);
int arr[1000] = {};
for (size_t i = 0; i < S.size(); ++i)
{
arr[i] = (S[i] - '0');
}
// or:
// std::transform(S.begin(), S.end(), arr, [](char ch){ return int(ch - '0'); });
return 0;
}
Otherwise, if you really want to read in an int and loop through its digits directly, you can use something more like this:
#include <iostream>
int main()
{
unsigned int N;
std::cin >> N;
int arr[1000] = {};
size_t i = 0;
while (N != 0)
{
arr[i++] = num % 10;
num /= 10;
}
return 0;
}

Remove leading zeroes from Binary converted from Decimal

I am solving a problem where I have to convert given first N natural numbers to binary numbers. I am using bitset and .to_string(). But, after the number is converted to binary it has some leading zeroes obviously as equal to the size of the given bitset. The task is to remove that. I have done that using std::string:: erase() But I think it's not a good approach to do so. How can I optimize this part of the code?
#include <iostream>
#include <bitset>
#include <string>
int main()
{
int T;
std:: cin >> T;
while(T--) {
int n;
std:: cin >> n;
for(auto i = 1; i <= n; ++i) {
std::string binary = std::bitset<32>(i).to_string(); //to binary
//This part here
int j = 0;
while(binary[j] == '0') {
++j;
}
binary.erase(0, j);
//Till here
std::cout<<binary<<" ";
}
std:: cout << std:: endl;
}
return 0;
}
You could make use of the std::string::find_first_not_of() function to get the position of the first character that isn't a zero. Then use std::string::erase() to erase from the beginning of the string (index 0) to the position of the first non-zero character. This will avoid the while loop you're currently using.
Example:
std::string binary = std::bitset<32>(128).to_string(); //"00000000000000000000000010000000"
binary.erase(0, binary.find_first_not_of('0')); //"10000000"
std::cout << binary;
I would suggest to use log2 function from cmath header file. You can count the number of bits you would require to represent the integer in binary format with this. Thus you won't need the while loop used to count the number of leading zeroes.
Here is the code:
#include <iostream>
#include <bitset>
#include <string>
#include <cmath>
int main()
{
int T;
std:: cin >> T;
while(T--) {
int n;
std:: cin >> n;
for(auto i = 1; i <= n; ++i) {
std::string binary = std::bitset<32>(i).to_string(); //to binary
int len = log2(i)+1;
binary.erase(0,32-len);
std::cout<<binary<<"\n";
}
std:: cout << std:: endl;
}
return 0;
}
As john mentioned in the comment section, you not necessarily need to remove the number of leading zeroes. For that you can do this,
std::cout<<binary.substr(32-len,len)<<"\n";

Why can't I directly read from cin into an array index?

I'm trying to learn C++ on HackerRank, but I've encountered a weird situation in one of the exercises given.
The exercise is to read in a list of numbers and print them out reversed. However, my code appears to spit out garbage values for one of the test cases.
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
/* Enter your code here. Read input from STDIN. Print output to STDOUT */
int n;
int temp;
int *arr = new int[n]();
cin >> n;
for (int i = 0; i < n; i++) {
// This works
/*
cin >> temp;
arr[i] = temp;
*/
cin >> arr[i]; // But this doesn't
}
for (int j = n - 1; j >= 0; j--) {
cout << arr[j] << " ";
}
return 0;
}
The input for the offending test case was a bit long, so I put it into a pastebin: https://pastebin.com/VCjciUet
When reading directly from cin (i.e. cin >> arr[i]), the output was as follows:
6002 {...truncated...} 8084 3909 5426 808465952 942682421 540227121 824194360 909189169 959526176 825243441 540619576 891304241 842539056 825374240 960050744 540619575 958412851 892805173 808722489 960050720 959460408 540553528 891302967 926425141 909718304 859189816 540226104 941634871 842342452 808662048 809054519 540160311 891303224 875634745 808466464 876034355 540423990 958412593 925966391 892613920 808662321 540422194 958411319 840972592 876159030 825374752 926364977 540553273 874526514 924858416 876093495 875770144 858928434 540030771 941634360 875831350 959788576 842413112 540095796 874525239 959651892 959723040 842018869 540096056 874525751 540424244 908079412 859185206 960051232 875901235 540028978 924857392 926228532 808925216 959526195 540095028 908079408 960045108 825308448 942684471 540096306 840971065 858857522 892739637 926103072 842150707 540291892 941634608 875700275 876033824 909457721 540160822 824194100 859250740 825766688 875706678 540356912 840972345 875962418 808923936 825242421 540226869 924856887 892608560 825439520 909130037 540620083 857749813 943267896 943011360 925972531 540094773 840971319 825368627 808728608 808728374 540161588 908079666 842080313 909652512 876032561 540554040 941635895 808788017 808858144 825505842 540555320 840972344 892870710 825832480 842150450 540422199 874526264 909713464 892482592 926366005 540094769 924857396 842407992 892811040 875705656 540619320 908080177 857748528 875962423 909652256 892745779 540226866 540423479 540554291 540619064 540096820 891302709 926294071 808597792 892679200 909522745 540555315 924858417 891303988 909451315 859054128 909523232 942684473 540031287 857748019 808984630 959591456 925971510 540619057 958411316 909385783 825506080 858927392 808597810 540357168 908080176 909385778 858993440 875705632 892679737 540422960 924858672 875896883 875967520 842283065 540358967 908079669 859381815 943273248 825439288 540422969 908081465 926162994 925905440 959591735 540094512 824193335 859054130 875896889 876098848 959459892 540358706 540028977 2139 7277 9113 6303 924 7608 749 6043
However, the output was accurate (the entire list of numbers reversed) when I used a temporary variable first.
Why is this so?
It's so because you didn't listen to your compiler:
main.cpp: In function 'int main()':
main.cpp:13:27: warning: 'n' is used uninitialized in this function [-Wuninitialized]
int *arr = new int[n]();
^
Writing low-level code is prone to mistakes like those. Prefer high-level library features that prevent them. If your goal was to read a collection of numbers and print them out, it can be done without any loops at all:
#include <vector>
#include <iostream>
#include <algorithm>
int main() {
std::vector<int> v;
std::copy(
std::istream_iterator<int>(std::cin),
std::istream_iterator<int>(),
std::back_inserter(v)
);
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout));
}
This code will simply read until the numbers end. If you want to read the count of them first, you still should check whether they don't end beforehand. One issue with learning via things like HackerRank is that they completely omit learning input sanitization and error handling, which are crucial in real-world coding.
Turn on the compiler warnings:
source>:13:24: error: 'n' is used uninitialized in this function [-Werror=uninitialized]
13 | int *arr = new int[n]();
|
n was uninitallized when you used it. Also, you never deleted the array. Yes, the OS will clean up after you, but it is best to free the memory you allocated. Here's the fixed version:
#include <iostream>
int main() {
int n;
std::cin >> n;
int *arr = new int[n]();
for (int i = 0; i < n; i++) {
std::cin >> arr[i];
}
for (int j = n - 1; j >= 0; j--) {
std::cout << arr[j] << " ";
}
delete[] arr;
return 0;
}
Having said that, it's probably a better idea to use std::vector and std::size_t. Here's how you go about doing that:
#include <iostream>
#include <vector>
int main() {
std::size_t n{};
std::vector<int> vec{};
std::cin >> n;
vec.resize(n);
for (auto&& elm : vec)
std::cin >> elm;
for (auto rit = vec.crbegin(), rend = vec.crend(); rit != rend; ++rit)
std::cout << *rit << ' ';
return 0;
}
With a little help from Boost this example can be shorter.
#include <iostream>
#include <vector>
#include <boost/range/adaptor/reversed.hpp>
int main() {
std::size_t n{};
std::vector<int> vec{};
std::cin >> n;
vec.resize(n);
for (auto&& elm : vec)
std::cin >> elm;
for (auto&& elm : boost::adaptors::reverse(vec))
std::cout << elm << ' ';
}

C++ determinable array input in one line

I'm pretty new to c++ and can't seem to find correct way to code this. I have array of n digits, my code now:
int main()
{
int n,i;
cin >> n;
int a[n];
for (i=1;i<=n;i++)
{
cin >> a[i];
}
return 0;
}
This way every element of array has to be input in different line, is it possible to put all elements of a array in one line, with space between them.
I am assuming your question is "what is the correct way to do this?"
I would do it this way:
#include <iostream>
#include <vector>
using std::cin;
using std::cout;
using std::endl;
using std::vector;
int main()
{
int n;
cin >> n;
vector<int> v;
int i = 0;
int value;
while (i++ < n && cin >> value)
{
v.push_back(value);
}
char const* sep = "";
for (auto item : v)
{
cout << sep << item;
sep = " ";
}
cout << endl;
}
Note that this code is making assumptions that the input is well formed. If you need something that is more robust in handling possibly malicious input, that would require extra effort. This code, as given, will give-up-trying-and-continue which may or may not be suitable for your purposes.
The following code snippet of your program is a Variable Length Array(VLA) and this is only supported in C since ISO C99.
cin >> n;
int a[n];
And as previously pointed out, you can also use std::vector instead.
int main()
{
int size;
std::cin >> size;
int *array = new int[size];
delete [] array;
return 0;
}
References:
http://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html
How to create a dynamic array of integers
Without using stl container , one can implement like so:
#include <iostream>
#include <string>
#include "stdlib.h"
void GetInput(int* inputs, int n)
{
// store the entered numbers in a char[]
std::string word;
std::cout << "enter numbers (separate by space) ";
std::getline(std::cin, word);
char ch[100];
strcpy_s(ch, word.c_str());
char *temp = ch;
// parse the char[] for integers
for (int i = 0; strcmpi(temp, "") != 0 && i <= n; temp++,i++) {
*(inputs +i) = std::strtol(temp, &temp, 10);
}
}
int main()
{
int n = 3;
int inputs[10];
GetInput(inputs,n);
for (int j = 0; j < n; j++)
std::cout << inputs[j] << " \n";
return 0;
}
Output:

Why does it crash when I reach my 2D Array? out_of_range

#include <iostream>
#include <iomanip>
#include <fstream>
#include <cstdio>
#include <stdlib.h>
using namespace std;
int gradeExam(string answerKeyARR[]);
int main()
{
const int QUESTIONS = 10;
const int MAX_STUDENTS = 250;
ifstream inFile;
ofstream outFile;
inFile.open("grade_data.txt");
outFile.open("grade_report.txt");
string ansKey;
inFile >> ansKey;
string answerKeyARR[QUESTIONS];
//Loop for storing each answer into an array rather than all in a single string.
for (int j = 0; j < QUESTIONS; j++)
{
answerKeyARR[j] = ansKey.substr(j,1);
}
int i = 0;
int numStudents = 0;
string studentAnswers[MAX_STUDENTS];
//Loop to read in all answers into array and count number of students.
while (!inFile.eof())
{
inFile >> studentAnswers[i];
numStudents++;
i++;
}
//WHY DOES IT CRASH HERE?!
string studentAnswersARR[numStudents][QUESTIONS];
for (int k = 0; k < numStudents; k++)
{
for (int l = 0; l < QUESTIONS; l++)
{
studentAnswersARR[k][l] = studentAnswers[l].substr(l,1);
cout << studentAnswersARR[k][l];
}
}
inFile.close();
outFile.close();
return 0;
}
Okay, so basically once it gets to the part where it's removing the substring, it crashes. It works perfectly fine for retrieveing the answerkey answers, so why the hell is it crashing when it gets to this point? This is still a WIP for basic coding 2.
Also, when I change variable 'l' to, say, position 0, it works. What gives?
There are multiple issues with your code that may cause problems.
First, your input loop is not bounded properly. It should stop at MAX_STUDENTS, but you fail to check for this limit.
Second, do not use eof() to check for the end of file. There are many posts on SO discussing this.
while (!inFile && i < MAX_STUDENTS)
{
inFile >> studentAnswers[i];
numStudents++;
i++;
}
The next issue is the line you highlighted in your question. It probably crashes due to stack space being exhausted. But the code you have uses a non-standard C++ extension, and once you do that, then the rule as to what that line really does internally is up to the compiler vendor.
So to alleviate this with using standard C++, the following can be done:
#include <vector>
#include <string>
#include <array>
//...
std::vector<std::array<std::string, QUESTIONS> >
studentAnswersARR(numStudents);