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
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.
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;
}
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.
Can someone explain me why when i back form function i lost my data from tabOfOffsets. I did the same thing twice and program crash only with the second array.
I printed values of this array on the end of function and everything is clear and correct. Maybe i make mistake somewhere with delete?
Below it is the code.
#include<iostream>
#include <algorithm>
using std::cout;
using std::endl;
void changeSizeOfVector(int *tabValue, int *tabOffsets, int &oldSize, int
newSize) {
int temp = std::min(oldSize, newSize);
int *newTabOfValues = new int [newSize] {0};
int *newTabOfOffsets = new int [newSize] {0};
for (int i = 0; i < temp; i++) {
newTabOfValues[i] = tabValue[i];
newTabOfOffsets[i] = tabOffsets[i];
}
delete[] tabValue;
delete[] tabOffsets;
tabValue = new int [newSize] {0};
tabOffsets = new int [newSize] {0};
for (int i = 0; i < newSize; i++) {
tabValue[i] = newTabOfValues[i];
tabOffsets[i] = newTabOfOffsets[i];
std::cout << tabOffsets[i] << tabValue[i] << endl;
}
oldSize = newSize;
delete[] newTabOfValues;
delete[] newTabOfOffsets;
for (int i = 0; i < newSize; i++) {
std::cout << tabOffsets[i] << tabValue[i] << endl;
}
}
int main() {
int SIZE = 10;
int * tabOfOffsets = new int[SIZE];
int * tabOfValues = new int[SIZE];
for (int i = 0; i < SIZE; i++)
{
tabOfValues[i] = i;
tabOfOffsets[i] = i;
cout << tabOfValues[i] << " : " << tabOfOffsets[i] << endl;
}
changeSizeOfVector(tabOfValues, tabOfOffsets, SIZE, 12);
for (int i = 0; i < SIZE; i++) {
cout << tabOfOffsets[i] << " : " << tabOfValues[i] << endl;
}
delete[] tabOfOffsets;
delete[] tabOfValues;
}
This function declaration is wrong:
void changeSizeOfVector(int *tabValue, int *tabOffsets, int &oldSize, int
newSize);
it means you can change the values of tabOffsets but not the pointer itself in order to make it behave correctly you should declare it as follows:
void changeSizeOfVector(int *tabValue, int **tabOffsets, int &oldSize, int
newSize);
This way you can change the pointer itself and assign a newly allocated array to it.
I'm pretty new to C++ and I have some problems with getting into all that pointer stuff. Basically I am passing a pointer to a Function, creating an Array at that pointer. Back in the main function I can't access this array.
Here's my code:
#include <iostream>
using namespace std;
void createArray(char** dict, int* arraysize)
{
*arraysize = 26*26*26*26;
delete dict;
dict = 0;
//Initialisiere character array of character
//char **wortliste = 0;
dict = new char*[*arraysize];
for(int i = 0; i < *arraysize; i++)
dict[i] = new char[5];
int ctr = 0;
//Erstelle Einträge (sortiert)
for (char i = 'A'; i <= 'Z'; i++)
{
for (char j = 'A'; j <= 'Z'; j++)
{
for (char k = 'A'; k <= 'Z'; k++)
{
for (char l = 'A'; l <= 'Z'; l++)
{
dict[ctr][0] = i;
dict[ctr][1] = j;
dict[ctr][2] = k;
dict[ctr][3] = l;
dict[ctr][4] = '\0';
ctr++;
}
}
}
}
}
int main(void)
{
char** dict = 0;
int arraysize;
createArray(dict, &arraysize);
cout << dict[0] << endl << dict[arraysize-1] << endl;
return 0;
}
I can't figure out my error thank you very much in advance.
In C++ parameters are pass by value (unless explicitly marked as being reference parameters), so when you pass dict, a pointer (to a pointer to char) to createArray, the dict inside your function is a different object, albeit with the same initial value, as the dict in main. If you want to see changes to dict in main you would have to pass it by reference, or pass the address of it into a function taking a char ***.
E.g.
void createArray(char**& dict, int* arraysize)
or
void createArray(char*** pdict, int* arraysize)
{ // use (*pdict) instead of dict ...
and
// ...
createArray(&dict, &arraysize);
A more "C++" way to achieve what you want would be to have:
void createArray( std::vector<std::string>& dict );
and to simply have createArray resize the vector to the required size. Using standard containers like vector and string also frees you of the obligation to explicity deallocate that memory that you allocate which is currently missing from your code.
There are a couple of mistakes.
To delete an array:
char **array = /* new with whatever */;
/* do your work */
for (i = 0; i < array_size; ++i)
delete[] array[i];
delete[] array;
To new an array:
char **array = new char *[array_size];
for (i = 0; i < array_size; ++i)
array[i] = new char[array_size_2];
When deleteing, to make sure you don't iterate over a not-newed array, check it against NULL:
for (i = 0; i < array_size; ++i)
{
if (array[i] != NULL) /* Or simply if (array[i]) */
delete[] array[i];
array[i] = NULL;
}
if (array != NULL)
delete[] array;
array = NULL;
alternatively, since delete makes a check for NULL anyway, you can simplify this to:
if (array != NULL)
for (i = 0; i < array_size; ++i)
delete[] array[i]; /* no need to set to NULL after if going to delete the array */
delete[] array;
array = NULL;
Note: delete deletes a single object while delete[] deletes an array.
I can't imagine what you would do with such data, but you can at least use modern techniques.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
vector<string> create() {
vector<string> result;
for (char i = 'A'; i <= 'Z'; ++i) {
for (char j = 'A'; j <= 'Z'; ++j) {
for (char k = 'A'; k <= 'Z'; ++k) {
for (char l = 'A'; l <= 'Z'; ++l) {
result.push_back(string() + i + j + k + l);
}
}
}
}
return result;
}
int main() {
vector<string> data = create();
cout << data.front() << endl << data.back() << endl;
}