Read/write to file, bytes go missing, might be char overflow - c++

I am new to programming and sometimes even the stuff I write remains mysterious to me. This is my first time asking for help on the internet.
I have a problem here and I haven't been able to solve it for some time now.
This is what I want to do:
Read byte by byte from a file into a vector, modify the bytes and write them back.
This is what happens:
All the encryption stuff seem to work, but somehow after several of these operations a part of the file goes missing.
In the byte modifying process I use char overflows, that means I add some random number to each part of my vector and write it back as a whole.
In my opinion this could be some kind of arithmetic overflow issue I don't know about.
By the way, I use Qt SDK and Windows environment, in case that helps.
Here's the code fragment:
void crypt(string * password,string filename, int sign){
vector<char> stack;
ifstream is;
is.open(filename.c_str());
char c;
for (int i = 0; !is.eof(); i++){
is >> noskipws >> c;
stack.push_back(c);
}
stack.pop_back();
is.close();
int code = 0;
double x;
char method = 0;
int var;
for (int i = 0; i < password->size(); i++)
code += password->at(i);
for (int i = 0; i < (stack.size()); i++){
// some unrelated stuff skipped
if (sign == 1)code += stack[i];
stack[i] += var*method*sign; //<----this might be the cause!
if (sign == -1)code += stack[i];
method = 0;
}
ofstream os;
os.open(filename.c_str());
for (int i = 0; i < stack.size(); i++){
os << noskipws << stack[i];
}
os.flush();
os.close();
}
Sorry for the mess in the code, I kind of wrote it for testing.
Any ideas will be appreciated.

You are opening your files in "text" mode, this can cause problems especially since your output characters will most certainly end up outside the range of printable ASCII characters. This can cause issues as on windows for example, when you try to output the value 0xD (carriage return), the library will convert that into a 0xD followed by 0XA (line feed).
So, try to open your files in binary mode like this:
os.open(filename.c_str(), ios::binary);

Related

Taking user input in C++ without c++ standard library classes

