Only read numbers out of users input - c++

I'm trying to write a function which only reads four ints out of a users input like this: ewzge242jfdsiii23 So it is supposed to save only 2422.
This is my code and it just gives me some weird output, if I let it cout number.
Can you maybe see my mistakes and explain why I can't do it how I did and what I could do instead? Thanks a lot!
int readnumber ( ) {
char kar, ont_kar, ont_ont_kar;
int number;
while (kar != '\n' ){
cin.get (kar);
if (kar >= '0' && kar <= '9') {
old_kar=kar;
old_kar = old_kar*10 + (kar - '0');
old_old_kar = old_kar ;
} //if
} //while
if (old_kar < 9999) {
number=old_kar;
}//if
else {
number=old_old_kar;
}//else
}//readnumber

This looks too complicated, why do you need so many variables?
Also old_kar and old_old_kar are misstyped. The function does not return, that should be the main problem.
Here's a quick simple example:
unsigned readnumber(int number_of_chars) {
char ch;
unsigned number = 0;
while (number_of_chars > 0) {
std::cin.get(ch);
if ('\n' == ch)
break; // Stop on new line
if (ch < '0' or ch > '9')
continue; // Skip non-digits
--number_of_chars; // One digit processed
number = number * 10 + ch - '0'; // And added to the result
}
return number;
}
And here is a full version without break or continue:
#include <iostream> // std::cin, std::cout
#include <fstream> // std::ifstream
using namespace std;
int readnumber(int number_of_chars) {
char ch;
int number = 0;
while (number_of_chars > 0) {
std::cin.get(ch);
if ('\n' == ch)
return number;
if (ch >= '0' and ch <= '9') {
--number_of_chars;
number = number * 10 + ch - '0';
}
}
return number;
}
int main() {
int n = readnumber(4);
cout << "You entered: " << n << endl;
return 0;
}
NB: Always compile with all warnings on, this will save you a lot of time.

Related

Why does the program print 0 instead of the average?

Wrote a function that calculates the average length of words in a sentence.
Why does the program print 0 instead of the average?
Please help me fix my mistake.
If you know how to make an implementation in one function, please write.
#include <iostream>
#include <string>
using namespace std;
int CountWordsAndLetters(char* str, int& words, int& letters)
{
words = 0;
int i = 0;
letters = 0;
while (str[i] == ' ')
i++;
for (; str[i]; i++) {
if (((str[i] >= 'a') && (str[i] <= 'z'))
|| ((str[i] >= 'A') && (str[i] <= 'Z')))
letters++;
if (str[i] == ' ') {
words++;
while (1)
if (str[i] == ' ')
i++;
else {
i--;
break;
}
}
}
words = words + 1;
return (words);
}
float AverageLetters(float words, float letters)
{
float a = (double)(letters / words);
return a;
}
int main()
{
char array[255];
int words = 0;
int letters = 0;
cout << "Enter the string\n\n";
gets_s(array);
int size;
for (size = 0; array[size]; size++)
;
char* str = new char[size];
CountWordsAndLetters(str, words, letters);
cout << "\nAverage number of letters per word: "
<< AverageLetters(words, letters);
return 0;
}
If you know how to make an implementation in one function, please write.
Here, you are allocating an uninitialized array of char:
char* str = new char[size];
You put nothing in it.
You then pass it to CountWordsAndLetters:
// here -------v
CountWordsAndLetters(str, words, letters);
You should consider simply sending array instead:
CountWordsAndLetters(array, words, letters);
Here's a live example of your code working.

How can I correctly encrypt the input when there is a space?

