Append user input to array in C++ - 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.

Related

c++ segmentation fault and Trace/breakpoint trap when using Dynamic memory allocation

I am practicing Dynamic memory allocation in C++. I wanna enter some word which length is less than 10, and when I enter "-1", it will print the word I have entered before.
But when I enter more than three words, it will give me an Trace/breakpoint trap or segmentation fault. I use gdb-peda to check my code, it said "double free detected in tcache 2", I think the problem is the "delete" part in my code, but I dont know how to correct it.
the gdb-peda reply
this is my code:
#include <iostream>
#include <limits>
using namespace std;
int counter = 0; //be used to count how many times we have entered
char **ins();
int main() {
auto dict = ins(); //Total list
for ( int i = 0; i < counter; i++ ) {
for ( int j = 0; j < 10; j++ ) {
if ( *( *( dict + i ) + j ) == '\0' ) //if the word is null,print the word and go to next word
break;
cout << *( *( dict + i ) + j );
}
cout << endl;
}
for ( int i = 0; i < counter; i++ )
delete[] dict[i]; //delete the total list
system( "pause" );
return 0;
}
char **ins() {
auto dict = new char *[1](); //total list
auto cpdict = new char *[1](); //copy list
while ( 1 ) {
auto word = new char[10](); //a list be used to store the entered word (length<10)
cout << "input word: ";
cin.get( word, 10, '\n' ); //get the entered word in the list
if ( word[0] == '-' && word[1] == '1' ) { //if enter "-1" , delete the copy list and return the total list
delete[] cpdict;
return dict;
}
counter++; //plus one of the times of entering
delete[] dict; //delete the old total list
auto dict = new char *[counter](); //create a new total list, the lenth is one more than the old total list
for ( int i = 0; i < counter - 1; i++ ) *( dict + i ) = *( cpdict + i ); //copy the stuffs in old copy list to new total list
*( dict + counter - 1 ) = word; //copy the word we just enter into total list
delete[] cpdict; //delter the old copy list
auto cpdict = new char *[counter](); //create a new copy list
for ( int i = 0; i < counter; i++ ) *( cpdict + i ) = *( dict + i ); //copy the stuffs in new total list to new copy list
cin.clear();
cin.ignore( numeric_limits<std::streamsize>::max(), '\n' );
}
}
My imagine input and output is like:
input word: aaa
input word: bbb
input word: ccc
input word: ddd
input word: -1
output:
aaa
bbb
ccc
ddd
First of all, try not to use using namespace std;.
I have also found a memory leak in your code. You allocate the word pointer every iteration but did you make sure to delete it when you get to the next iteration? What you need to do is, delete the word buffer at the end of the iteration. Plus you also have two variables dict and cpdict which you allocate memory for no reason, delete them later on in the while loop only to assign a new block of memory. Try to avoid unwanted allocations as it'll only slow things down. Frankly its hard to debug your code (mainly because your working with a lot of pointers) so ill show you a good implementation (ill add comments to show important notes).
#include <iostream>
#include <limits>
//using namespace std; <-- Dont use this, ever.
/**
* Lets create a struct named Word so that its easier to work with and debug.
* Also we can use a normal stack allocated array because we know the maximum word size beforehand and it has the added
* benifit of not needing to deallocate it at the end of each iteration.
*/
struct Word {
char mWord[10];
};
int counter = 0; //be used to count how many times we have entered
Word* ins();
int main() {
auto dict = ins(); //Total list
for (int i = 0; i < counter; i++) {
// Here you dont have to worry about null terminations as itll automatically gets terminated because the
// default values of all the elements in the word array is 0.
std::cout << dict[i].mWord;
std::cout << std::endl;
}
// Here you just have to delete the array itself.
delete[] dict;
system("pause");
return 0;
}
Word* ins() {
Word* dict = nullptr; // The array of words. Dont allocate anything here because its unwanted.
while (1) {
Word word; // Instantiate the struct.
std::cout << "input word: ";
std::cin.get(word.mWord, 10, '\n'); //get the entered word in the list
if (word.mWord[0] == '-' && word.mWord[1] == '1') { //if enter "-1" , delete the copy list and return the total list
return dict;
}
counter++; //plus one of the times of entering
// The instruction pointer came here because there was a new word inserted which is not "-1" so we need to
// add it to the array. Lets first allocate a new buffer.
Word* cdict = new Word[counter];
// If we had an array before, lets copy the old content to the new buffer using memcpy() and delete the old block.
if (dict)
{
memcpy(cdict, dict, sizeof(Word) * (static_cast<size_t>(counter) - 1));
delete[] dict;
}
// Now we can add the new word to buffer.
cdict[counter - 1] = word;
// Now lets assign the buffer to the main array pointer. Remember, we dont delete the buffer as this buffer
// contains the actual data. We will have to delete it at the end when the program terminates.
dict = cdict;
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}
Try not to use raw pointers as it'll make it harder to understand what's going on and it'll be a lot painful to debug in these types of errors. The C++ standard library provides a lot of nice options like std::string, std::vector and use Smart Pointers whenever possible.

Memory Violation in 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++;
}

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.

