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.
Related
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.
I am trying to store a sentence to a 2d array by separating each words. In the 2d array each row will contain each word from the sentence. Here is what I think I should do.
//Logic
//given string mystring
string mystring = "testing the arrays";
//create a 2d char array to hold 4 words with 10 max size
char 2darr[4][10] = {" "};
int x = 0;
for (int i = 0,j=0; i <mystring.length(); i++)
{
if (mystring(i) != ' ')
2darr[x][j++] = mystring(i); //copy the each character to the first row
else
2darr[x][j++] = '\0';
++x; // goes to next row
j = 0; //reset j for new row
}
Is there a better way to do this? I think my logic is a little off as well
The better way to do this is:
1) There is no need to check spaces. For this to occur, you can use std::istringstream with operator >> to obtain each word in a loop.
2) Use strncpy to copy the string into the 2 dimensional array
3) You need to make sure that the string does not exceed the bounds of the array, and that you have no more than 4 separate words.
Here is an example:
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <cstring>
int main()
{
char arr2d[4][10] = {};
std::string mystring = "testing the arrays";
// create an input stream containing the test string
std::istringstream strm(mystring);
std::string word;
// this is the word count
int curCount = 0;
// obtain each word and copy to the array
while (strm >> word && curCount < 4)
strncpy(arr2d[curCount++], word.c_str(), 9);
// output the results
for (int i = 0; i < curCount; ++i)
std::cout << arr2d[i] << "\n";
}
Output:
testing
the
arrays
this expression char 2darr[4][10] = {" "} will only set the first element to be " ", the others will be '\0' or NULL. But it is probably OK, since it is the default terminator of C-strings.
Variables can't start with a digit, call it arr2d instead.
String character access is mystring[i], not mystring(i)
You only indented the lines in the else block, in C++ if you don't enclose a block with curly braces, it only captures the first row, what you basically wrote is:
else {
2darr[x][j++] = '\0';
}
++x; // goes to next row
j = 0; //reset j for new row
Corrected code is
std::string mystring = "testing the arrays";
//create a 2d char array to hold 4 words with 10 max size
char arr2d[4][10] = { };
int x = 0;
for (int i = 0, j = 0; i < mystring.length(); i++)
{
if (mystring[i] != ' ') {
arr2d[x][j++] = mystring[i]; //copy the each character to the first row
}
else {
arr2d[x][j++] = '\0';
++x; // goes to next row
j = 0; //reset j for new row
}
}
I'm getting this error, "Heap corruption detected after normal block". This is after the array doubles and 'count' reaches 10. What am I doing wrong with this?
Thanks,
int* temp = NULL; // temp defined likewise
int size = 10;
int count = 0; // track array length
bool end = false; // flag to terminate while loop; AVOID using break stmt in loop
int* Arr = new int [size]; // Arr is pointer to an array of ints in heap
cout << endl; // provide blank line so user sees first prompt easily
while (!cin.eof() && cin.good() && end == false)
{
temp = new(int[10]); // ask for one new int in heap
if (temp != NULL)
{ // if heap available
cout << "Please enter an int number or EOF to terminate" << endl;
cin >> *(temp + count); // get user's next input
if (!cin.eof() && cin.good())
{ // if valid input
for (int i = 0; i < count; i++) // enter Arr array into temp array
*(temp + i) = *(Arr + i);
delete[] Arr; // delete current reference in Arr
Arr = temp; // assign reference in temp to Arr
}
else
{ // if user entered an invalid value including EOF in input
if (!cin.eof())
{
cout << "Invalid Input" << endl;
}
end = true; // set flag to terminate while loop
}
count++; // increment count of inputs for anticipated next input
if (count == 10)
{
cout << "etsdgsdggd";
int newSize = size * 2;
int* newArr = new int[newSize];
for (int i = 0; i < count; i++)
*(newArr + i) = *(Arr + i);
size = newSize;
delete[] Arr;
Arr = newArr;
}
}
else
{
cout << "Heap exhausted." << endl;
end = true; // set flag to terminate while loop here also
}
}
count--; // decrement count, which was incremented in anticipation of
// another valid input
if (count > 0)
{ // if positive count, display entries of input array
cout << "Input Array is: " << endl;
for (int j = 0; j < count; j++) // display array
cout << *(Arr + j) << " ";
cout << endl; // return cursor to lefthand position
}
// system("PAUSE"); // in case your system expects PAUSE before ending program
return 0;
}
This is because, for some unclear reason, this code allocates an array of ten integers on every iteration of the loop. And then saves the next value into one of the elements of the array, discarding the previously allocated array, and all previously-entered values, completely.
Then, after count reaches 10, the code goes through the motion of doubling the size of the array.
Immediately after this, on the very next iteration, the code allocates another ten-element array, and then tries to save the next number into the 11th position of the ten element array.
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++;
}
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.