My Program Only Processes One Line From The Input - c++

I'm doing a Caesar block cypher. The general steps to a solution are:
Read your message into a large buffer or a string object.
Either remove the spaces and punctuation or not (it's harder for the
Enemy to read if you do).
Then count the chars in the message.
Pick the first perfect square greater than the message length,
allocate an array of char that size.
Read the message into a square array of that size from left to right,
top to bottom.
Write the message out top to bottom, left to right, and you've
encyphered it.
My Code:
#include <iostream>
#include <cstdlib>
#include <string>
#include <cstring>
#include <ctype.h>
#include <cmath>
#include <functional>
#include <numeric>
#include <algorithm>
#include <locale>
using namespace std;
int main(int argc, char *argv[])
{
int length = 0;
cout << "Enter a string: ";
string buffer;
char buff[1024];
while (getline(cin, buffer))
{
buffer.erase(remove_if(buffer.begin(), buffer.end(), not1(ptr_fun(::isalnum))), buffer.end());
break;
}
length = buffer.length();
int squareNum = ceil(sqrt(length));
strcpy(buff, buffer.c_str());
char** block = new char*[squareNum];
for(int i = 0; i < squareNum; ++i)
block[i] = new char[squareNum];
int count = 0 ;
for (int i = 0 ; i < squareNum ; i++)
{
for (int j = 0 ; j < squareNum ; j++)
{
block[i][j] = buff[count++];
}
}
for (int i = 0 ; i < squareNum ; i++)
{
for (int j = 0 ; j < squareNum ; j++)
{
cout.put(block[j][i]) ;
}
}
return 0;
}
For the most part, it works. The problem I get is when there's more than one line of input.
Ex. 1
this is sample text suitable for a simulation of a diplomatic mission or a spy's instructions
Ex. 2
this is sample text suitable
for a simulation of a diplomatic
mission or a spy's instructions
Example 1 works and example 2 does not because there are multiple lines. I have a feeling it has to do with the while(getLine) function but I don't know exactly what to change.

This "break" inside the "while" loop - it breaks the loop after the first "getline" call. That's why you get only one line.

May be you should consider removing break after erase.

What you do in here:
while (getline(cin, buffer))
{
buffer.erase(remove_if(buffer.begin(), buffer.end(), not1(ptr_fun(::isalnum))), buffer.end());
break;
}
is saving new line to buffer every time you use getline. I mean, each time there is getline() evoked your buffer is being replaced, not appended.
Try this:
string buffer = "";
string buff2;
// You need to provide some way to let the user stop the input
// e.g. ask him to declare number of lines, or what I recommend
// check for an empty line given, which is implemented below:
while (getline(cin, buff2))
{
// now pressing [enter] after the last input line stops the loop
if (buff2.empty())
break;
buff2.erase(remove_if(buffer.begin(), buffer.end(), not1(ptr_fun(::isalnum))), buffer.end());
buffer += buff2;
}

Related

Unexpected return from cin.getline() in C++

