Reading single char's into variables from file c++ - c++

I am messing around with file input/output and I am trying to make a encoding/decoding program. I need help reading the encoded chars from the file back into the program to be decoded. (this is not an assignment, as I am only going into 9th grade next year, I am trying to do this because it seemed challenging.)
Here's my code:
#include <iostream>
#include <fstream>
#include <string>
#include <cstdio>
#include <cstdlib>
/*
* OUT: categorize words into char's, assign a symbol/number to each char, output number
* combonation to file.
IN: load file, decode file, read decoded version. */
using namespace std;
void Encode(){
char message[100];
char ENCODED[100];
cout<<"input new content:\n>";
cin.getline(message, 99);
cin.ignore();
cout<<"encoding...\n";
for (int i=0; i<100; ++i){
if (message[i]=='a') ENCODED[i]='1';
else if (message[i]=='b') ENCODED[i]='$';
else if (message[i]=='c') ENCODED[i]='!';
else if (message[i]=='d') ENCODED[i]='*';
else if (message[i]=='e') ENCODED[i]='2';
else if (message[i]=='f') ENCODED[i]='&';
else if (message[i]=='g') ENCODED[i]='^';
else if (message[i]=='h') ENCODED[i]='%';
else if (message[i]=='i') ENCODED[i]='3';
else if (message[i]=='j') ENCODED[i]='=';
else if (message[i]=='k') ENCODED[i]='_';
else if (message[i]=='l') ENCODED[i]='-';
else if (message[i]=='m') ENCODED[i]='2';
else if (message[i]=='n') ENCODED[i]='9';
else if (message[i]=='o') ENCODED[i]='4';
else if (message[i]=='p') ENCODED[i]='|';
else if (message[i]=='q') ENCODED[i]='/';
else if (message[i]=='r') ENCODED[i]='>';
else if (message[i]=='s') ENCODED[i]='?';
else if (message[i]=='t') ENCODED[i]='}';
else if (message[i]=='u') ENCODED[i]='5';
else if (message[i]=='v') ENCODED[i]=',';
else if (message[i]=='w') ENCODED[i]='.';
else if (message[i]=='x') ENCODED[i]=';';
else if (message[i]=='y') ENCODED[i]=')';
else if (message[i]=='z') ENCODED[i]='#';
else if (message[i]==' ') ENCODED[i]='#';
else if (message[i] =='\0') {ENCODED[i] = '\}'; break;}
else ENCODED[i]=' ';
}
cout<<"done encoding.\n";
cout<<"exporting file...\n";
ofstream OUTfile ("encoded.txt");
OUTfile<<ENCODED;
cout<<"file exported to parent directory.\n";
cin.get();
}
void Decode(){ //this is where I run into problems!!
string encoded[100]
char DECODED[100]
ifstream INfile ("encoded.txt");
cout<<"Decoding...\n";
INfile>>encoded;
for (i=0; i<100; ++i){
if (encoded[i]=='1') DECODED[i]='a';
else if (encoded[i]=='$') DECODED[i]='b';
else if (encoded[i]=='!') DECODED[i]='c';
else if (encoded[i]=='*') DECODED[i]='d';
else if (encoded[i]=='2') DECODED[i]='e';
else if (encoded[i]=='&') DECODED[i]='f';
else if (encoded[i]=='^') DECODED[i]='g';
else if (encoded[i]=='%') DECODED[i]='h';
else if (encoded[i]=='3') DECODED[i]='i';
else if (encoded[i]=='=') DECODED[i]='j';
else if (encoded[i]=='_') DECODED[i]='k';
else if (encoded[i]=='-') DECODED[i]='l';
else if (encoded[i]=='2') DECODED[i]='m';
else if (encoded[i]=='9') DECODED[i]='n';
else if (encoded[i]=='4') DECODED[i]='o';
else if (encoded[i]=='|') DECODED[i]='p';
else if (encoded[i]=='/') DECODED[i]='q';
else if (encoded[i]=='>') DECODED[i]='r';
else if (encoded[i]=='?') DECODED[i]='s';
else if (encoded[i]=='}') DECODED[i]='t';
else if (encoded[i]=='5') DECODED[i]='u';
else if (encoded[i]==',') DECODED[i]='v';
else if (encoded[i]=='.') DECODED[i]='w';
else if (encoded[i]==';') DECODED[i]='x';
else if (encoded[i]==')') DECODED[i]='y';
else if (encoded[i]=='#') DECODED[i]='z';
else if (encoded[i]=='#') DECODED[i]=' ';
else if (encoded[i] =='\0') {DECODED[i] = '\}'; break;}
else DECODED[i]==' ';
}
cout<<"Decoded file content: "<<DECODED;
cin.get();
}
int main(){
string choice;
cout<<"Encode new message or decode previous file?\n> ";
cin>>choice;
cin.ignore();
if (choice=="encode") Encode();
if (choice=="decode") Decode();
return 0;
}
As you can see, I have no idea what I am doing when it comes to the Decode function.
ANY help would be appreciated! Thank you!
EDIT: I updated the code with the suggestions provided, but When the compiler gets to the line " INfile>>encoded;" it says there is no match for operator ">>" in "INfile>>encoded"...