#include <iostream>
#include <cstring>
#include <string>
//#include <cctype>
using namespace std;
string k;
int key[1024];
int size = 0;
int count = 0;
char text[1024];
char o;
void encrypt(char input[]);
void decrypt(char input[]);
// get arguments from command line
int main(int argc, char *argv[])
{
if(argc >= 3)
{
k = argv[2];
// removing spaces from key
// storing key into char array
for(int i = 0; i < k.length(); i++)
{
if(k.at(i) == ' ')
{
key[i] = k.at(i+1);
i++;
}
else
{
key[i] = k.at(i);
// cout << key[i] << endl;
}
size++;
}
if(strcmp(argv[1], "-e") == 0)
{
// get text from user
// encrypt
cout << "encryption " << endl;
cin.getline(text, sizeof(text));
encrypt(text);
}
else if(strcmp(argv[1], "-d") == 0)
{
// get text from user
// decrypt
cout << "decryption " << endl;
decrypt(text);
}
}
}
void encrypt(char input[])
{
string word = input;
char wkey[word.length()];
// cout << word.length();
for(int i = 0; i < word.length(); count++, i++)
{
// if input is larger than the key
// chars of key will repeat until the size is the length of the input
if(i > size - 1)
{
if(i == size)
{
count = 0;
}
wkey[i] = wkey[count];
}
else
{
wkey[i] = key[i];
}
// if input is a space, cout a space
if(input[i] == ' ')
{
cout << " ";
}
// if input is something other than a letter, then just print it out
else if(input[i] < 65 || input[i] > 122 || input[i] > 90 && input[i] < 97)
{
cout << input[i];
}
else
{
// ignoring case of the letters in the key
// give the letters a range of 0-25
if(wkey[i] >= 65 && wkey[i] <= 90)
{
wkey[i]-= 'A';
}
else if(wkey[i] >= 97 && wkey[i] <= 122)
{
wkey[i]-= 'a';
}
// cout << wkey[i] << endl;
// if input is uppercase, put it in the range of 0-25
// make shift by adding to char in key
// mod by 26 to wrap around
// o is the encrypted character that will be printed
if(input[i] >= 65 && input[i] <= 90)
{
o = ((wkey[i] + (input[i] - 'A')) % 26) + 'A';
}
else if(input[i] >= 97 && input[i] <= 122)
{
o = ((wkey[i] + (input[i] - 'a')) % 26) + 'a';
}
}
cout << o;
}
}
The problem is that I am having trouble encrypting plaintext if that text contains a space. If the text is just one single word, then the program works. In the encryption function where I test the input for a space, I just print out a space, and then the next iteration of the for loop occurs. I think that this problem is occurring because once that next iteration occurs, the character in the key that is at the same index as the space in the input is skipped. I've tried doing an if statement to roll back to the skipped letter in the key, but I still get the wrong output. If anyone could give me some advice on how to fix this problem, I would really appreciate it.

Converting binary to ASCII

