I am trying to XOR some already encrypted files.
I know that the XOR key is 0x14 or dec(20).
My code works except for one thing. All the '4' is gone.
Here is my function for the XOR:
void xor(string &nString) // Time to undo what we did from above :D
{
const int KEY = 0x14;
int strLen = (nString.length());
char *cString = (char*)(nString.c_str());
for (int i = 0; i < strLen; i++)
{
*(cString+i) = (*(cString+i) ^ KEY);
}
}
Here is part of my main:
ifstream inFile;
inFile.open("ExpTable.bin");
if (!inFile) {
cout << "Unable to open file";
}
string data;
while (inFile >> data) {
xor(data);
cout << data << endl;
}
inFile.close();
Here is a part of the encypted file:
$y{bq //0 move
%c|{ //1 who
&c|qfq //2 where
'saufp //3 guard
x{wu`}{z //4 location
But x{wu}{z` is returning //location. Its not displaying the 4.
Note the space infront of the X. thats supposed to be decoded to 4.
What am I missing? Why is it not showing all the 4? <space> = 4 // 4 = <space>
UPDATE
This is the list of all the specific conversions:
HEX(enc) ASCII(dec)
20 4
21 5
22 6
23 7
24 0
25 1
26 2
27 3
28 <
29 =
2a >
2b ?
2c 8
2d 9
2e :
2f ;
30 $
31 %
32 &
33 '
34
35 !
36 "
37 #
38 ,
39 -
3a .
3b /
3c (
3d )
3e *
3f +
40 T
41 U
42 V
43 W
44 P
45 Q
46 R
47 S
48 \
49 ]
4a ^
4b _
4c X
4d Y
4e Z
4f [
50 D
51 E
52 F
53 G
54 #
55 A
56 B
57 C
58 L
59 M
5a N
5b O
5c H
5d I
5e J
5f K
60 t
61 u
62 v
63 w
64 p
65 q
66 r
67 s
68 |
69 }
6a
6b
6c x
6d y
6e z
6f {
70 d
71 e
72 f
73 g
75 a
76 b
77 c
78 l
79 m
7a n
7b o
7c h
7d i
7e j
7f k
1d /tab
1e /newline
Get rid of all casts.
Don't use >> for input.
That should fix your problems.
Edit:
// got bored, wrote some (untested) code
ifstream inFile;
inFile.open("ExpTable.bin", in | binary);
if (!inFile) {
cerr << "Unable to open ExpTable.bin: " << strerror(errno) << "\n";
exit(EXIT_FAILURE);
}
char c;
while (inFile.get(c)) {
cout.put(c ^ '\x14');
}
inFile.close();
Are you sure that it is printing '//location'? I think it would print '// location' -- note the space after the double-slash. You are XORing 0x34 with 0x14. The result is 0x20, which is a space character. Why would you want to xor everything with 0x14 anyway?
** edit ** ignore the above; I missed part of your question. The real answer:
Are you entirely sure that the character before the x is a 0x20? Perhaps it's some unprintable character that looks like a space? I would check the hex value.
Related
Trying to figure out how to write something in C++ that will decrypt a rotating XOR to packet bytes that will be in varying sizes with a known 10 byte key (key can be ascii or hex, whatever is easier).
For example:
XOR 10-byte key in hex: 41 30 42 44 46 4c 58 53 52 54
XOR 10-byte key in ascii: A0BDFLXSRT
Here is "This is my message in clear text" in hex that needs to be decrypted with above key
15 58 2B 37 66 25 2B 73 3F 2D 61 5D 27 37 35 2D 3F 36 72 3D 2F 10 21 28 23 2D 2A 73 26 31 39 44
I need a way to apply my XOR key over the top of these bytes like this in a rotating fashion:
41 30 42 44 46 4c 58 53 52 54 41 30 42 44 46 4c 58 53 52 54 41 30 42 44 46 4c 58 53 52 54 52 54
15 58 2B 37 66 25 2B 73 3F 2D 61 5D 27 37 35 2D 3F 36 72 3D 2F 10 21 28 23 2D 2A 73 26 31 39 44
When I XOR these together, I get the data in readable format again:
"This is my message in clear text"
I've seen some examples that take the entire XOR key and apply it to each byte, but that's not what I need. It needs to somehow rotate over the bytes until the end of the data is reached.
Is there anyone who can assist?
Use the % (modulus) operator!
using byte_t = unsigned char;
std::vector< byte_t > xor_key;
std::vector< byte_t > cipher_text;
std::string plain_text;
plain_text.reserve( cipher_text.size( ) );
for( std::size_t i = 0;
i < cipher_text.size( );
++i )
{
auto const cipher_byte = cipher_text[ i ];
// i % xor_key.size( ) will "rotate" the index
auto const key_byte = xor_key[ i % xor_key.size( ) ];
// xor like usual!
plain_text += static_cast< char >( cipher_byte ^ key_byte );
}
You just use a loop, and a modulus operation, to XOR one byte of the key, with one byte of the cypher text.
void decrypt(char *cypher, int length, char* key) {
for (int i = 0; i < length; i++) cypher[i] ^= key[i % 10];
}
By indexing the key with modulus (remainder) of 10, it will always have "rotating" values between 0 and 9.
Can someone tell me whats wrong with my code?
It works fine in my test example.. but when I use it in production model it decrypts the string but adds a padded symbol to maintain some kind of block size or something.
I didn't post my encrypt/decrypt methods as they would make this post too big, plus they work fine as my test example decrypts and encrypts properly, ini.GetValue is a INI retrieval method there is nothing wrong with it, plus you can see the base64 size is the same as the example code, so I believe it works fine, I never had any problems with it before without encryption when I used it, it returns a const char*The problem is known as you can see the production code ciphertext has appended to it 2 null bytes which I find strange becasue both codes are pretty much identical, I'm not good at C++ so I'm probably overlooking some basic char array stuff
The encryption code I use is AES-256-CBC from OpenSSL 1.1.1
Look at my outputs to see whats wrong.
Good looking example code:
Ciphertext is:
000000: 7a e1 69 61 65 bb 74 ad 1a 68 8a ae 73 70 b6 0e z.iae.t..h..sp..
000010: 4f c9 45 9b 44 ca e2 be e2 aa 16 14 cd b1 79 7b O.E.D.........y{
000020: 86 a5 92 26 e6 08 3e 55 61 4e 60 03 50 f3 e4 c1 ...&..>UaN`.P...
000030: fe 5a 2c 0b df c9 1b d8 92 1f 48 75 0d f8 c2 44 .Z,.......Hu...D
Base64 (size=88):
000000: 65 75 46 70 59 57 57 37 64 4b 30 61 61 49 71 75 euFpYWW7dK0aaIqu
000010: 63 33 43 32 44 6b 2f 4a 52 5a 74 45 79 75 4b 2b c3C2Dk/JRZtEyuK+
000020: 34 71 6f 57 46 4d 32 78 65 58 75 47 70 5a 49 6d 4qoWFM2xeXuGpZIm
000030: 35 67 67 2b 56 57 46 4f 59 41 4e 51 38 2b 54 42 5gg+VWFOYANQ8+TB
000040: 2f 6c 6f 73 43 39 2f 4a 47 39 69 53 48 30 68 31 /losC9/JG9iSH0h1
000050: 44 66 6a 43 52 41 3d 3d DfjCRA==
b cip len = 64
a cip len = 16
plain b = 0
plain a = 3
Decrypted text is:
wtf
Decrypted base64 is:
wtf
000000: 77 74 66 00 wtf.
Bad production code example:
Base64 (size=88)
000000: 6a 7a 48 30 46 71 73 54 45 47 4d 76 2f 67 76 59 jzH0FqsTEGMv/gvY
000010: 4d 73 34 54 2f 39 58 32 6c 37 54 31 4d 6d 56 61 Ms4T/9X2l7T1MmVa
000020: 36 45 4f 38 52 64 45 57 42 6b 65 48 71 31 31 45 6EO8RdEWBkeHq11E
000030: 39 2b 77 37 47 4e 49 4a 47 4a 71 42 55 74 54 70 9+w7GNIJGJqBUtTp
000040: 30 36 58 46 31 4d 66 45 79 44 45 71 5a 69 58 54 06XF1MfEyDEqZiXT
000050: 79 45 53 6b 65 41 3d 3d yESkeA==
Ciphertext is:
000000: 8f 31 f4 16 ab 13 10 63 2f fe 0b d8 32 ce 13 ff .1.....c/...2...
000010: d5 f6 97 b4 f5 32 65 5a e8 43 bc 45 d1 16 06 47 .....2eZ.C.E...G
000020: 87 ab 5d 44 f7 ec 3b 18 d2 09 18 9a 81 52 d4 e9 ..]D..;......R..
000030: d3 a5 c5 d4 c7 c4 c8 31 2a 66 25 d3 c8 44 a4 78 .......1*f%..D.x
000040: 00 00 ..
b cip len = 65
a cip len = 17
crypt miss-match
plain b = 16
crypt write fail
plain a = 16
000000: 77 74 66 09 09 09 09 09 09 09 09 05 05 05 05 05 wtf.............
Here are my codes as you can see they both look very similar so I don't understand whats the problem.
Here is a little helper function for hexdump outputs I use.
void Hexdump(void* ptr, int buflen)
{
unsigned char* buf = (unsigned char*)ptr;
int i, j;
for (i = 0; i < buflen; i += 16) {
myprintf("%06x: ", i);
for (j = 0; j < 16; j++)
if (i + j < buflen)
myprintf("%02x ", buf[i + j]);
else
myprintf(" ");
myprintf(" ");
for (j = 0; j < 16; j++)
if (i + j < buflen)
myprintf("%c", isprint(buf[i + j]) ? buf[i + j] : '.');
myprintf("\n");
}
}
char* base64(const unsigned char* input, int length) {
const auto pl = 4 * ((length + 2) / 3);
auto output = reinterpret_cast<char*>(calloc(pl + 1, 1)); //+1 for the terminating null that EVP_EncodeBlock adds on
const auto ol = EVP_EncodeBlock(reinterpret_cast<unsigned char*>(output), input, length);
if (pl != ol) { myprintf("b64 calc %d,%d\n",pl, ol); }
return output;
}
unsigned char* decode64(const char* input, int length) {
const auto pl = 3 * length / 4;
auto output = reinterpret_cast<unsigned char*>(calloc(pl + 1, 1));
const auto ol = EVP_DecodeBlock(output, reinterpret_cast<const unsigned char*>(input), length);
if (pl != ol) { myprintf("d64 calc %d,%d\n", pl, ol); }
return output;
}
Here is the test example that works fine.
/* enc test */
/* Message to be encrypted */
unsigned char* plaintext = (unsigned char*)"wtf";
/*
* Buffer for ciphertext. Ensure the buffer is long enough for the
* ciphertext which may be longer than the plaintext, depending on the
* algorithm and mode.
*/
unsigned char* ciphertext = new unsigned char[128];
/* Buffer for the decrypted text */
unsigned char decryptedtext[128];
int decryptedtext_len, ciphertext_len;
/* Encrypt the plaintext */
ciphertext_len = encrypt(plaintext, strlen((char*)plaintext), ciphertext);
/* Do something useful with the ciphertext here */
myprintf("Ciphertext is:\n");
Hexdump((void*)ciphertext, ciphertext_len);
myprintf("Base64 (size=%d):\n", strlen(base64(ciphertext, ciphertext_len)));
Hexdump((void*)base64(ciphertext, ciphertext_len), 4 * ((ciphertext_len + 2) / 3));
/* Decrypt the ciphertext */
decryptedtext_len = decrypt(ciphertext, ciphertext_len, decryptedtext);
/* Add a NULL terminator. We are expecting printable text */
decryptedtext[decryptedtext_len] = '\0';
/* Show the decrypted text */
myprintf("Decrypted text is:\n");
myprintf("%s\n", decryptedtext);
myprintf("Decrypted base64 is:\n");
myprintf("%s\n", decode64(base64(decryptedtext, decryptedtext_len), 4 * ((decryptedtext_len + 2) / 3)));
Hexdump(decode64(base64(decryptedtext, decryptedtext_len), 4 * ((decryptedtext_len + 2) / 3)), 4 * ((decryptedtext_len + 2) / 3));
/* enc test end */
Here is the bad production code:
//Decrypt the username
const char* b64buffer = ini.GetValue("Credentials", "SavedPassword", "");
int b64buffer_length = strlen(b64buffer);
myprintf("Base64 (size=%d)\n", b64buffer_length);
Hexdump((void*)b64buffer, b64buffer_length);
int decryptedtext_len;
int decoded_size = 3 * b64buffer_length / 4;
unsigned char* decryptedtext = new unsigned char[decoded_size];
//unsigned char* ciphertext = decode64(b64buffer, b64buffer_length); //had this before same problem as below line, this worked without initializing new memory I perfer to fix this back up
unsigned char* ciphertext = new unsigned char[decoded_size];
memcpy(ciphertext, decode64(b64buffer, b64buffer_length), decoded_size); //same problem as top line.
myprintf("Ciphertext is:\n");
Hexdump((void*)ciphertext, decoded_size);
/* Decrypt the ciphertext */
decryptedtext_len = decrypt(ciphertext, decoded_size - 1, decryptedtext);
/* Add a NULL terminator. We are expecting printable text */
decryptedtext[decryptedtext_len] = '\0';
Hexdump(decryptedtext, decryptedtext_len);
strcpy(password_setting, (char*)decryptedtext); //save decrypted password back
delete[] decryptedtext;
delete[] ciphertext;
In the example that works, you get ciphertext_len directly from the encryption function. When you display the ciphertext, you use this length.
In the "bad production code", you calculate decoded_size from the length of the Base64 data. However, Base64 encoded data always has a length that is a multiple of 4. If the original data size is not a multiple of 3, then there are one or two padding characters added to the string. In both of your examples, you have two of these characters, the '=' at the end of the Base64 data.
When calculating the length of the decrypted data, you need to account for these bytes. If there are no '=' characters at the end of the string, use the length that you calculated (3 * N / 4). If there is one '=' character, reduce that calculated length by 1, and if there are two '=' characters, reduce the calculated length by 2. (There will not be 3 padding characters.)
Edit: Here is my fix: (sspoke)
char* base64(const unsigned char* input, int length) {
const auto pl = 4 * ((length + 2) / 3);
auto output = reinterpret_cast<char*>(calloc(pl + 1, 1)); //+1 for the terminating null that EVP_EncodeBlock adds on
const auto ol = EVP_EncodeBlock(reinterpret_cast<unsigned char*>(output), input, length);
if (pl != ol) { printf("encode64 fail size size %d,%d\n",pl, ol); }
return output;
}
unsigned char* decode64(const char* input, int* length) {
//Old code generated base length sizes because it didn't take into account the '==' signs.
const auto pl = 3 * *length / 4;
auto output = reinterpret_cast<unsigned char*>(calloc(pl + 1, 1));
const auto ol = EVP_DecodeBlock(output, reinterpret_cast<const unsigned char*>(input), *length);
if (pl != ol) { printf("decode64 fail size size %d,%d\n", pl, ol); }
//Little bug fix I added to fix incorrect length's because '==' signs are not considered in the output. -sspoke
if (*length > 3 && input[*length - 1] == '=' && input[*length - 2] == '=')
*length = ol - 2;
else if (*length > 2 && input[*length - 1] == '=')
*length = ol - 1;
else
*length = ol;
return output;
}
I have a string given, which contains the following content (so the following lines are stored in a String-variable):
S*⸮
------------------------
K!
NAG 00.10
K"
NMAGICSTAR 2 L V1.0-1
K#
AUFSTELLORT: S 00000000
K$
GERAET NR.: 0000000000
KC
ZULASSUNGS NR.:411107770
K)
BAUART: NAG5A02
K(
ABLAUFDATUM: 2021/04
------------------------
Can anyone help me or give me a short hint how to remove the control codes (so the S*⸮ respectively the K!) out of this string (there is always a small rectangle before the control code, i don't know why it is removed)? So that in the end, it's
------------------------
NAG 00.10
NMAGICSTAR 2 L V1.0-1
AUFSTELLORT: S 00000000
GERAET NR.: 0000000000
ZULASSUNGS NR.:411107770
BAUART: NAG5A02
ABLAUFDATUM: 2021/04
------------------------
Let me finally quote something out of the documentation, maybe it helps:
Each line is max. 24 characters long and must end with LF [0Ah]
Control Code "ESC 'S' 21h LF" means: XON Startsequence with manufacturer code, machine code and dataset code
I am trying to do this whole task on an ESP32/ Arduino IDE (C++).
This is not an anwser. You may use the following code to print you string as integer in hex form. Every 12 characters a wide separation, and every 24 a new line. The arrange makes easier for you to count 24 characters.
#include <iostream>
void dump_str(const std::string&str)
{
int n;
std::cout << std::hex;
for (int i=0; i<str.size(); i++)
{
n = str[i];
if (i%24==0) std::cout << std::endl;
else if (i%12 == 0 ) std::cout <<" ";
if (n<16) std::cout << " " << '0' << n;
else std::cout << " " << n;
}
}
int main ()
{
std::string str ( "some\r\ttest\rst\2\athis is \n a ran\5dom\10g\n\nTake this for granted. To bo or not to be\a\a\t\t");
dump_str(str);
}
Print-out of this example:(meaning of the number can be checked in an ascii table google search.)
73 6f 6d 65 0d 09 74 65 73 74 0d 73 74 02 07 74 68 69 73 20 69 73 20 0a
20 61 20 72 61 6e 05 64 6f 6d 08 67 0a 0a 54 61 6b 65 20 74 68 69 73 20
66 6f 72 20 67 72 61 6e 74 65 64 2e 20 54 6f 20 62 6f 20 6f 72 20 6e 6f
74 20 74 6f 20 62 65 07 07 09 09
Send you string to above function dum_str(string), and copy the resultant table appending to your post.
Here's how to split the string at \r and \n characters. This way you can iterate each line separately.
void str_split(const std::string& in, std::vector<std::string>& out, const std::string& delim=" \t\r\n")
{
std::string::size_type firstPos = in.find_first_not_of(delim);
std::string::size_type secondPos = in.find_first_of(delim, firstPos);
out.clear();
if(firstPos != std::string::npos)
out.push_back( in.substr( firstPos, secondPos - firstPos ) );
while( secondPos != std::string::npos )
{
firstPos = in.find_first_not_of(delim, secondPos);
if(firstPos == std::string::npos)
break;
secondPos = in.find_first_of( delim, firstPos );
out.push_back( in.substr( firstPos, secondPos - firstPos ) );
}
}
I recently submitted an assignment that I had started using VS code and the Ubuntu WSL terminal and G++ compiler, but had to switch to Visual Studio 2019 because when I would output several strings on the same line, they would write over each other. The assignment had me read data from a file and place each element into an "ArrayList" (our self made vector class) of "Car" objects and output each cars elements to the user. We would also have to search through the list of cars to find cars of certain models and print all cars of that model. Not only could I not cout all of these elements on the same line, I could not compare elements (strings) with each other. Why would this only happen on Ubuntu? Why can't I clear the cout buffer with std::cout.flush(); or std::cout << std::flush;? Why can't I compare the elements to each other?
I have tried to flush the system in numerous ways (as I have found from other posts) such as: std::cerr, std::cout << std::flush;. The only thing that seems to work is if I use std::endl, however, I need these to be placed on the same line. I also cannot compare two strings using the == operand (or any other). Although, I can compare two int elements just fine.
Here is my (shortened) cars.data (.data was a requirement for the assignment) that held all the cars' elements that were to be stored into an "ArrayList":
1
Tesla
Model 3
Black
2
Chevrolet
Volt
Grey
3
Tesla
Model S
White
4
Nissan
Leaf
White
5
Toyota
Prius
Red
My implementation for storing each element into the "ArrayList":
ArrayList cars_list(15);
std::fstream cars;
cars.open("cars.data");
int tempID;
std::string tempIDstr;
std::string tempMake;
std::string tempModel;
std::string tempColor;
if (cars.is_open())
{
for (int i = 0; !cars.eof(); ++i)
{
std::getline(cars, tempIDstr);
tempID = std::stoi( tempIDstr );
std::getline(cars, tempMake);
std::getline(cars, tempModel);
std::getline(cars, tempColor);
Car tempCar(tempID, tempMake, tempModel, tempColor);
std::cout.flush();
std::cout << tempIDstr << " ";
std::cout.flush();
std::cout << tempMake << " ";
std::cout.flush();
std::cout << tempModel << " ";
std::cout.flush();
std::cout << tempColor << " " << std::endl;
cars_list.push_back(tempCar);
}
}
cars.close();
And a function that I have used to compare strings to search the list:
void searchByMake(ArrayList list)
{
std::string make;
std::cout << "Enter the make you would like to search: ";
std::cin >> make;
std::cin.clear();
std::cin.ignore(10000,'\n');
// Searching through the cars_list for the Make
for (int i = 0; i < list.size(); ++i)
{
Car tempCar = list.get(i);
if (make.compare(tempCar.getMake()) == 0)
{
std::cout << "ID:\t" << tempCar.getID() << "\n"
<< "Make:\t" << tempCar.getMake() << "\n"
<< "Model:\t" << tempCar.getModel() << "\n"
<< "Color:\t" << tempCar.getColor() << "\n\n";
}
}
}
The results of the first segment of code are (I noticed the spaces before each output):
Black 3
Greyvrolet
White S
Whitean
Redusta
The expected output should look like:
1 Tesla Model 3 Black
2 Chevrolet Volt Grey
3 Tesla Model S White
4 Nissan Leaf White
5 Toyota Prius Red
And whenever I try to compare strings the output returns a blank line:
Enter the make you would like to search: Tesla
Expected output would be:
Enter the make you would like to search: Tesla
id: 1
Make: Tesla
Model: Model 3
Color: Black
id: 3
Make: Tesla
Model: Model S
Color: White
My teacher mentioned that the issue may be with Ubuntu itself not being able to clear the buffer even when prompted to, but I still can't find a solution. FYI This is a passed assignment that I can no longer get credit for, this question is strictly out of curiosity and a desire to still use Ubuntu WSL as my development terminal.
Do not control your read loop with !cars.eof() see: Why !.eof() inside a loop condition is always wrong.. The crux of the issue being after your last successful read with the file-position-indicator sitting immediately before end-of-file, no .eofbit() has been set on your stream. You then check !cars.eof() (which tests true) and you proceed.
You then call, e.g. std::getline 4-times never checking the return. The read fails on your very first std::getline(cars, tempIDstr); setting .eofbit(), but you have no way of detecting that, so you continue, invoking Undefined Behavior repeatedly attempting to read from a stream with .eofbit() set, and then using the indeterminate values in tempIDstr, etc.. as if they contained valid data.
Instead either loop continually checking the return of each input function used, or use the return of your read function as the condition in your read loop, for example you could do something similar to:
std::ifstream f(argv[1]); /* open file for reading */
...
while (getline (f,tmp.IDstr) && getline (f,tmp.Make) &&
getline (f,tmp.Model) && getline (f,tmp.Color))
cars_list[n++] = tmp;
Above, your loop only succeeds if ALL of your calls to getline succeed and only then, if all succeed, is your data used in your cars_list.
Now on to your classic carriage-return problem. It is clear the file you are reading from contains DOS line-ending. For example, if you look at the actual contents of your input file, you will see:
Example Input File with DOS "\r\n" Line-Endings
Note the DOS line-endings denoted 0d 0a (decimal 13 10) "\r\n":
$ hexdump -Cv dat/cars_dos.txt
00000000 31 0d 0a 54 65 73 6c 61 0d 0a 4d 6f 64 65 6c 20 |1..Tesla..Model |
00000010 33 0d 0a 42 6c 61 63 6b 0d 0a 32 0d 0a 43 68 65 |3..Black..2..Che|
00000020 76 72 6f 6c 65 74 0d 0a 56 6f 6c 74 0d 0a 47 72 |vrolet..Volt..Gr|
00000030 65 79 0d 0a 33 0d 0a 54 65 73 6c 61 0d 0a 4d 6f |ey..3..Tesla..Mo|
00000040 64 65 6c 20 53 0d 0a 57 68 69 74 65 0d 0a 34 0d |del S..White..4.|
00000050 0a 4e 69 73 73 61 6e 0d 0a 4c 65 61 66 0d 0a 57 |.Nissan..Leaf..W|
00000060 68 69 74 65 0d 0a 35 0d 0a 54 6f 79 6f 74 61 0d |hite..5..Toyota.|
00000070 0a 50 72 69 75 73 0d 0a 52 65 64 0d 0a |.Prius..Red..|
0000007d
Your file has DOS "\r\n" line-endings. How does getline() work? By default getline() read up to the first '\n' character, extracting the '\n' from the input stream, but not storing it as part of the string returned. This leaves an embedded '\r' at the end of each string you store. Why does this matter? the '\r' (carriage-return) does just what its namesake says. Acting like an old typewriter, the cursor position is reset to the beginning of the line. (explaining why you see your output being overwritten -- it is) You write text until a '\r' is encountered and then the cursor is positioned back at the beginning of the line, what is written next overwrites what you just output there.
Instead your file should be a file with Unix/POSIX line-endings:
Example Input File with Unix/POSIX '\n' Line-Endings
Note the Unix/POSIX line-endings are denoted as 0a (decimal 10) '\n':
$ hexdump -Cv dat/cars.txt
00000000 31 0a 54 65 73 6c 61 0a 4d 6f 64 65 6c 20 33 0a |1.Tesla.Model 3.|
00000010 42 6c 61 63 6b 0a 32 0a 43 68 65 76 72 6f 6c 65 |Black.2.Chevrole|
00000020 74 0a 56 6f 6c 74 0a 47 72 65 79 0a 33 0a 54 65 |t.Volt.Grey.3.Te|
00000030 73 6c 61 0a 4d 6f 64 65 6c 20 53 0a 57 68 69 74 |sla.Model S.Whit|
00000040 65 0a 34 0a 4e 69 73 73 61 6e 0a 4c 65 61 66 0a |e.4.Nissan.Leaf.|
00000050 57 68 69 74 65 0a 35 0a 54 6f 79 6f 74 61 0a 50 |White.5.Toyota.P|
00000060 72 69 75 73 0a 52 65 64 0a |rius.Red.|
00000069
To see the effect let's look at a short example that reads your input file, both with Unix/POSIX line-endings and again with DOS line-endings to see the difference in action. The short example could be:
#include <iostream>
#include <fstream>
struct ArrayList {
std::string IDstr, Make, Model, Color;
};
int main (int argc, char **argv) {
if (argc < 2) {
std::cerr << "error: insufficient input.\n" <<
"usage: " << argv[0] << " filename.\n";
return 1;
}
std::ifstream f(argv[1]);
ArrayList cars_list[15], tmp;
size_t n = 0;
while (getline (f,tmp.IDstr) && getline (f,tmp.Make) &&
getline (f,tmp.Model) && getline (f,tmp.Color))
cars_list[n++] = tmp;
for (size_t i = 0; i < n; i++)
std::cout << " " << cars_list[i].IDstr
<< " " << cars_list[i].Make
<< " " << cars_list[i].Model
<< " " << cars_list[i].Color << '\n';
}
Now let's look at the output if your file has Unix/POSIX line endings:
Example Use/Output
$ ./bin/arraylist_cars dat/cars.txt
1 Tesla Model 3 Black
2 Chevrolet Volt Grey
3 Tesla Model S White
4 Nissan Leaf White
5 Toyota Prius Red
Now lets look at the output after reading the file with DOS line ending:
$ ./bin/arraylist_cars dat/cars_dos.txt
Black 3
Greyrolet
White S
Whiten
Redusa
That looks curiously similar to the output you report. Hint, in WSL you should have a tool called dos2unix (which converts line-endings from DOS to Unix). Use it on your input file, e.g. dos2unix filename. Now re-run your program (after fixing your read loop) using the file as input and your problem should disappear.
(if you don't have dos2unix installed, then install it, e.g. sudo apt-get dos2unix)
Look things over and let me know if you have further questions.
What is the greatest product of four adjacent numbers in the same direction (up, down, left, right, or diagonally) in the 20×20 grid?
08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08
49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00
81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65
52 70 95 23 04 60 11 42 69 24 68 56 01 32 56 71 37 02 36 91
22 31 16 71 51 67 63 89 41 92 36 54 22 40 40 28 66 33 13 80
24 47 32 60 99 03 45 02 44 75 33 53 78 36 84 20 35 17 12 50
32 98 81 28 64 23 67 10 26 38 40 67 59 54 70 66 18 38 64 70
67 26 20 68 02 62 12 20 95 63 94 39 63 08 40 91 66 49 94 21
24 55 58 05 66 73 99 26 97 17 78 78 96 83 14 88 34 89 63 72
21 36 23 09 75 00 76 44 20 45 35 14 00 61 33 97 34 31 33 95
78 17 53 28 22 75 31 67 15 94 03 80 04 62 16 14 09 53 56 92
16 39 05 42 96 35 31 47 55 58 88 24 00 17 54 24 36 29 85 57
86 56 00 48 35 71 89 07 05 44 44 37 44 60 21 58 51 54 17 58
19 80 81 68 05 94 47 69 28 73 92 13 86 52 17 77 04 89 55 40
04 52 08 83 97 35 99 16 07 97 57 32 16 26 26 79 33 27 98 66
88 36 68 87 57 62 20 72 03 46 33 67 46 55 12 32 63 93 53 69
04 42 16 73 38 25 39 11 24 94 72 18 08 46 29 32 40 62 76 36
20 69 36 41 72 30 23 88 34 62 99 69 82 67 59 85 74 04 36 16
20 73 35 29 78 31 90 01 74 31 49 71 48 86 81 16 23 57 05 54
01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48
My c++ code :
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream fd ("file.txt"); // this file contains the grid
int A[463],max=-1;
for (int i=1;i<=400;i++){
fd >> A[i];
}
for (int i=463;i>400;i--){ // zero out array numbers that exceed 400
A[i]=0;
}
for (int i=1;i<=400;i++){
if ((A[i]*A[i+20]*A[i+40]*A[i+60])>max){ //vertical maximum
max=A[i]*A[i+20]*A[i+40]*A[i+60];
}
if ((i%20!=0)||((i-18)%20!=0)||((i-19)%20!=0)){ //diagnol \ maximum (first if checks if out of bounds)
if ((A[i]*A[i+21]*A[i+42]*A[i+63])>max){
max=A[i]*A[i+21]*A[i+42]*A[i+63];
}
}
if (((i-1)%20!=0)||((i-2)%20!=0)||((i-3)%20!=0)){// diagnol / maximum (first if checks if out of bounds)
if ((A[i]*A[i+19]*A[i+18]*A[i+17])>max){
max=A[i]*A[i+19]*A[i+18]*A[i+17];
}
}
if ((i+2)%20!=0){ // horizontal maximum (first if checks if out of bounds)
if ((A[i]*A[i+1]*A[i+2]*A[i+3])>max){
max=A[i]*A[i+1]*A[i+2]*A[i+3];
}
}
}
cout <<max;
fd.close();
return 0;
}
Whit this code I get the answer 51267216 which is the vertical answer, but this answer is not correct, I'm thinking there is a problem with my diagnol checking.
If I output the diagnol maximum I get something 4xxxxxxx which is close to the maximum vertical but not correct.
P.S I check both / and \ diagnols.
First thing you should do is using 2D Arrays. They make your problem look a lot easier. Second thing - use constants. Don't use meaningless numbers which could seem to a second person like black magic. Third thing - use a right, left and down padding of three rows and three columns. Last thing to remember - write your code like someone else would have to read it. Even if only you and a computer will see the code - it's a good habit and gives you an advance when you apply for a job.
const int parameters = 20;
const int padding = 3;
int tab[parameters + padding][parameters + padding];
See? It's a lot easier to read and tells you what you're doing. The extra columns and rows will spare us a lot of if if statements. You can pack the program in functions - it'll be easier to read and easier to use. Normally I would do it by defining a new class, but for algorithm purposes I'll use global variables and functions.
#include <fstream>
using namespace std;
const int parameters = 20;
const int padding = 3;
int tab[parameters + padding][parameters + 2*padding];
int diagonalLeft(int i, int j) {
int answer = 1;
for (int u = 0; u <= padding; u++)
answer *= tab[i - u][j - u];
return answer;
}
int diagonalRight(int i, int j) {
int answer = 1;
for (int u = 0; u <= padding; u++)
answer *= tab[i - u][j + u];
return answer;
}
int vertical(int i, int j) {
int answer = 1;
for (int u = 0; u <= padding; u++)
answer *= tab[i + u][j];
return answer;
}
int horizontal(int i, int j){
int answer = 1;
for (int u = 0; u <= padding; u++)
answer *= tab[i][j + u];
return answer;
}
int max(int a, int b) {
if (a > b)
return a;
return b;
}
int main() {
ifstream input("file.txt");
for (int i = 0; i < parameters; i++)
for (int j = padding; j < parameters + padding; j++)
input >> tab[i][j];
int maximum = 0;
int temp;
for (int i = 0; i < parameters; i++) {
for (int j = padding; j < parameters + padding; j++) {
temp = diagonalLeft(i, j);
temp = max(temp, diagonalRight(i, j));
temp = max(temp, vertical(i, j));
temp = max(temp, horizontal(i, j));
maximum = max(maximum, temp);
}
}
cout << maximum << endl;
input.close();
return 0;
}
If you the code is not only easier to read, it's easier to find bugs in a clean code. Don't even try to find them in your code, because it'll take you even several hours.
There is a reason why two dimensional arrays were invented. Your could have more bugs than you think you have, because of this one dimensional array.
Look at the size of your if statements. Mine are shorter and easier to debug. The padding around the table leaves me without exceptions like the ones you have.
Indeed, the tests for diagonals look wrong.
For instance, the \ diagonal test should be:
// not starting from the 3 rightmost columns,
// not starting from the 3 bottom rows
if ((i%20 <= 16) && i < 20*17)
The other diagonal should be:
// idem above:
if ((i%20 >= 3) && i < 20*17)
Edit :
The indices for the top-right to bottom-left diagonal are wrong: they should be {0, 19, 2*19, 3*19}, ie {0, 19, 38, 57}:
Here is the whole for loop, outputting the correct result: (70600674)
for (int i=0; i < 400; ++i) // <- I used a regular array indexed from 0
{
if (i < 17 * 20)
{
if ((A[i] * A[i + 20] * A[i + 40] * A[i + 60]) > max)
{
max = A[i] * A[i + 20] * A[i + 40] * A[i + 60];
}
if (i % 20 <= 16)
{
if ((A[i] * A[i + 21] * A[i + 42] * A[i + 63]) > max)
{
max = A[i] * A[i + 21] * A[i + 42] * A[i + 63];
}
}
if (i % 20 >= 3)
{
if ((A[i] * A[i + 19] * A[i + 38] * A[i + 57]) > max)
{
max = A[i] * A[i + 19] * A[i + 38] * A[i + 57];
}
}
}
if (i % 20 <= 16)
{
if ((A[i]*A[i+1]*A[i+2]*A[i+3])>max)
{
max=A[i]*A[i+1]*A[i+2]*A[i+3];
}
}
}
On a side note, a 2 dimensional array would have been much more clear (and you probably wouldn't have made such a mistake)