I have this problem that when I use getline() function to input a char array it also inserts other characters, that are not constant and change every time I run the program.
I do realize it is most likely because of some kind of overflow happening, and it just takes numbers from the RAM.
But is there a possibility to fix that?
(Program is supposed to reverse a string and remove any non-letters, excluding spaces)
Here is my program:
#include <iostream>
#include <ctype.h>
#include <string>
using namespace std;
int main() {
string decoded = "";
char text[100];
cin.getline(text,sizeof(text));
for(int i = sizeof(text)-1; i >= 0; i--){
if (isalpha(text[i]) || text[i] == ' ' )
decoded.push_back(text[i]);
}
cout << decoded;
return 0;
}
Add #include <string.h> and change
for(int i = sizeof(text)-1; i >= 0; i--){ to
for(int i = strlen(text)-1; i >= 0; i--){
because strlen(text) calculates length upto \n where as sizeof(text) includes \n too.
or as Ruks mentioned in the comment a simple initialization char text[100] {}; works.
Just declare text as an empty array same as char[] text = new char[]{};

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);

Reformatting an entered string with spaces in it

Currently I am working on a problem to reformat the inputted string into the odd char then even char with no newline. ex. Input: Good Test. Ouput: Go etodTs. For some reason when I run the program it only outputs a "G".
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
using namespace std;
int main (int argc, char ** argv) {
char sWordOdd[100] = {0};
scanf("%s", sWordOdd);
int iNum = strlen(sWordOdd);
for (int i=0; i<=iNum && i%2==0; i++) {
printf("%c",sWordOdd[i]);
}
for (int a=0; a<=iNum && a%2!=0; a++) {
printf("%c",sWordOdd[a]);
}
printf("\n");
return 0;
}
Your i<=iNum && i%2==0 break condition terminates your loop early. To achieve the effect you want, put an if statement inside the loop, like so:
for (int i = 0; i <= iNum; i++){
if(i % 2 == 0)
printf("%c",sWordOdd[i]);
}
As for your second loop, I think you meant a++ instead of a--, because otherwise you'll try to access the array using a negative index. I think you meant for your loop to look like this:
for (int a = 0; a <= iNum; a++){
if(a % 2 != 0)
printf("%c",sWordOdd[a]);
}
Side note: Notice the spacing between the variables and the operators in my code. Using spaces like this makes your code easier to read.
int main()
{
string line;
getline(cin, line);
for (size_t start : {0,1})
for (size_t ii = start; ii < line.size(); ii += 2)
cout << line[ii];
cout << endl;
}
The above code handles arbitrarily long lines, is C++11 rather than C, and works.
As said before the loops terminate if i<=iNum && i%2==0 is true (for the first loop), which is the case for i=0. The second loop terminates with i=1.
Since you want to iterate all characters you have to move the i%2==0 part out of the for-statement:
for (int i=0; i<=iNum; i++) {
if (i%2==0)
{
printf("%c",sWordOdd[i]);
}
}
The second loop needs to be modified in the same way...
To fix this problem you have to use a function that can see stuff after whitespaces. This function is called getline. But with getline, you have to use string, so in this example I used string. I then found the size with the .size() function and then using just one constraint for the for loop instead of two in the question. I also took off the char array and replaced it with string as stated above. Everything else is pretty much the same. Using this answer lets me not having to use cstring and also simplifying my code into a short, easy way that is easy to follow through.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#define Set(a, s) memset(a, s, sizeof (a))
#define Rd(r) freopen(r, "r", stdin)
#define Wt(w) freopen(w, "w", stdout)
using namespace std;
int main (int argc, char ** argv)
{
string sWordOdd;
getline(cin, sWordOdd, '\n');
int iNum = (int)sWordOdd.size();
for (int i=0; i<iNum; i+=2){
cout << sWordOdd[i];
}
for (int a=1; a<iNum; a+=2){
cout << sWordOdd[a];
}
printf("\n");
return 0;
}

How to ignore non-letters from std::cin

So, I am trying to read a string from cin, then loop through the string to count which characters in that string are actually letters in the English alphabet. I have wrote a program that works just fine, but I want to know if there is a more efficient way of doing this, without looping through the entire English alphabet.
#include <iostream>
#include <string>
using namespace std;
int main() {
string my_str; //will use to store user input
getline(cin, my_str); //read in user input to my_str
int countOfLetters = 0; //begine count at 0
string alphabet = "abcdefghijklmnopqrstuwxyz"; //the entire english alphabet
for(int i = 0; i < my_str.length(); i++){
for(int j = 0; j < alphabet.length(); j++){
if (tolower(my_str.at(i)) == alphabet.at(j)){ //tolower() function used to convert all characters from user inputted string to lower case
countOfLetters += 1;
}
}
}
cout << countOfLetters;
return 0;
}
EDIT: Here is my new and improved code:
#include <iostream>
#include <string>
using namespace std;
int main() {
string my_str; //will use to store user input
getline(cin, my_str); //read in user input to my_str
int countOfLetters = 0; //begine count at 0
string alphabet = "abcdefghijklmnopqrstuwxyz"; //the entire english alphabet
for(unsigned int i = 0; i < my_str.length(); i++){
if (isalpha(my_str.at(i))){ //tolower() function used to convert all characters from user inputted string to lower case
countOfLetters += 1;
}
}
cout << countOfLetters;
return 0;
}
enter code here
Use isalpha() to see which characters are letters and exclude them.
So, you could modify your code like this:
#include <iostream>
#include <string>
using namespace std;
int main() {
string my_str;
getline(cin, my_str);
int countOfLetters = 0;
for (size_t i = 0; i < my_str.length(); i++) { // int i produced a warning
if (isalpha(my_str.at(i))) { // if current character is letter
++countOfLetters; // increase counter by one
}
}
cout << countOfLetters;
return 0;
}
You could perhaps use isalpha:
for(int i = 0; i < my_str.length(); i++)
if (isalpha(my_str.at(i))
countOfLetters++;
You can use the std::count_if() algorithm along with the iterator interface to count characters for which some predicate returns true. The predicate can use std::isalpha() to check for alphabetical characters. For example:
auto count = std::count_if(std::begin(str), std::end(str),
[&] (unsigned char c) { return std::isalpha(c); });
You could also check if the int cast is between 65-90 or 97-122
at example
(int)'a'
Should give 97
This will be the most performant method without any doubt.
Its better than using isalpha().
Check http://www.asciitable.com/ for ASCI Numbers
isalpha works well for this particular problem, but there's a more general solution if the list of characters to accept wasn't so simple. For example if you wanted to add some punctuation.
std::set<char> good_chars;
good_chars.insert('a'); good_chars.insert('A');
good_chars.insert('b'); good_chars.insert('B');
// ...
good_chars.insert('z'); good_chars.insert('Z');
good_chars.insert('_');
// the above could be simplified by looping through a string of course
for(int i = 0; i < my_str.length(); i++){
countOfLetters += good_chars.count(my_str[i]);
}

How to read in an array of chars as ints with spaces included?

I'm trying to create a program that reads in and solves incomplete 9x9 sudoku boards from a text file. One of the boards might look like this:
N
145369287
629785431
783412569
567148392
938527 14
214936758
851 74623
492853 76
376291845
I need to print out the board read in, which I'm doing by just using getline and printing the string, and then store each digit into an array, blanks can be converted to zeroes for the purpose of evaluation. If I tried to read the board in as straight ints then it would try to read all the digits of a row as one int until a space or a newline was reached, and if I try to read it in char by char with get(), I run into problems again with newlines, and I would then have to convert the array of chars to an array of ints for evaluation which I think I will run into problems with as well. This is my code so far, I figured using an istringstream would be convenient but then realized that I would have to have more for loops, so a solution without it would be ideal. Not allowed to use vectors or fancy modules or structs anything like that, it is a class assignment.
#include <iostream>
#include <string>
#include <sstream>
#include <iomanip>
#include <fstream>
using namespace std;
int main() {
ifstream infile("sudoku_infile.txt");
ofstream outfile("sudoku_outfile.txt");
int board[9][9];
char n;
char c;
string str;
stringstream into;
while (infile >> n){
for (int i = 0; i < 9; i++)
for (int j = 0; j < 9; j++){
getline(infile, str);
cout << str << "\n";
into << str;
}
return 0;
}
EDIT:
Ok, I've devised a solution on my own by trying to convert chars to ints and putting them in an array, but it doesn't seem to be working:
while (infile >> str){
for (int i = 0; i < 9; i++)
for (int j = 0; j < 9; j++){
getline(infile, str);
cout << str << "\n";
for (int z = 0; z < 9; z++){
if (isdigit(str[z])){
d = str[z] - '0';
}
else{
d = 0;
}
board[i][j] = d;
}
}
for (int m = 0; m < 9; m++){
for (int f = 0; f < 9; f++)
cout << board[m][f];
cout << endl;
}
}
I get this as output:
145369287
629785431
783412569
567148392
938527 14
214936758
851 74623
492853 76
376291845
071924836
555555555
555555555
555555555
555555555
555555555
555555555
555555555
555555555
You have to make sure, that your file just contains up to 9*9 characters - otherwise it will run out of bounds this way - but it's easy to add a bounds check in there. Because '0' starts in ASCII at index 48, I'm calculating the char value minus the magic number 48.
However you still have to add a check for ' ' by yourself (otherwise it gets initalized with -16), but I'm sure you can do it!
#include <iostream>
#include <string>
#include <iomanip>
#include <fstream>
int main(int argc, char **argv) {
std::ifstream infile("sudoku_infile.txt");
std::ofstream outfile("sudoku_outfile.txt");
int board[9][9];
size_t index = 0;
std::string str;
while (std::getline(infile, str)){
//std::cout << str << "\n";
for (size_t i = 0; i < str.size(); i++, index++){
board[index%9][index/9] = str[i] - '0';
}
}
return 0;
}
This can easily be done with one of the standard algorithm functions, namely std::copy. You can use it with iterator helpers like std::istream_inserter and std::back_inserter.
Use the above functions to put the integers into a std::vector.
After you're done with the basics, learning to use the standard library will really help you.
For example, even though you can't use it for this assignment, the above mentioned functions could be used like this:
std::vector<std::string> vs;
std::copy(std::istream_iterator<std::string>(infile),
std::istream_iterator<std::string>(),
std::back_inserter(vs));
After the above, the vector vs will contain all white-space delimited string from the infile stream.
To then get it into a board, you could to like this:
std::array<std::array<int, 9>, 9> board;
int i = 0;
for (const std::string& s : vs)
{
int j = 0;
for (const char& c : s)
board[i][j++] = c - '0';
++i;
}