I'm trying to take user input from the console without using the c++ standard library classes. Here's my code
while(true){
std::string line = " ";
while (getline(std::cin, line)) {
std::string arr[100];
int i = 0, len = 0;
for (int j=0; j < line.length(); j++) {
if(line[j] ==' ' || line[j] == '\n'){
std::string word = line.substr(i, j);
arr[len] = word;
len++;
i = j;
}
}
for (int k = 0; k <len ; ++k) {
std::cout<<arr[k]<<std::endl;
}
}
//break;
}
The idea is to identify each word and store it in an array. However this program only identifies the first word. Any idea, what am I doing wrong here.
In reading this, it would seem your problem lies on the line std::string word = line.substr(i, j);. You have to understand that substr's arguments are not "from i to j", but "from i, j characters". Read the documentation. :)
I haven't tested this, so it might not be perfect, but the principle is there.
while(true){
std::string line = " ";
while (getline(std::cin, line)) {
std::string arr[100];
int num_chars = 0, word = 0;
for (int i=0; i < line.length(); i++) {
/*We increment i, so every non-space character is one we
* will include in the word.*/
num_chars++;
if(line[i] ==' ' || line[i] == '\n'){
/*We want all characters from i to i+num_chars, that is
* we want all characters from j, forward i indices.
*/
std::string word = line.substr(i, num_chars);
arr[word] = word;
word++;
//We reset i here, in prep for parsing the next word.
i = 0;
}
}
for (int k = 0; k <len ; ++k) {
std::cout<<arr[k]<<std::endl;
}
}
//break;
}
Two other considerations:
1) Beware the single-letter variables, as it makes it far harder to read your code later. i is standard for a loop iterator or index, with j being the next when you're nesting for loops. However, i is not suitable for the "length of the word". Similarly, len is not suitable for the index of the word being stored. I changed the variables in the code to make it easier to read.
2) I would seriously consider revisiting your loop structure. while is common and very useful, but it is also highly prone to infinite loops. In fact, while(true) IS an infinite loop, so if you don't reach break for whatever reason, you'll wind up with some serious issues.
--
I would also agree that, if you want to avoid "STL" (and, actually std:: and stl are commonly confused, but are not the same thing...so let's say you want to avoid std), you'll want to avoid std::string and std::cin. Use C-strings and scanf/printf instead, as Nidhoegger suggested. It is more efficient than the std options, but it also more prone to the errors and "undefined behaviors" characteristic to C. It would take more effort, but would yield a more efficient result if you do it right.
While we're at it, I do NOT recommend std::stringstream unless your other tools cannot do the job well. That class has serious performance and efficiency problems, which are well-documented. I only recommend using it in cases where writing your own code with std::string and such would be either too laborious or have a high probability of being inefficient. This is NOT one of those cases.

C++ Add random characters into a string array

So I want to create 1000 words with a length of 5 random characters. In my main I have word[1000] but when I try to run this code, it gives me an error saying "Expression:string subscript out of range". I'm not sure why it does that because I thought string arrays were 2 dimensional? If anyone could tell me why my code is wrong I'd appreciate it. Thanks.
void createText(string w[], int seed) {
char ch;
srand(seed);
for(int i = 0; i < 1000; i++) {
for(int j = 0; j < 5; j++) {
ch = ('A' + rand() % 26);
w[i][j] = ch;
}
}
for(int i = 0; i < 1000; i++) {
cout << w[i];
}
cout << endl;
}
I suppose that the array w does not have 1000 elements, also remember that here you will get a copy of string w[]. Better would be passing a pointer to w (string* w), then You will have very clearly what is wrong. remember also that cout writes the string out untill it reaches a '\0' character, this also might be the cause. Quick session with gdb will help:
gdb program
...
run
bt full
should pinpoint Your problem. if it's some kind of IDE, learn how to debug in it. Valgrind or some other memcheck like visual leak detector or luke stackwalker will also show you some tips about bad initialization or unmentioned memory leaks.
If an array is bidimensional, you can't print its values like w[i]. You must print always keeping in mind that the array is bidimensional, which means that the output must be done like cout << w[i][j];
In addition, you're passing an array of strings as an argument, and what you're doing is add characters to every single position, which means that you won't actually have nothing but 1000 characters inserted into that string (because you actually added "one-char" strings), so you'll only put 200 words with a length of 5 characters each one. Insert strings directly, and you'll get your 1000 words, but first find a way to build strings with random characters.
Something like:
for(conditions){
for(conditions){
build a word
}
array[x][y] = string
}
I guess it is similar to what you intended to do

C++ how make a 2D array using strings and spaces instead of ints

I am making a Sudoku program and my i have a test.txt file that reads
53__7____
6__195___
_98____6_
8___6___3
4__8_3__1
7___2___6
_6____28_
___419__5
____8__79
where the "_" are actually spaces. The reason i give you _ is so you can see that there are literally only 9 characters on each line.
I was thinking that I would have to do something like having GRID[row][column], however I frankly don't know what types I should put my arrays as and I am just lost.
I simply want to make it so when i want to output say GRID[0][0] it returns 5, while if i ask for GRID[0][3] it returns a ' '.
It is getting it so the array store both the numbers and the spaces is where i am getting completely lost
What I currently have tried so far:
int main()
{
ifstream myfile(test.txt);
string line;
char sudoku_grid[9][9];
if (myfile.is_open())
{
while(myfile.good())
{
getline(myfile, line);
cout << sudoku_grid[line] << endl;
}
myfile.close();
}
else cout << "error";
return 0;
}
it returns the error line 12: no match for 'operator [ ]' in 'sudoku_grid[line]'
Here is my attempt though guidelines through you guys:
int main()
{
ifstream myfile(test.txt);
string line;
char sudoku_grid[9][9];
if (myfile.good())
{
for(int i = 0; i < 9; i++)
{
getline(myfile, line);
for(int j = 0; j < 9; j++)
{
if (line[j] == ' ')
sudoku_grid[j][i] = -1;
else sudoku_grid[j][i] = line[i];
}
cout << sudoku_grid[i] << endl;
}
myfile.close();
}
else cout << "error";
return 0;
}
The result is a very awkward answer of strange letters and a new numbers.
I'll just give you the algorithm/logic, not going to write the code for you. Try it and come back when stuck.
Initialize output in memory 2D array: numbers[9][9]
Open the file
Until there is no line left in the file:
a. Get the line i
b. Until there are no more characters in the line:
b1. Get each character of the line c
b2. If the character is not space, then numbers[i]=c, else numbers[i]=-1
Your array can be made up of int and in b2 if a whitespace is encountered you can insert -1 to indicate the absence of a number. Of course your code manipulating numbers array needs to take that into account.
Since you need to store both chars and integer type values, use char. each of your integer lies in the range 0-9, so can be stored as a character.
char Grid[9][9];
now you can read each character from the string and store it in the array. It will not only keep your spaces intact but also each character. Always remember to use ASCII codes to access the elements of the grid. For 0-9, ASCII codes are 48-57, ASCII code for space is 32.
Hope it helps...
Edit code: Here is the simplest example... PLace your test file in d:, or edit the path of file in code
int main (void)
{
FILE *fp = fopen("d:\\test.txt","r");
char sudoku_grid[9][9], ch;
// I am assuming that file is valid and data in that is also valid
if(fp)
{
for(int i = 0; i < 9; i++)
{
for(int j = 0; j < 9; j++)
{
//too read each character
ch = fgetc(fp);
sudoku_grid[i][j] = ch;
}
// to read '\n' from the line
ch = fgetc(fp);
}
//for checking if data went correctly
for(int i = 0; i< 9;i++)
{
for(int j= 0; j<9;j++)
cout<<sudoku_grid[i][j];
cout<<endl;
}
}
return 0;
}
In the first code you get the error message because sudoku_grid can
only be indexed by numbers and not by strings.
In the second code the line
sudoku_grid[j][i] = line[i];
should probably be
sudoku_grid[j][i] = line[j];
Does this answer your question?

itoa creates an infinite loop in C++

This is very strange. itoa(); seems to create an infinite loop.
for(int i = 0; i < 10; i++)
{
char buffer[1];
itoa(i, buffer, 10);
std::cout << buffer;
}
Why on earth does it do that? I've tried using different variables than i, numerical values without variables (i.e. itoa(1, buffer, 10);), it still keeps ending up in an infinite loop.
I've tried to google without much success, I found an old mail about it here.
I am using Windows XP 32 bit and Code::Blocks (with GCC) as a compiler.
Does anyone know what's wrong? Thanks in advance.
itoa null-terminates the string it produces, but you haven't made buffer large enough to hold the terminating NUL character. Try:
for (int i = 0; i < 10; i++)
{
char buffer[2];
itoa(i, buffer, 10);
std::cout << buffer;
}
Why on earth are you using a general number conversion routine for single digits?
for (int i = 0; i < 10; i++)
std::cout << char('0' + i);
(You need the cast back to char so that the compiler uses the correct overload of <<. The C++ standard guarantees that the character constants '0' through '9' have consecutive numeric values.)
Your buffer is too small -- itoa will write a null-terminated string, so your buffer will need at a minimum 2 bytes to hold values from 0-9.

Overflow or Memory error c++

This could be considered a homework question.
This problem is wel known: "you have a triangle of numbers and you have to find the greatest sum"
well no problem, I've made a solution in python some time ago, works flawless.
But now in c++, the solution is 75256, my answer is 9729.
So the problem is that the type short overflows.
So to fix this, I assumed changing my array to type int would solve everything.. but then, when declaring an array a[1001][1001] it freezes (i guess memory error).
anyone know what to do?
I tried something with another int, and whenever the value in a got bigger than 32767 it would increment, but my solution then still is off 300? (the code works - tested on many smaller ones)
#include <iostream>
#include <fstream>
int main() {
std::ofstream fout ("numtri.out");
std::ifstream fin ("numtri.in");
short trifield[1001][1001] = {0};
int Rows, tmp=0;
fin >> Rows;
for (int x = 0; x<Rows;x++)
for (int nr = 0; nr<=x;nr++){
fin >> tmp;
trifield[x][nr] = tmp;}
for (int y = (Rows-2); y > -1; y--)
for (int x = 0; x <= y+1; x++) {
int a = trifield[y+1][x];
int b = trifield[y+1][x+1];
if (a > b) trifield[y][x] += a;
else trifield[y][x] += b;
}
fout << trifield[0][0] << std::endl;
return 0;
}
note: I'm not looking for the solution, just a good way to deal with overflows, examples appreciated!
If you have issues with memory try to assign your array dynamically:
short** trifield = new short[1001][1001];
You have an array of 1001x1001 shorts... that's 1002001*2 bytes. That's all going on your local stack. Depending on your system that could be TOO big. Try allocating the space for your 'trifield' with a malloc instead. See what that does for you
You get a stack overflow instead of a numeric overflow!
Move the array to static memory outside of main, so it doesn't use the stack.
The way I check for overflow is to check for an obviously bogus result. For instance,
if (myInt + 1 < myInt) {
// Overflow condition
cerr << "Overflow" << endl;
}
else {
myInt++;
}
Overflowing an int is an UB. Overflowing an unsigned int value is defined in the standard.
So, the only way is to manually check the values before doing the operation, and make sure it doesn't overflow.