Problems:
Compilation failed (g++-4.5.1) with no suitable overload of the ifstream constructor found, needs name.c_str().
ifstream INfile (name);
There are semicolons missing on the next two declarations
char encoded[100]
char DECODED[100]
The loop counter i is undeclared (for(int i = 0; ...)
for (i=0; i<100; ++i){
if (encoded[i]=='1') DECODED[i]='a';
From here on, you're comparing DECODED[i] to character constants, not assigning them. Replace all these DECODED[i]== by DECODED[i] =.
else if (encoded[i]=='$') DECODED[i]=='b';
else if (encoded[i]=='!') DECODED[i]=='c';
else if (encoded[i]=='*') DECODED[i]=='d';
One further problem is that you encode and decode 100 characters, no matter whether the actual message is shorter. In both, Decode() and Encode(), add a check for the end of the string
if (array[i] =='\0') {
other_array[i] = '\}';
break;
}
to end the conversion.

I believe the problem here is that you do not understand the difference between char and string. A char is a letter or symbol, like 'a' 'b' 'c' '1' '0' '^' ( etc. But a string - it as a sequence of chars, like "abc" "123" "*&^" etc. In C/C++ to specify a char we use single quote, like 'a'. A value inside single quotes can only have one letter inside. To specify a string we use double quotes, like a mentioned before. A value inside double quotes may have as many characters as you want.

Since this is an exercise for yourself, may I suggest that you create a mapping to avoid those crazy if-statements (and make it easier to modify your encodings later):
// Warning: always address these with ints or unsigned char, not char
// if you expect extended ASCII characters
static unsigned char encode_map[256] = {0};
static unsigned char decode_map[256] = {0};
void InitEncodingMap()
{
encode_map['a'] = '1';
encode_map['b'] = '$';
encode_map['c'] = '!';
encode_map['d'] = '1';
// etc...
encode_map['z'] = '#';
encode_map[' '] = '#';
// Create the reverse map
for( int i = 0; i < 256; i++ ) {
unsigned char encoded = encode_map[i];
if( decode_map[encoded] != 0 ) {
printf("Collision for mapping %c -> %c\n", (char)i, encoded );
} else {
decode_map[encode_map[i]] = (unsigned char)i;
}
}
}
Now, try rewriting your Encode and Decode functions to use these maps.

Related

Recursion cin.getline() doesn't want to ask for input

Here is the code:
void Reader::read(short& in) {
char* str = new char[6];
char* strbeg = str;
cin.getline(str, 6);
in = 0;
int value = 0;
short sign = 1;
if (*str == '+' || *str == '-') {
if (*str == '-' ) sign = -1;
str++;
}
while (isdigit(*str)) {
value *= 10;
value += (int) (*str - '0');
str++;
if (value > 32767) {
cout.write("Error, value can't fit short. Try again.\n", 41);
delete[] strbeg;
read(in);
return;
}
}
if (sign == -1) { value *= -1; }
in = (short) value;
delete[] strbeg;
return;
}
What happens is that if I type 999999999, it calls itself but on fourth line it's not gonna ask for input again. Debugger couldn't give much info as it is more language-specific question. Thank you in advance. Have a nice day!
Yes, the goal is to parse input as short. I know about losing 1 from min negative, wip :)
=== edit ===
I've tried goto... No, same thing. So it's not about visible variables or addresses, I guess.
=== edit ===
I can't use operator >> as it is forbidden by the task.
999999999 will cause an overflow, thus failbit is set for cin. Then your program reach read(in), then the cin.getline(). Here, beacause of failbit, cin will not ask any input again.
If you tried to figure out why in my code cin do ask for more input, you might find out all this by yourself.
I write you an example.
#include <iostream>
#include <climits>
using namespace std;
int main() {
char str[6];
short x = 0;
bool flag = false;
while (flag == false) {
cin.getline(str, 6);
flag = cin.good();
if (flag) { // if read successfully
char *p = str;
if (*p=='-') // special case for the first character
++p;
while (*p && *p>='0' && *p<='9')
++p;
if (*p) // there is a non digit non '\0' character
flag = false;
}
if (flag == false) {
cout << "An error occurred, try try again." << endl;
if (!cin.eof()) {
cin.unget(); // put back the possibly read '\n'
cin.ignore(INT_MAX, '\n');
}
cin.clear();
} else {
// str is now ready for parsing
// TODO: do your parsing work here
// for exemple x = atoi(str);
}
}
std::cout << x << std::endl;
return 0;
}
As we have discussed, you don't need new.
Check whether the string read is clean before parsing. If you mix checking and parsing, things will be complicated.
And you don't need recursion.
Read characters from stream by istream::getline seems to be the only option we have here. And when an error occurred, this function really doesn't tell us much, we have to deal with overflow and other problem separately.

C/C++ reading line at a time

I was trying to solve a programming problem of some site and this one had the following statement:
Read a string and parse it as a number, char 'l' can be considered as number 1 and chars 'o' and 'O' can be considered as number 0, commas and spaces will be accepted in the input but ignored, if any other character is found then output error...
So... since there can be spaces in the lines, I used gets (the documentation says it removes the new line and puts a terminator)...
My sequence of IF test if it is a number, then if its an acceptable letter, then checks if it is not a comma or a space... And I found out that it was almost always entering in the last IF even though there wasn't any character that should lead it there so I changed the printf inside it to print the
printf("%d error", st[k]);
And it outputs 13: carriage return... I tried this compiler here
#include <cstdio>
#include <cstring>
#include <cstdlib>
int main()
{
char st[100];
char buf[100];
int k, i;
long long int num;
ops: while(gets(st))
{
for(k = i = 0; st[k]; k++)
if(st[k] >= '0' && st[k] <= '9')
buf[i++] = st[k];
else if(st[k] == 'o' || st[k] == 'O')
buf[i++] = '0';
else if(st[k] == 'l')
buf[i++] = '1';
else if(st[k] != ',' && st[k] != ' ')
{
printf("error\n");
goto ops;
}
// remaining code comes here...
}
The input sample had the following lilnes:
lo6
234,657
hi
,,,,,5,,5, 4
2200000000
00
Should I use other function to read instead?
Any suggestions on how to avoid this damn Carriage Return?
The statemente for the problem can be seen here if you want more detail
Thanks
EDIT:
I'm asking that because there seem to be a difference between the compiler I'm using and the compiler the website was using, once I submitted a code that wasn't generating the correct output on mine but I thought the code was correct... and it passed. Then after it, I tried the code on a linux virtual machine and also correct but my gcc on windows failed... some characters were completely away from where they should be
The thing is:
The preferred method of line input is getline. If you do not know the width of the input beforehand, getline will allocate space for you if you set the buffer pointer to NULL.
Since you indicate you have some experience in C, the following will show you how to step through an input string and parse it in the manner you want. While there are many ways to handle parsing strings, it is hard to beat assigning a pointer to the beginning of the string and then advancing down the string until you reach the null-terminating character (unsigned 0, or char '\0'). If you have any questions after looking it over, just ask:
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char *argv[]) {
char *buffer = NULL;
size_t n = 0;
ssize_t len;
char *ptr = NULL;
char *output = NULL;
int idx = 0;
printf ("\nEnter your string below: ([ctrl + d] on blank line to end)\n");
while ((len = getline (&buffer, &n, stdin)) != -1) {
ptr = buffer;
idx = 0;
output = malloc (sizeof (char) * len);
while (*ptr != 0) {
if (*ptr >= 48 && *ptr <= 57) output [idx++] = *ptr;
if (*ptr == 'I') output [idx++] = '1';
if (*ptr == 'o' || *ptr == 'O') output [idx++] = '0';
ptr++;
}
output [idx] = 0;
printf ("\n valid output: %s\n\n", output);
free (output);
}
return 0;
}
output:
Enter your string below: ([ctrl + d] on blank line to end)
This sting has 12345 aeiou AEIOU,,,,,commas, and 99, to end.
valid output: 123450100990

Taking string as input character by charcter and giving output on pressing enter

I want to write a program in C or C++ which takes a string as a input character by character and gives output when enter key is pressed. I have to take the input character by character.
while (1)
{
scanf("%c",&a); //cin>>a;
if(a=='\n')
break;
//do operation on the character
}
//give output
something like this but I am not able to do it.
IIUC, you're looking for the getchar function:
while (1)
{
char c = (char)getchar();
if(c=='\n')
break;
//do operation on the character
}
//give output
Ideally your code should work properly.
Since a scanf reads a character and stores it.
What is the error/output you are getting?
Also try comparing (a==10)
10 is the ascii value of '\n'
Try this:
int main()
{
char str[100],c;
int i =0;
while((c=getc(stdin)) != '\n')
{
str[i] = c;
i++;
}
str[i] = '\0';
printf("%s",str);
return 0;
}
Here is one way:
char ch;
while(1)
{
if((ch=getchar())=='\n')
break;
}// its working fine
And another way:
char ch;
while(1)
{
scanf("%c",&ch);
if((ch=='\n'))
break;
}

Output wrong. Possible strncpy issue?

So, I'm trying to get this code to parse each line inputted from the file into individual tokens, then add each one in turn to tklist array. Then the main just prints out each token. It's printing blanks though, and when I step into the code it looks like the strncpy isn't working. Any ideas what the issue is? I get no errors.
Here's the main function:
#include <iostream>
#include <fstream>
using namespace std;
#include "definitions.h"
#include "system_utilities.h"
int main()
{
ifstream inFile;
char line[MAX_CMD_LINE_LENGTH];
char* token[MAX_TOKENS_ON_A_LINE];
int numtokens;
system("pwd");
inFile.open("p4input.txt", ios::in);
if(inFile.fail()) {
cout << "Could not open input file. Program terminating.\n\n";
return 0;
}
while (!inFile.eof())
{
inFile.getline(line, 255);
line[strlen(line)+1] = '\0';
numtokens = parseCommandLine(line, token);
int t;
for (t=1; t <= numtokens; t++) {
cout << "Token "<< t << ": " << token[t-1] << "\n";
}
}
return 0;
}
And here's the parseCommandLine function:
int parseCommandLine(char cline[], char *tklist[]){
int i;
int length; //length of line
int count = 0; //counts number of tokens
int toklength = 0; //counts the length of each token
length = strlen(cline);
for (i=0; i < length; i++) { //go to first character of each token
if (((cline[i] != ' ' && cline[i-1]==' ') || i == 0)&& cline[i]!= '"') {
while ((cline[i]!=' ')&& (cline[i] != '\0') && (cline[i] != '\r')){
toklength++;
i++;
}
//---------------
tklist[count] = (char *) malloc( toklength +1);
strncpy(tklist[count], &cline[i-toklength], toklength);
//--------------
count ++;
toklength = 0;
}
if (cline[i] == '"') {
do {
toklength++;
i++;
if (cline[i] == ' ') {
toklength--;
}
} while (cline[i]!='"');
//--------------
tklist[count] = (char *) malloc( toklength +1);
strncpy(tklist[count], &cline[i-toklength], toklength);
//--------------
count ++;
toklength = 0;
}
}
int j;
for (j = 0; j < count; j++) {
free( (void *)tklist[j] );
}
return count;
}
Like I said, when I debug it looks like a problem with copying, but I'm a beginner so I suspect I'm doing something wrong.
Thanks for any help you can give!!
Try something like
tklist[count][toklength]='\0';
after
strncpy(tklist[count], &cline[i-toklength], toklength);
strncpy() does not necessarily add a null terminator for you. strncpy needs some care to use safely.
No null-character is implicitly appended at the end of destination if
source is longer than num..
Just for starters... there are other deeper issues as mentioned in comments.
To start with the generic equivalent of malloc/free is new/delete (heap memory allocation).
Second you seem to be confusing strings and c_strings (good old char*). getline uses strings, your parsing function uses c_strings they are not the same things and there is .c_str() a member function of string to do the conversion.
So, I'm trying to get this code to parse each line inputted from the
file into individual tokens, then add each one in turn to tklist
array.
For
each line inputted from the file
use
std::ifstream ifs;
std::string s;
/**/
std::getline(ifs, s);
adopted to your loop.
To
parse [..] into individual tokens
look how
std::string
can help you on that task (or use boost::tokenizer).
And this
then add each [token] in turn to tklist array.
almost cries for std::list or std::vector instead of a plain C array, the choice, which container to use depends e.g. on what you intend to do with the tokens found.

a simple getch() and strcmp problem

I have this simple problem that gets an input from the user using a function then checks if the input is 'equal' to the "password". However, strcmp would never return my desired value, and the culprit is somewhere in my loop that uses getch() to take each character separately and add them to the character array. I found this out by having printf display the character array. If I type in pass word, the function would display it as pass word ". I have no idea on why the closing double quote and a whitespace was included in the array right after the word I typed in. Any idea? Here's the code. Thanks.
#include <stdio.h>
#include <iostream>
#include <conio.h>
#include <string.h>
int validateUser();
int main()
{
for(int x = 0;x<2;x++)
{
if(validateUser())
{
system("cls");
printf("\n\n\t\t** Welcome **"); break;
}
else
{
system("cls");
printf("\n\n\t\tIntruder Alert!");
system("cls");
}
}
system("PAUSE>nul");
return 0;
}
int validateUser()
{
char password[9];
char validate[] = "pass word";
int ctr = 0, c;
printf("Enter password : ");
do
{
c = getch();
if(c == 32)
{
printf(" ");
password[ctr] = c;
}
if(c != 13 && c != 8 && c != 32 )
{
printf("*");
password[ctr] = c;
}
c++;
}while(c != 13);
return (!strcmp(password, validate));
}
Your char array password does not
have a terminating null char.
You need to ensure that you don't
stuff more than 8 char into
password
Also c++ should be ctr++
.
do {
// stuff char into password.
ctr++;
}while(c != 13 && ctr <8);
password[ctr] = 0;
You're incrementing c in your loop. You should be incrementing ctr. Also, all the stuff everyone else has said (null terminator, only 8 characters, etc).
getch() is a function defined in a non-standard header <conio.h>. Relying on non-standard features is not recommended when you want your code to be portable. :)
do {
// stuff char into password.
++ctr;
} while(c != 13 && ctr < 9);
password[ctr] = '\0';