In this code I am getting numbers from a file, when the first number is the size of the 2D array.
In my code I'm defining
char *filename=new char;
(I have to use char *filename, this is the exercise..)
Everything works fine, until the moment I try to delete. both delete and delete[] gives me error and crashing my program.
This is my full code:
#include <iostream>
#include <fstream>
using namespace std;
double **readmat(char *filename, int *size)/////question 2
{
ifstream read(filename);
cout << filename << endl;
if (!read)
{
cout << "Can't open file!" << endl;
exit(1);
}
read >> *size;
double **mat = new double*[*size];
for (int i = 0; i < *size; i++)
{
mat[i] = new double[*size];
for (int j = 0; j < *size; j++)
{
read >> mat[i][j];
}
}
read.close();
return mat;
}
int main()
{
int size;
char *filename = new char;
filename = "text.txt";
double **arr = readmat(filename, &size);
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
{
cout << arr[i][j]<<" , ";
}
cout << endl;
}
cout << endl;
delete filename; //<-------- this crashed my code
for (int i = 0; i < size; i++)
{
delete[] arr[i];
}
delete[] arr;
return 0;
}
This is how my file looks:
This is what the console app looks like after running the code:
Which is what I am expecting to get, but I get this error:
Does anyone have any idea what could this happen, and what I can do to fix it?
You are trying to delete a char* that is not pointing at memory allocated with new.
On this line:
char *filename = new char;
You do new some memory (a single char, not a string of chars). But then on this line:
filename = "text.txt";
You change the char* pointer to point at completely different memory, thus leaking the memory you new'ed.
Then on this line:
delete filename;
You try to delete the "text.txt" literal, not the char you new'ed. That is why you crash.
For what you are attempting to do, you need to do this instead:
char *filename = new char[strlen("text.txt")+1];
strcpy(filename, "text.txt");
...
delete[] filename;
However, you really should not be using new/new[] for filename at all. Use std::string instead:
#include <fstream>
#include <string>
double **readmat(const std::string &filename, int *size)
{
std::ifstream read(filename.c_str());
...
}
int main()
{
int size;
double **arr = readmat("text.txt", &size);
...
}
Alternatively:
#include <fstream>
#include <string>
double **readmat(const char *filename, int *size)
{
ifstream read(filename);
...
}
int main()
{
int size;
std::string filename = "text.txt";
double **arr = readmat(filename.c_str(), &size);
// or simply:
// double **arr = readmat("text.txt", &size);
...
}
And then, while you are at it, you should not be using new[] for your matrix, either. Use std::vector instead:
#include <vector>
std::vector< std::vector<double> > readmat(char *filename)
{
...
int size;
read >> size;
std::vector< std::vector<double> > mat(size);
for (int i = 0; i < size; i++)
{
mat[i].resize(size);
for (int j = 0; j < size; j++)
{
read >> mat[i][j];
}
}
return mat;
}
int main()
{
...
std::vector< std::vector<double> > arr = readmat("text.txt");
size_t size = arr.size();
for (size_t i = 0; i < size; i++)
{
for (size_t j = 0; j < size; j++)
{
std::cout << arr[i][j] << " , ";
}
std::cout << endl;
}
std::cout << endl;
return 0;
}
char *filename = new char;
filename = "text.txt";
This creates a new char, then leaks it because the pointer filename is reassigned to something that is statically declared.
Therefore, later on you delete something else than the original char.
Multiple issues here (using new instead of new[], etc). Suggestion, forget everything and use std::string and STL.
This is the source of your problem:
char *filename = new char;
filename = "text.txt";
filename no longer points to dynamically allocated memory, thus you can't delete it (and you're also leaking 1 byte of memory). Change your declaration to const char *filename = "test.txt"; and remove the delete filename;.
new char allocates a single character on the heap. Most functions that take a const char* as parameter expect a pointer to the first element of an array with the null character (\0) as delimiter (a C-style string).
You shouldn't even be able to assign a string literal to a variable of type char *, at least not in standard C++. You also don't need to dynamically allocate memory for string literals, simply use
const char *filename = "text.txt";
Then you also don't delete pointers to string literals. (That's what causes the error most likely, you deleted a pointer that pointed to a string literal)
Just replace
char* filename = new char;
with
const char* filename = "text.txt";
and remove
delete filename;
This is how your final code will look
int main()
{
int size;
const char *filename = "text.txt";
double **arr = readmat(filename, &size);
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
{
cout << arr[i][j]<<" , ";
}
cout << endl;
}
cout << endl;
for (int i = 0; i < size; i++)
{
delete[] arr[i];
}
delete[] arr;
return 0;
}
Related
I am facing problems to make this piece of code work:
char **createCharArray() {
char **charArray = new char*[PARAM_COUNT];
for (int i = 0; i < PARAM_COUNT; ++i) {
charArray[i] = new char[MAXSIZE];
}
return charArray;
}
void deleteCharArray(char **charArray) {
for (int i = 0; i < PARAM_COUNT; ++i) {
delete[] charArray[i];
}
delete[] charArray;
}
int main(){
char ** test = createCharArray();
char *asd = new char[MAXSIZE];
cin >> asd;
for (int i = 0; i < PARAM_COUNT; ++i) {
strcpy_s(test[i], asd);
}
for (int i = 0; i < PARAM_COUNT; ++i) {
cout << i << " " << test[i] << endl;
}
deleteCharArray(test);
return 0;
}
How do I copy that string into the char array, where am I mistaking?
Edit: As answered by Igor Tandetnik and user17732522 in the comments and Joseph Larson in the reply below, this was solved by adding the buffer argument to the strcpy_s function, making it a total of 3 arguments.
There are a few things I find troublesome. First, you've seen people say you should use std::string instead of char arrays, and that's true. But new programmers should understand the entire language, and so understanding how to use char arrays has value.
So let's ignore C++ strings and look at your code:
char ** test = createCharArray(); // array of pointers to char arrays
char *asd = new char[MAXSIZE];
cin >> asd;
for (int i = 0; i < PARAM_COUNT; ++i) {
strcpy_s(test[i], asd);
}
for (int i = 0; i < PARAM_COUNT; ++i) {
cout << i << " " << test[i] << endl;
}
deleteCharArray(test);
return 0;
Let's start with this. We don't know what createCharArray() does. Is it doing everything it should? Not only should it create an array of char pointers, but the way you're using it, it also needs to create the buffers they each point to. So it might look something like this:
char ** createCharArray() {
char ** array = new char *[PARAM_COUNT];
for (int index = 0; index < PARAM_COUNT; ++index) {
array[index] = new char[MAXSIZE];
}
return array;
}
If yours looks remarkably different, you may have issues.
After that, let's look at this:
for (int i = 0; i < PARAM_COUNT; ++i) {
strcpy_s(test[i], asd);
}
As others have said, this version of strcpy_s takes three arguments:
strcpy_s(test[i], asd, MAXSIZE);
Note that you're copying the same string into place multiple times. I wonder if your code should really do this:
for (int i = 0; i < PARAM_COUNT; ++i) {
cin >> asd;
strcpy_s(test[i], asd, MAXSIZE);
}
And finally, the delete method needs to delete the individual pointers and then the array of pointers.
I am trying to move a part of my code from main function to the additional void function, but I keep getting a problem with deleting allocated memory in the end. By that moment my program did not printed out my array as it should have. So i am looking for a tip how i can fix this.
#include "pch.h"
#include <iostream>
using namespace std;
void push(char* C, int size, istream &in);
void print_str(char* word, int length);
int main()
{
char* C = new char[0];
int size = 0;
cout << "input your text: ";
push(C, size, cin);
print_str(C, size);
delete[] C;
return 0;
};
void print_str(char* word, int length) {
for (int k = 0; k < length; k++)
{
cout << word[k];
}
cout << " ";
};
void push(char* C, int size, istream& in) {
while (1) {
char current = in.get();
if (current == '\n')
break;
else {
char* text1 = new char[size];
for (int i = 0; i < size; i++)
text1[i] = C[i];
delete[] C;
C = new char[size + 1];
for (int i = 0; i < size; i++)
C[i + 1] = text1[i];
delete[] text1;
C[0] = current;
}
size++;
}
}
Breakpoint
push changes the value of C, so it must return the new value so that the other code can see the change. Like this (for instance)
int main() {
...
C = push(C, size, cin);
...
}
char* push(char* C, int size, istream& in) {
while (1) {
char current = in.get();
if (current == '\n')
break;
else {
char* text1 = new char[size];
for (int i = 0; i < size; i++)
text1[i] = C[i];
delete[] C;
C = new char[size + 1];
for (int i = 0; i < size; i++)
C[i + 1] = text1[i];
delete[] text1;
C[0] = current;
}
size++;
}
return C;
}
you need to define c as pointer to pointer , because changing c in push scope won't change value of c in main
here's the changed code
#include "pch.h"
#include <iostream>
using namespace std;
void push(char** C, int size, istream& in);
void print_str(char* word, int length);
int main()
{
char* C = new char[0];
int size = 0;
cout << "input your text: ";
push(&C, size, cin);
print_str(C, size);
delete[] C;
return 0;
};
void print_str(char* word, int length) {
for (int k = 0; k < length; k++)
{
cout << word[k];
}
cout << " ";
};
void push(char** C, int size, istream& in) {
while (1) {
char current = in.get();
if (current == '\n')
break;
else {
char* text1 = new char[size];
for (int i = 0; i < size; i++)
text1[i] = (*C)[i];
delete[] C;
*C = new char[size + 1];
for (int i = 0; i < size; i++)
C[i + 1] = text1[i];
delete[] text1;
(*C)[0] = current;
}
size++;
}
}
also you can make more efficient algorithms to reach your end ,instead of allocating and deallocating memory for each character witch is costy
I am trying to input names from a file to a double pointer. Since, the file structure is as such that i don't know how many names will I encounter. I am regrowing my pointer both 2D and 1D at run time. But the problem is that since i am using fin.eof() in my while loop. When all the names have been entered, the loop doesn't detect the end of file and adds another array to the 2D pointer and since it hasn't any memory allocated yet. And then it tries to add '\0' to unallocated memory and then it throws an exception error.
#include <iostream>
#include <fstream>
using namespace std;
void OneDRegrow(char * & ptr, int & size)
{
char * temp = new char[size];
for (int i = 0; i < size; i++)
{
temp[i] = ptr[i];
}
if(!ptr)
delete[] ptr;
ptr = temp;
size++;
}
void TwoDRegrow(char ** & ptr, int & size)
{
char ** temp = new char*[size + 1];
for (int i = 0; i < size; i++)
{
temp[i] = ptr[i];
}
delete[] ptr;
ptr = temp;
temp = nullptr;
size++;
}
bool Read(ifstream & fin, char ** & ptr, int & rows)
{
if (!fin.is_open())
return false;
rows = 0;
int cols = 0;
char ch = '\0';
while (!fin.eof()) {
TwoDRegrow(ptr, rows);
cols = 0;
fin >> ch;
while (ch != ';') {
OneDRegrow(ptr[rows-1], cols);
ptr[rows - 1][cols-1] = ch;
fin >> ch;
}
ptr[rows - 1][cols] = '\0';
}
}
void Print2D(char ** ptr, int size)
{
for (int i = 0; i < size; i++)
{
cout << ptr[i] << endl;
}
}
int main()
{
int size;
char ** ptr = NULL;
ifstream fin("input.txt", ios::in);
Read(fin, ptr, size);
Print2D(ptr, size);
system("pause");
return 0;
}
Input from my file is as follows:
Roger;
James;
Mathew;
William;
Samantha;
Do it the right way
while (fin >> ch) {
TwoDRegrow(ptr, rows);
cols = 0;
while (ch != ';') {
...
Never (almost) use eof as the condition in a while loop, for exactly the reasons you have found.
I am writing a class in c++ that should add pointers of a string to an array. Instead of adding a pointer to a string I'm only adding the first character to the array but I want to be able to recall the whole string afterwards. How can I add a pointer of the string to the list so that I can print out the whole string?
class Listptr{
public:
Listptr();
void append(char *item);
private:
int size = 5;
char * buffer;
};
Listptr::Listptr(){
buffer = (char*)malloc(size);
for(int i=0; i<size; i++){
buffer[i] = NULL;
}
}
void Listptr::append(char *item){
for(int i=0; i<size; i++){
if(buffer[i] == NULL){
buffer[i] = *item;
break;
}
}
for(int i=0; i<size; i++){
cout << " " << buffer[i];
}
}
int main() {
Listptr test;
char val[] = "test";
char val2[] = "test2";
test.append(val);
test.append(val2);
}
You should really use std::string and std::vector<std::string> or something, as I mentioned in the comments. However, there were several problems with your code, which I've fixed below. Mainly you want a pointer to char arrays, i.e. a char**, not a char*, and then you need to check to make sure you're not trying to print a char array that's just a null pointer. You were also not using malloc correctly. So for educational purposes, to understand what you did wrong and not just say "stop it," here's the fixed code:
class Listptr{
public:
Listptr();
void append(char *item);
private:
int size = 5;
char ** buffer; // char**
};
Listptr::Listptr(){
buffer = (char**)malloc(size * sizeof(char**)); // char**
for(int i=0; i<size; i++){
buffer[i] = NULL;
}
}
Listptr::~Listptr() {
// Add destructor to free malloc-allocated memory when we're done
free(buffer);
}
void Listptr::append(char *item){
for(int i=0; i<size; i++){
if(buffer[i] == NULL){
buffer[i] = item;
break;
}
}
for(int i=0; i<size; i++){
if (buffer[i] != NULL) { // Do not dereference null pointer
cout << " " << buffer[i];
}
}
}
int main() {
Listptr test;
char val[] = "test";
char val2[] = "test2";
test.append(val);
test.append(val2);
}
Output
test test test2
I have modified the code from my previous question, and now it looks like this:
//#include "stdafx.h"
#include <iostream>
#include <cstring>
#include <chrono>
#include <cassert>
using namespace std;
const int MAX_SIZE=10000;
const int MAX_STRINGS = 10;
char** strings=new char*[10];
int len;
char* GetLongestCommonSubstring( char* str1, char* str2 );
inline void readNumberSubstrings();
inline const char* getMaxSubstring();
void readNumberSubstrings()
{
cin >> len;
assert(len >= 1 && len <=MAX_STRINGS);
for(int i=0; i<len;i++)
strings[i]=new char[MAX_SIZE];
for(int i=0; i<len; i++)
cin >> strings[i];
}
const char* getMaxSubstring()
{
char *maxSubstring=strings[0];
auto begin = chrono::high_resolution_clock::now();
for(int i=1; i < len; i++)
maxSubstring=GetLongestCommonSubstring(maxSubstring, strings[i]);
cout << chrono::duration_cast <chrono::milliseconds> (chrono::high_resolution_clock::now()-begin).count() << endl;
return maxSubstring;
}
char* GetLongestCommonSubstring( char* string1, char* string2 )
{
if (strlen(string1)==0 || strlen(string2)==0) cerr << "error!";
int *x=new int[strlen(string2)+ 1]();
int *y= new int[strlen(string2)+ 1]();
int **previous = &x;
int **current = &y;
int max_length = 0;
int result_index = 0;
int length;
int M=strlen(string2) - 1;
for(int i = strlen(string1) - 1; i >= 0; i--)
{
for(int j = M; j >= 0; j--)
{
if(string1[i] != string2[j])
(*current)[j] = 0;
else
{
length = 1 + (*previous)[j + 1];
if (length > max_length)
{
max_length = length;
result_index = i;
}
(*current)[j] = length;
}
}
swap(previous, current);
}
delete[] x;
delete[] y;
string1[max_length+result_index]='\0';
return &(string1[result_index]);
}
int main()
{
readNumberSubstrings();
cout << getMaxSubstring() << endl;
return 0;
}
It's still solving the generalised longest common substring problem, and now it's rather fast.
But there's a catch: if a user specifies, say, 3 as a number of strings he's about to enter, and then only actually enters one string, this code waits forever.
How do I change that?
If you read from a file and the number of arguments isn't equal to the number of arguments provided, just print a nice, clean error message to the user.
"Expected 7 arguments, received 3:"
Print out the arguments you found so the user has an idea of what the program is looking at when it spits out the error.
As for human input, I agree with the comments. The program should wait until the user close it or enters all the needed arguments.