C++ creating a two-dimensional array based on user input string length

I have an assignment to create a block transposition cipher program. A user is to input a phrase of their choice, and the program is to strip the phrase of spaces, punctuation, and make lowercase, before reading its length and creating a two-dimensional array the size of the nearest square that will fit all the chars in the mutated string, and filling in the remaining space with random letters.
Problem is, I'm having issues with creating that square.
I have this so far:
int main()
{
string input;
cout << "Please enter message to cipher." << endl;
getline(cin, input);
/* do punctuation removal/mutation */
int strLength = input.length(); //after mutation
/* need to find the square here before applying sizes and values to arrays */
char * original = new char[][]; // sizes pending
char * transposed = new char[][]; // sizes pending
for (int i = 0; i <= /* size pending */ ; i++)
{
for (int j = 0; j <= /* size pending */ ; j++)
{
transposed[j][i] = original[i][j];
}
}
/* do more stuff here */
}
any ideas?
(I already have done the mutation portion; tested with alternate code)
You can't do e.g.
char * original = new char[][];
First of all you are trying to create an array of arrays (or pointer of pointers) and assign it to a single pointer. You need to do it in two steps:
Allocate the "outer" array:
char **original = new char* [size];
Allocate the "inner" strings:
for (int i = 0; i < size; i++)
original[i] = new char [other_size];
However I would highly recommend against using that! Instead you should be using std::vector instead of "arrays" allocated on the heap, and if the contents are strings then use std::string:
std::vector< std::vector< std::string > > original;
You can take the square root of the length, round down to an integer, and add one to get the new length.
int len = (int)(sqrt(strLength) + 1e-9) + 1;
You'd then malloc the square using len and fill as you normally would.
I believe you do not need the "new" to create your storage. Following code should just do the job:
char buf[size][size]; // size is a variable
... // populate your buf
char tmp;
for(int i = 0; i < size; i++) {
for(int j = 0; j < i; j++) {
tmp = buf[i][j];
buf[i][j] = buf[j][i];
buf[j][i] = tmp;
}
}
This does the transpose in place. You don't need another array to store the char's.

C++ Memory/Input Problem

I'm trying to create a small program in c++ where the user puts in multiple lines and the program outputs all the lines of after a EOT command is given (ctrl-d)
But i'm getting some error's when executing the program. I think i did a lot wrong.
(This is an hypothetical exersise, i don't want to use any vectors, lists etc., and only want include iostream.
#include <iostream>
using namespace std;
int main()
{
//Temp input string
string input_string;
//Array with input lines
string lines[1];
//Counter for input lines
size_t line_counter = 0;
//Input terminated checker
bool breaker = false;
//Eternal loop
for(;;){
//Get line, store in input_string and set breaker if input is terminated
if(getline(cin, input_string).eof()) breaker = true;
//Create a new temp array to hold our data
string temp_lines[line_counter+1];
for(size_t counter = 0; counter != line_counter; ++counter){
//And use a for loop to get data from our last array with data
temp_lines[counter] = lines[counter];
}
//Create a second array and repeat process
//because c++ doesn't allow us to create dynamic array's
string lines[line_counter+1];
for(size_t counter = 0; counter != line_counter; ++counter){
lines[counter] = temp_lines[counter];
}
//store input in the new array
lines[line_counter] = input_string;
//increase the input counter
++line_counter;
//if breaker is set terminate loop but output lines first
if(breaker){
//for each input
for(size_t anothercounter = 0; anothercounter != line_counter; ++anothercounter){
//output the inputed line
cout << anothercounter << ": " << lines[anothercounter] << "\n";
}
//break out of eternal for loop
break;
}
}
}
Try something like this (untested, edited in notepad):
#include <iostream>
using namespace std;
int main()
{
//Temp input string
string input_string;
//Array with input lines
string * lines = 0;
// Array used for temporary storage
string * temp_lines = 0;
//Counter for input lines
size_t line_counter = 0;
//Input terminated checker
bool breaker = false;
//Eternal loop
for(;;){
//Get line, store in input_string and set breaker if input is terminated
if(getline(cin, input_string).eof()) breaker = true;
// Copy all lines from original array to temporary array, to enable resizing the original
temp_lines = new string[line_counter+1];
for(size_t tmp = 0; tmp < line_counter; tmp++) temp_lines[tmp] = lines[tmp];
temp_lines[line_counter] = input_string;
delete [] lines;
lines = new string[line_counter+1];
for(size_t tmp = 0; tmp <= line_counter; tmp++) lines[tmp] = temp_lines[tmp];
delete [] temp_lines;
//increase the input counter
++line_counter;
//if breaker is set terminate loop
if(breaker) break;
}
//for each input
for(size_t anothercounter = 0; anothercounter != line_counter; ++anothercounter){
//output the inputed line
cout << anothercounter << ": " << lines[anothercounter] << "\n";
}
}
For one thing I can see wrong is you cannot do this
//Create a new temp array to hold our data
string temp_lines[line_counter+1];
as line_counter is a variable, and array size must be a compile time time constant. Otherwise use new to allocate memory for the array.
Also it would help a lot in answering your question if you also post the errors you are getting.