Memory Violation in c++ - c++

I'm getting the following error when I run my code:
Unhandled exception at 0x00F66754 in KSU.CIS308.Project5.exe: 0xC0000005: Access violation writing location 0xFDFDFDFD.
I assume it is due to having memory for the pointer but not what it is pointing too. I have no clue how to assign it though. Here is the code, it is the constructor method for the Matrix objects:
Matrix::Matrix(int row, int col)
{
this->rows = row;
this->cols = col;
this->arr = new int*[row];
for (int i = 0; i < row; i++)
{
this->arr[i] = new int[col];
}
}
The this->arr = new int*[row]; is what is throwing it. It is a pointer to a pointer so that I can store the matrix like a 2-d array. Any help is much appreciated.
I think it is also being thrown later but if I can figure one out the rest should be easy to fix as well.
Arr is declared like this in the header file:
int **arr;
Okay so when debugging I found that col is getting passed 0 which might explain the error.
I thought I calculated the right value for passing it. Here is the main file. I use to strtok's to put everything into a Vector. User input format is: "1 2 3 // 3 2 1" Where "//" is row break.
int main() {
vector<int> v1;
int rowCountA = 1;
int colCountA = 0;
cout << "Enter First Matrix (put // to denote row breaks): ";
char buff[200];
char *token;
char *tok;
scanf("%s", buff);
token = strtok(buff, "//");
while (token != NULL)
{
tok = strtok(token, " ");
while (tok != NULL)
{
v1.push_back(atoi(tok));
tok = strtok(NULL, " ");
colCountA++;
}
token = strtok(NULL, "//");
rowCountA++;
}
A = new Matrix(rowCountA, colCountA/(rowCountA+1));
for (int i = rowCountA; i > 0; i--)
{
for (int k = colCountA; k < 1; k--)
{
A->setElem(i, k, v1.back());
v1.pop_back();
}
}
}