I have a text full of binary values(0-1) and i'm trying to convert it to ASCII , I made a code but it didn't work well and it takes too long time and writing, this is a part of it:
#include <iostream>
#include <fstream>
#include <string>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
int main()
{
ofstream fout("C:\\test.txt",ios :: binary);
ifstream file("E:\\mnmn.txt");
string content;
while(file >> content)
{
for (size_t i = 0; i < content.size(); i++)
{
while((content[i] == '0')
&& (content[i+1] == '0')
&& (content[i+2] == '0')
&& (content[i+3] == '0')
&& (content[i+4] == '0')
&& (content[i+5] == '0')
&& (content[i+6] == '0')
&& (content[i+7] == '0')
{
char *data = "00000000";
char c = strtol(data, 0, 2);
fout<<c;
}
}
}
}
i have to do the same for all values and even if i did the program repeats the values because the zeros and ones is connected without any spaces between , isn't there a better way to convert it?
the text contains:
00001111101010001001010101110
etc..
GCC 4.8.2: g++ -Wall -Wextra -std=c++11 read-01.cpp
#include <bitset>
#include <fstream>
int main() {
std::ofstream fout("test.txt");
std::ifstream fin("mnmn.txt");
char ic;
std::bitset<8> oc;
int i = 8;
while (fin >> ic) {
oc[--i] = ic - '0';
if (0 == i) {
fout << static_cast<char>(oc.to_ulong());
i = 8; } }
return 0; }
You can read the contents of the file character by character and accumulate the characters in a variable. After reading 8 characters, you have the ASCII value. The core of your function can be changed to:
int inChar = 0;
int outChar = 0;
int count = 0;;
while( (inChar = file.get()) != EOF )
{
int x = inChar - '0';
// Ignore newlines and other characters that are not '0' or '1'.
if ( x == 0 || x == 1 )
{
// Accumulate the bit into the output char.
outChar = (outChar << 1) + x;
++count;
if ( count == 8 )
{
fout.put(outChar);
outChar = 0;
count = 0;
}
}
}
// Deal with unused outChar.
if ( count > 0 )
{
cout << "There are " << count << " bits that were not used.\n";
}
If you want to get eight characters (bits) at a time from the input you read, then you should use the std::string::substr function, and you can use the resulting string directly, either in std::stoi (or if you don't have it std::strtol).
Something like
while (file >> content)
{
do
{
std::string byte = content.substr(0, 8); // Get eight "bits"
fout << std::stoi(byte, nullptr, 2); // Convert and output to file
content = content.substr(8); // The remaining bits
} while (!content.empty());
}

Using functions to output strings or characters. Noob

I have an input file named animals.dat that I need my program to read and output the files in block format. For example the file reads:
TIGER
DOG
CAT
It needs to output
TTTTTTTTTTTTTTTTTTTT (T would be 1x20 as it's the first character in the word and 20th letter in the alphabet)
IIIIIIIII
IIIIIIIII (I 2x9 as it's the 2nd character and 9th in the alphabet)
I've tried to set up functions to do this but my output kinda goes insane, outputting just TONS of one character at a time, and I'm pretty sure not even doing the rows. What am I doing wrong?
#include "stdafx.h"
#include <iostream>
#include <fstream>
using namespace std;
ifstream fin;
ofstream fout;
void rectangle(char ch, int alphacount,int count) {
int height=1, width=0;
while(width <= alphacount && height <= count) {
while(width <= alphacount) {
fout << ch;
cout << ch;
width++;
}
cout << endl;
if(height <= count) {
fout << ch << endl;
cout << ch << endl;
height++;
}
}
}
int main(void) {
fin.open("animals.dat");
fout.open("out.dat");
int count=0, alphacount=0;
char ch, x='A';
while(!fin.eof()) {
fin >> ch;
while(x!=ch) {
x++;
alphacount++;
}
rectangle(ch, alphacount, count);
count++;
if(ch =='\n') {
alphacount = 0;
count = 0;
x = 0;
}
}
system("pause");
}
Things that I see:
The function rectangle can be easily simplified. You just need two for loops.
void rectangle(char ch, int alphacount,int count)
{
for ( int height = 0; height < count; ++height )
{
for ( int width = 0; width < alphacount; ++width )
{
fout << ch;
cout << ch;
}
cout << endl;
}
}
You don't need x at all because you can compute alphacount directly using arithmetic.
You can move alphacount inside the while loop.
The code inside the while loop can be simplified to:
while(!fin.eof())
{
int alphacount = 0;
count++;
char ch;
fin >> ch;
if ( isalpha(ch) )
{
if ( ch > 'Z' )
{
// It's a lower case letter.
alphacount = ch - 'a' + 1;
}
else
{
// It's an upper case letter.
alphacount = ch - 'A' + 1;
}
rectangle(ch, alphacount, count);
}
if(ch =='\n')
{
count = 0;
}
}
You're not reinitializing x and alphacount within the outer loop. Your code should look like this:
while(!fin.eof())
{
int alphacount=0;
char ch, x='A';
fin >> ch;
.
.
.
A debugger would have found this problem for you in much less time than it took to write your question.

Shift deciphering tool (cesar cipher)

I have built a Program to decipher shift ciphers (Cesar Cipher). It seems to take the Input and makes a output file but it is empty. I am thinking that something may be wrong with the Deciphering function and have tried changing multiple things to no avail. I use Bloodshed C++ for compiling and windows for a OS.
Thanks
kd7vdb
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
using namespace std;
const int ARRAYSIZE = 128;
void characterCount(char ch, int list[]);
void calcShift( int& shift, int list[]);
void writeOutput(ifstream &in, ofstream &out, int shift);
int main()
{
int asciiCode = 0,
shift = 0;
string filename;
char ch;
ifstream infile;
ofstream outfile;
//input file
cout << "Input file name: ";
getline(cin, filename);
infile.open(filename.c_str());
if (!infile.is_open()) {
cout << "Unable to open file or it doesn't exist." << endl;
return 1;
}
//output file
cout << "Output file name: ";
getline(cin, filename);
outfile.open(filename.c_str());
int list[ARRAYSIZE] = {0};
while (infile.peek() != EOF)
{
infile.get(ch);
characterCount(ch, list);
}
infile.clear();
infile.seekg(0);
calcShift (shift, list); //Calculate the shift based on the <strong class="highlight">most</strong> characters counted
writeOutput(infile, outfile, shift); //Decypher and write to the other document
return 0;
}
void characterCount(char ch, int list[])
{
if (ch >= 'A' && ch <= 'z') //If the character is in the alphabet...
{
int asciiCode = 0;
asciiCode = static_cast<int>(ch); //Change it to the ASCII number
list[asciiCode]++; //And note it on the array
}
}
void calcShift( int& shift, int list[])
{
int maxIndex = 0, //Asuming that list[0] is the largest
largest = 0;
for (int i = 1; i < ARRAYSIZE; i++)
{
if (list[maxIndex] < list[i])
maxIndex = i; //If this is true, change the largest index
}
largest = list[maxIndex]; //When the maxIndex is found, then that has the largest number.
if (largest >= 65 && largest <= 90) //Calculate shift with <strong class="highlight">E</strong> (for upper-case letters)
shift = largest - 69;
if (largest >= 97 && largest <= 122) //For lower-case letters (<strong class="highlight">e</strong>)
shift = largest - 101;
}
void writeOutput(ifstream &infile, ofstream &outfile, int shift)
{
char ch;
int asciiCode = 0;
while (infile.peek() != EOF) { //Until it is the end of the file...
infile.get(ch); //Get the next character
if (ch >= 'A' && ch <= 'z') //If the character is in the alphabet...
{
asciiCode = static_cast<int>(ch); //Change it to the ASCII number
asciiCode += shift; //Do the shift
ch = static_cast<char>(asciiCode); //Change it to the shifted letter
}
outfile << ch; //Print to the outfile
}
}
You have a couple of logical errors. I think your last two functions should be more like:
void calcShift( int& shift, int list[])
{
int maxIndex = 0; //Asuming that list[0] is the largest
for (int i = 1; i < ARRAYSIZE; i++)
{
if (list[maxIndex] < list[i])
maxIndex = i; //If this is true, change the largest index
}
if (maxIndex >= 'A' && maxIndex <= 'Z') //Calculate shift with <strong class="highlight">E</strong> (for upper-case letters)
shift = 'E' - maxIndex;
if (maxIndex >= 'a' && maxIndex <= 'z') //For lower-case letters (<strong class="highlight">e</strong>)
shift = 'e' - maxIndex;
}
void writeOutput(ifstream &infile, ofstream &outfile, int shift)
{
char ch;
while (infile.peek() != EOF) { //Until it is the end of the file...
infile.get(ch); //Get the next character
if (ch >= 'A' && ch <= 'Z') //If the character is in the alphabet...
{
ch = 'A' + (((ch - 'A') + shift + 26) % 26);
}
if (ch >= 'a' && ch <= 'z') //If the character is in the alphabet...
{
ch = 'a' + (((ch - 'a') + shift + 26) % 26);
}
outfile << ch; //Print to the outfile
}
}
To summarise, you don't need largest in calcShift, you need to subtract maxIndex from 'E' or 'e' to calculate the shift, and your calculation of the substituted char in writeOutput was pretty far off.
I'm not sure why you were getting an empty output file, but this works for me using MSVC.
It seems to me you forget to ofstream::close your output file.
http://www.cplusplus.com/reference/iostream/ofstream/close/
There's a few serious problems I noticed.
1) You're not wrapping around when shifting. So if shift = 20 and you get the character 'y', when you do this:
asciiCode = static_cast<int>(ch); //Change it to the ASCII number
asciiCode += shift; //Do the shift
ch = static_cast<char>(asciiCode);
asciiCode becomes 'y' + 20 == 141, which is off the end of standard 128 bit ascii. You need to take the number mod, I guess, 128. So:
asciiCode = static_cast<int>(ch); //Change it to the ASCII number
asciiCode += shift; //Do the shift
asciiCode %= 128; // Wrap around
ch = static_cast<char>(asciiCode);
2) But this still doesn't address why you're only shifting alphabetic characters, yet shifting those letters to non-letter characters in the result.
And why are you counting them in an array of size 128, instead of 52? Or just 26?
Even more so, why are you generating the shift value in-code? You need to know that value to decode later...
In short, I reccommend you do it this way:
Translate characters to the numbers 0-51, rather than 0-127 (or 0-25)
When applying the shift, add it to the 0-51 value, then take that % 52 to get the new character.
Consider manually inputting the shift value.
This is how a Ceasar Cypher generally works.
3) As to the printing problem, have you tried debugging?
I can't speak about Bloodshed C++, but even just adding a cout statement would be really helpful. For instance:
std::cout << ch; //Print to cout for debugging
outfile << ch; //Print to the outfile
would let you know if the error is in the outfile processing.