As you've found out, the problem is passing 0 as one of the dimensions, the 2D-array creation is otherwise correct. You shouldn't ever allow col to be 0, worst case scenario (let's say empty input), make it be 1.
Anyway you aren't parsing the input correctly:
scanf("%s") is returning only the first number, because it stops at the first space. Your code should use fgets() instead.
Using C string functions, you should replace your scanf("%s", buff); with:
fgets(buff, sizeof(buff)/sizeof(char), stdin);
But, you can't nest calls to strtok(). When you split the string on // and then call strtok on each token, you can no longer retrieve the next row because it forgets about the tokenizing based on //.
Here is a rough equivalent to the parsing you're doing using C++ i/o (although the code does have some other errors):
string sbuff;
getline(cin, sbuff);
stringstream ss(sbuff); // header file <sstream>
while (ss >> sbuff) {
if (sbuff == "//") {
rowCountA++;
}
v1.push_back(atoi(sbuff.c_str()));
colCountA++;
}

Related

"the readable size is 'x*4, but 8' bytes may be writted/read" with arrays

So I have a program, which helps me finding a cycles in graph by adjacency matrix. I have done everything, except output.
Realization
So, upon clicking exectute button, from masked edit control, an number up to 99 taken to for making a size of some arrays. Then I am creating 2d array **arr to fill it with zeros, and after that via for I fill info from text written in normal edit control. After this step I fill vector with edges from that array and doing DFS for that graph.
Now about problem
Like I said, I have 2d array. The whole procedure of filling it with zeros:
int **arr;
arr = new int* [x];
for (int i = 0; i < x; i++)
{
arr[i] = new int[x];
}
for (int i = 0; i < x; i++)
{
for (int j = 0; j < x; j++)
{
arr[i][j] = 0;
}
}
And with the next procedure (taking adjacency matrix from edit control) lies the warning #1:
int i = 0, j;
int lpos = 0;
for (CString line = s.Tokenize(_T("\r\n"), lpos); lpos > 0; line = s.Tokenize(_T("\r\n"), lpos))
{
j = 0;
int cpos = 0;
for (CString cell = line.Tokenize(_T(" "), cpos); cpos > 0; cell = line.Tokenize(_T(" "), cpos))
{
int num;
num = _wtoi(cell);
arr[i][j] = num;
j++;
}
i++;
}
Warning C6386 Buffer overrun while writing to 'arr[i]': the writable size is 'x*4' bytes, but '8' bytes might be written.
And before making output, I also put in another vector cycles and it also has warning #2:
for (int i = 1; i <= edges; i++) {
if (mark[i] != 0) {
int k = mark[i];
cycles[k].push_back(i);
}
}
Warning C6385 Reading invalid data from 'mark': the readable size is 'x*4' bytes, but '8' bytes may be read.
The problem is, when I tested output (adjacency matrix 7x7, all filled with 1), it catches an exception for those 2 pieces, which is being warnings. The exceptions is: Exception thrown at 0x00007FF6DD63AD7A in CTabControl.exe: 0xC0000005: Access violation writing location 0x00000000FDFDFDFD.
What I tried
For now, I tried to use make_unique pointer as an alterative for * pointer on mark, which was declared previously like this: int *mark = new int[x]; (changed to auto mark = make_unique<int[]>(x);). After change, there is a new error appear:
E0413 no suitable conversion function from "std::unique_ptr<int [], std::default_delete<int []>>" to "int *" exists
It points out to the function, where I use mark array: dfs_cycle(1, 0, color, mark, par, cyclenumber);
The function declared like this:
void dfs_cycle(int u, int p, int color[], int mark[], int par[], int& cyclenumber)
{
// ........
}
What can I do here to fix that?
EDIT
I think I found the problem, yet for now I can't find a solution. So, when the text is being read from text box, where adjacency matrix is, I am filling up the array with the contents of tokenized text. Here's how I am doing it:
int i = 0, j; int lpos = 0;
for (CString line = s.Tokenize(_T("\r\n"), lpos); lpos > 0; line = s.Tokenize(_T("\r\n"), lpos)){
j = 0;
int cpos = 0;
for (CString cell = line.Tokenize(_T(" "), cpos); cpos > 0; cell = line.Tokenize(_T(" "), cpos))
{
int num;
num = _wtoi(cell);
arr[i][j] = num;
j++;
}
i++;
}
When I try to make arr a 2d vector, I stumbled upon "out of range" error. So, that means I have to somehow tokenize my text and put it in array. I haven't figured out how.

C++. How can I free memory correctly?

Written code to find and remove the largest word in a string without the using of library functions. Everything works fine. But when I want to free memory, the result is negative (displays an empty line). If you remove the call to the memory release function, everything will work correctly, but there will be a leak of memory.
How do I fix it? Please help me.
#include <iostream>
using namespace std;
int length(char *text) // string length
{
char *begin = text;
while(*text++);
return text - begin - 1;
}
int size(char **text) // size of two-dimensional array
{
int i = 0;
while(text[i]) i++;
return i;
}
void free_memory(char **text)
{
for(int i=0; i<size(text); i++)
delete text[i];
delete [] text;
}
char **split(char *text, char delim)
{
int words = 1;
int len = length(text);
for(int i=0; i<len; i++)
if(text[i] == delim) words++;
char **result = new char*[words + 1];
int j = 0, t = 0;
for(int i=0; i<words; i++)
{
result[i] = new char[len];
while(text[j] != delim && text[j] != '\0') result[i][t++] = text[j++];
j++;
t = 0;
}
result[words + 1] = nullptr;
return result;
}
char *strcat(char *source, char *destination)
{
char *begin = destination;
while(*destination) destination++;
*destination++ = ' ';
while(*source) *destination++ = *source++;
return begin;
}
char *removeWord(char *in_string)
{
char **words = split(in_string, ' ');
int max = length(words[0]);
int j = 0;
for(int i=0; i<size(words); i++)
if(max < length(words[i]))
{
max = length(words[i]);
j = i;
}
int index;
char *result;
if(!j) index = 1;
else index = 0;
result = words[index];
for(int i=0; i<size(words); i++)
if(i != j && i != index)
result = strcat(words[i], result);
free_memory(words); // I want free memory here
return result;
}
int main()
{
char text[] = "audi and volkswagen are the best car";
cout << removeWord(text) << endl;
return 0;
}
In fact, this is C style programming - not C++. I see that your aim is to implement everything from scratch, possibly for practicing. But even then, your code is not designed/structured properly.
Besides that, you also have several bugs in your code:
result[words + 1] = nullptr; must be result[words] = nullptr;
You need result[i][t] = '\0'; after the while loop in split
delete text[i] must be delete [] text[i]
You cannot assign to your result pointer memory from words, then free it and then return it for use by the caller.
There is at least one further bug in the second half of removeWord. It would be tedious to try to understand what you are trying to do there.
You might want to start with a simpler task. You also should proceed step-by-step and check each function for correctness independently first and not implement everything and then test. Also take a look at the tool valgrind for memory checking - if you use Linux.
The way you free memory correctly is to use RAII:
Only use new and new[] in constructors
Pair those with delete and delete[] in the corresponding destructor
Use automatic storage duration objects as much as possible
If you are specifically not using std::string and std::vector etc, for reasons of learning pointers, you will end up writing some small number of classes that resemble string and vector and unique_ptr, and then you go about programming as if you were using the std versions.
You have two issues. First is that result is assigned to a memory location in words. Second, is that you're storing the result of strcat in words[i] which will likely not have enough room (see strcat documentation).
result = new char[len(in_string)+1]; // +1 for space for null char
// the old loop reversed the word order -- if you want to keep doing
// that, make this a descending loop
for(int i=0; i<size(words); i++)
if(i != j && i != index)
strcat(result, words[i]);
free_memory(words);
return result;
So that when you free words, what result points to is also free'd. You would then need to free your result in main().
int main()
{
char text[] = "audi and volkswagen are the best car";
char * result = removeWord(text);
cout << result << endl;
delete[] result;
return 0;
}

How to read integers from file into dynamic array

I am trying to read integers from a text file and put them into a dynamic array that will be represented as vectors and matrices for an assigment.
An example of a few lines from the input file:
3#456
33#123456789
The numbers before the pound sign represent the elements of the vector or matrix, so 3# would mean a three element vector and 33# would mean a matrix with 3 rows and 3 columns.
Reading those isn't really a problem as we were told we can assume we know which lines are matrices and which are vectors, however, I have never working with C++ file I/O so I don't know how to iterate through the numbers 4,5,6 and put them into a 3, 9, 12, etc, element dynamically created array. Here's somewhat of a sample of what I'm working with.
int *a;
int size_a;
char x;
ifstream infile("input.txt");
if (infile.is_open())
{
infile >> size_a;
// The x is basically a junk variable used to go past the '#'
// when reading the file
infile >> x;
a = new int[size_a];
}
After that, I have no real idea of how to loop until the end of the line and put the remaining elements in the array. For example in this line, the numbers 4, 5, and 6 would need to be put into the a array, then break from adding elements and go to the next line to work on the next array, which I don't know how to do either. Any ideas?
The below code will do this for you. Note that you do not need to use new here - you should just use a std::vector. In that case, the number before the '#' is unneeded as you do not need to specify the size of the array when you create it.
For that reason I have used new here anyway to show you how to read both parts of the file.
#include <iostream>
#include <fstream>
#include <string>
int main()
{
std::ifstream file("input.txt");
if(file.good()) {
std::string line;
std::getline(file, line);
std::string::size_type pos = line.find('#');
std::string strSize = line.substr(0, pos);
std::string strValues = line.substr(pos + 1);
int size = 0;
for(char c : strSize) {
if(size == 0)
size = static_cast<int>(c - '0');
else
size *= static_cast<int>(c - '0');
}
int* values = new int[size];
for(int i = 0; i < size; ++i) {
values[i] = static_cast<int>(strValues[i] - '0');
}
std::cout << "Array of size " << size << " has the following values:" << std::endl;
for(int i = 0; i < size; ++i) {
std::cout << values[i] << std::endl;
}
delete[] values;
}
}

Variables being overwritten when using new

I'm having a problem with dynamic memory allocations in c++. I have to write a function that solves a maze stored in a .dat file. The walls are made of # separated by a space, and some points are words that need to be read in to an arbitrary length c string. This c string is then stored in the maze array. My problem is that my c strings keep overwriting previous ones in memory. How can I tell the program not to overwrite certain blocks of memory?
This is the function the initialises the maze array:
int LoadMaze(Maze& maze, int& width, int& height, char fname[])
{
ifstream ifs(fname);
int stringLength;
char inputChar;
char* newCString;
if (ifs.good())
{
ifs >> width >> height;
maze = new char*[width*height];
for (int i=0;i<width*height;i++)
{
stringLength = 0;
inputChar = '1';
while(inputChar != ' ')
{
inputChar = ifs.get();
if(inputChar != ' ' && inputChar != '\n')
{
newCString = resizeChar(newCString, stringLength);
newCString[stringLength++] = inputChar;
}
}
//maze = resizeMaze(maze, i);
maze[i] = newCString;
}
ifs.close();
return 1;
}
else
{
cerr << "File not found." << endl;
return 0;
}
}
Since the C string has to be an arbitrary length, resizeChar increases the cstring size by one. Then the pointer to that cstring is stored in maze.
char* resizeChar(char* stringStart, int oldSize)
{
int counter = 0;
char* tempPtr = new char[oldSize + 1];
for(counter = 0; counter < oldSize; counter++)
{
*(tempPtr + counter) = *(stringStart + counter);
}
delete[] stringStart;
return (tempPtr);
}
You are passing an uninitialized value to your function:
char* newCString;
....
newCString = resizeChar(newCString, stringLength);
To fix this you need to give newCString a sensible initial value, and make sure that resizeChar can handle that scenario.
It would be better to initialize newCString each time around the loop. That also avoids the problem that you are using the same buffer for every row of the maze.
Another major problem is that you never null-terminate the strings you are building. So once you have gone maze[i] = newCString;, that row is just pointing to some characters but you have lost the information of how many characters are in the string. And if you try to output this string then you will buffer overflow and start outputting garbage.
You need to allocate 1 more byte than the number of characters in the string, and make the last one of those be '\0'.
The question is how do I stop new values of newCString from being written in the same memory location as previous ones?
If you replace the old value of a variable with a new one, then the old value will be overwritten because a variable, during its life, does not move in memory. If you don't want to change the value, simply don't write code that changes it. Set the value of newCString to the value you want it to hold and do not change its value from then one.

Append user input to array in C++

I'm trying to write a program that asks for user inputs (one at a time, and continues until the user interrupts somehow) and stores them in an array. In python, I can easily append new inputs to the end of an existing list, but this doesn't work in C++. What's the easiest way to do this without involving vectors? I'm thinking of deleting the array each time and creating a new one that's larger, but this seems like a pain.
This is some code I wrote up to do this, it basically creates a new array and copies over data from the old array. Hopefully this can help you. To give you an example of its usage, there is a demonstation area that inputs data from stdin until the user types "END" and the prints it to stdout excluding the "END".
#include <cstdio>
#include <iostream>
#include <cstring>
//Assuming you are storing strings
//Set this to the appropriate max length. The name of this may be misleading,
const int MAX_STRING_LENGTH = 128; //any other suggestions?
char** userInput;
int userInputUsed;
int userInputSize;
void append (char* text, int textLength) {
//If we have used up all the space in the array
if (userInputUsed >= userInputSize) {
//How large you want the new array to be compared to
//the original size (userInputSize)
int newArraySize = 2*userInputSize;
//Create the new array
char** newUserInput = new char*[newArraySize];
//We are only creating the new part of the array
//Another way you could do this is to create the strings as you go
for (int i = userInputUsed;i < newArraySize;i++) {
newUserInput[i] = new char[MAX_STRING_LENGTH];
}
//Copy everything over, I am setting our pointers to the old data
for (int i = 0;i < userInputUsed;i++) {
newUserInput[i] = userInput[i];
}
//Delete the old array
delete[] userInput;
//Set the new array to the old array
userInput = newUserInput;
//Update the size of our array;
userInputSize = newArraySize;
}
//Copy the input to userInput
memcpy(userInput[userInputUsed], text, textLength);
userInputUsed++;
}
int main () {
//Initialise userInput, initialise to whatever size you deem fit
userInputSize = 1;
userInput = new char*[userInputSize];
for (int i = 0;i < userInputSize;i++) {
userInput[i] = new char[MAX_STRING_LENGTH];
}
//Start of demonstration
//Get input until the user types "END"
for (bool running = true;running;) {
char temp[MAX_STRING_LENGTH];
//Scans in until some whitespace, this may not work if
//you want to scan in whole lines which end in '\n'
//scanf("%s", temp);
//or
std::cin >> temp;
//End if input is "END"
if (strcmp(temp, "END") == 0) {
running = false;
} else {
append(temp, strlen(temp));
}
}
//Print out the user input, to see that it is inputed correctly
for (int i = 0;i < userInputUsed;i++) {
//printf("%s\n", userInput[i]);
//or
std::cout << userInput[i] << std::endl;
}
//End of demonstration
//Cleanup our user input
for (int i = 0;i < userInputSize;i++) {
delete[] userInput[i];
}
delete[] userInput;
//Stop the program from ending, you may not need this
//while(true);
return 0;
}
Feel free to comment or suggest improvements to this answer.