C++ Vectors Segmentation Fault - c++

I am working on a program that has an input file and it either adds, removes, or prints the string. I have my print function working, but I am getting a segmentation fault when I uncomment the lines of code shown.
int main()
{
vector <string> vec; //Creates an empty vector
string command;
string word;
int index;
ifstream fin;
fin.open("datalabvec.dat"); //Opens the input file
if (!fin)
cout << "The input file does not exist" << endl << endl;
else
{
fin >> command;
while (fin)
{
if (command =="Add")
{
fin >> word >> index;
//addVec (vec, word, index);
}
//if (command == "Remove")
//{
//fin >> index;
//remVec (vec, index);
//}
// else //Print function
{
printVec(vec);
}
fin >> command;
}
}
}
void addVec(vector <string> &v, string word, int ind)
{
int size = v.size();
if (ind > size + 1)
cout << "Invalid adding at index " << ind << endl;
else
{
v.insert(v.begin()+ind, word);
}
}
void remVec(vector <string> &v, int ind)
{
int size = v.size();
if (ind > size)
cout << "Invalid removing at index " << ind << endl;
else
{
v.erase(v.begin() + ind);
}
}
void printVec(const vector <string> v)
{
int size = v.size();
for (int i = 0; i < size; i++)
{
cout << v[i] << "\t";
}
cout << endl;
}
Input File
Remove 0
Add Student 0
Add Kid 0
Add Final 1
Add Grow 1
Add Note 2
Add Bad 6
Remove 5
Add Worse -1
Print
Add Rich 5
Remove 1
Remove 7
Add Mind 2
Remove 3
Print

In your adding function. I guess mistakenly you wrote size+1 inside if statement. It should be size-1 because the last member of vector is at size-1. [0] - [size-1]. Correct statement is if(ind >= size) or ind > size-1. Like you used in for loop in writer function.
And as Brad suggested in comment below. It is good idea to check weather ind >= 0 or not.
void addVec (vector <string> &v, string word, int ind)
{
int size = v.size();
if (ind < 0 || ind >= size)
cout << "Invalid adding at index " << ind << endl;
else
{
v.insert(v.begin()+ind, word);
}
}
void remVec (vector <string> &v, int ind)
{
int size = v.size();
if (ind < 0 || ind >= size)
cout << "Invalid removing at index " << ind << endl;
else
{
v.erase(v.begin() + ind);
}
}

Related

c++: searching an array

I am writing a program that's supposed to search an array that is filled by user input and return different output depending on whether or not another integer given by the user is in that array. the output is the index of the element.
e.g., suppose my array is {1, 2, 3}. using search(), if I enter 2, it should tell me that 2 is in the array and that its index value is 1.
But for some reason, this function only works correctly if I enter the very first element. This means that if I search for 1 in the array above, it will tell me that the index value is 0 like it's supposed to, but it won't do that for other elements.
My code is below. What am I doing wrong here?
#include <iostream>
using namespace std;
const int DECLARED_SIZE = 20;
void fillArray(int a[], int size, int& numberUsed);
int search(const int a[], int numberUsed, int target);
int search2(const int a[], int numberUsed, int target);
int main() {
int size;
cout << "Enter the array size: ";
cin >> size;
int arr[size], listSize, target;
fillArray(arr, size, listSize);
char ans;
int result;
do {
cout << "Enter a number to search for: ";
cin >> target;
cout << endl << endl;
result = search(arr, size, target);
if (result == -1) {
cout << target << " is not on the list." << endl << endl;
cout << "Search again? (y/n): ";
cin >> ans;
cout << endl << endl;
}
else {
cout << target << " is stored in array position " << result << "." << endl << endl;
cout << "Search again? (y/n): ";
cin >> ans;
cout << endl << endl;
}
} while ((ans != 'n') && (ans != 'N'));
cout << "End of program." << endl;
return 0;
}
void fillArray(int a[], int size, int& numberUsed) {
cout << "Enter up to " << size << " non-negative whole numbers." << endl;
cout << "Mark the end of the list with a negative number." << endl;
int next, index = 0;
cin >> next;
while ((next >= 0) && (index < size)) {
a[index] = next;
index++;
cin >> next;
}
numberUsed = index;
}
//searches an array that is filled by the user
//this is where i think i am struggling
int search(const int a[], int numberUsed, int target) {
int index = 0;
bool found = false;
while ((!found) && (index < numberUsed)) {
if (target == a[index]) {
found = true;
}
else {
index++;
}
if (found) {
return index;
}
else {
return -1;
}
}
return 0;
}
If you look at your search function you will see that it always returns at the bottom of the while loop. That's why you only find the first number. What you should do is return if you find the number but carry on if you don't. Like this (with some other simplifications of your code)
int search(const int a[], int numberUsed, int target) {
for (int index = 0; index < numberUsed; index++) {
if (target == a[index]) {
return index;
}
}
return -1;
}
In your while loop in your search function, you're doing:
if (found) {
return index;
} else {
return -1;
}
Which means if you didn't find your input, it immediately returns -1 instead of trying the next index. You should only return when you've visited all other indexes.

C++ programming define array size from the external text file

I am trying to make my array have a size of a non-constant value. The size should be defined by the "test.txt" file that gets the information from. For example, if the txt file has 10 numbers then the array should be in size of 10. I tried using vectors but I couldn't make it work. Any help would be much appreciated. Here is the code below:
#include<iostream>
#include<fstream>
#include<sstream>
#include<string>
#include<vector>
#include<cstdlib>
using namespace std;
/* Function to print an array
A int[]: an array of n element
n int; length of an array
*/
void displayList(float A[], int n)
{
int i;
for (i = 0; i < n; i++)
cout << A[i] << ", ";
cout << endl;
}
/*
Insertion Sort function
A int[]: an array of n element
n int; length of an array
*/
void insertionSort(float A[], int n)
{
int i, j;
float key;
for (i = 1; i < n; i++)
{
key = A[i];// take key
j = i - 1;
/* Move elements of arr[0..i-1], that are
greater than key, to one position ahead
of their current position */
while (j >= 0 && A[j] > key)
{
A[j + 1] = A[j]; // move element to next postion
j = j - 1; // reduce index of j - go backward in the array
}
std::cout << "Step key at i = " << i << ": [" << key << "] inserted at j = " << j + 1 << "
position -> ";
A[j + 1] = key; // at j+1 th position we place the key
displayList(A, n);
}
};
ifstream input("test.txt"); //put your program together with thsi file in the same folder.
int main() {
int const ARRAY_SIZE = 9;
float A[ARRAY_SIZE];
string line;
ifstream inFile;
int i = 0, cnt = 0;
float n;
inFile.open("test.txt");
if (!inFile) {
cout << "Unable to open file";
exit(1); // terminate with error
}
while (!inFile.eof()) {
getline(inFile, line);
n = atof(line.c_str());
cnt++;
}
int cnt;
cin >> cnt;
vector<float> A(cnt);
inFile.close();
inFile.open("test.txt");
if (!inFile) {
cout << "Unable to open file";
exit(1); // terminate with error
}
while (!inFile.eof()) {
getline(inFile, line);
n = atof(line.c_str());
A[cnt++] = n;
}
inFile.close();
n = sizeof(A) / sizeof(A[0]);
cout << "insertionSort: \n";
cout << "Unsorted array: ";
displayList(A, n);
insertionSort(A, n);
std::cout << "Sorted array: ";
displayList(A, n);
}
sample input from txt file:
12
4
5
9
6
11
0
2
0.5
To make it work with vectors you shouldn't create the vector with a number of elements, like vector<float> v(10);. Create an empty vector and add one value at a time to it.
void display(const std::vector<float>& A) {
std::cout << "Got " << A.size() << " elements.\n";
for(float value : A) {
std::cout << value << '\n';
}
}
int main() {
std::vector<float> A; // an empty vector of floats
float temp; // a temporary float to use for extraction
while(input >> temp) { // loop while extraction succeeds
A.push_back(temp); // save the value at the end of the vector
}
display(A);
}

Last element added to an array is being added twice, unable to figure out why

Realization: Wow spent so much time staring at this code I finally noticed something I'd been missing all along. I initialize i = size which means at the start the array is looking at an unfilled spot so I finally understand why it always puts a repeat. Now to attempt to fix it. Feel free to berate me.
I'm looking through the array backwards because I'm using an insertion sort algorithm so I work backwards from the last known element to alphabetize the data. However no matter what the final line in the data file (from which I'm reading) it always repeats twice. Here is the array contents printed to demonstrate the repeat:
List of names sorted:
100 bill gates
100 bill gates
65 duck donald
60 frog freddie
71 ghost casper
85 mouse abby
73 mouse mickey
95 mouse minnie
Notice that bill gates is listed twice. The problem appears to be with the way I'm looping. If I modify the lower bound in the loop to 1 instead of 0 then shit goes haywire. Here is the function in question, I don't believe any of the code outside is relevant so I did not include it:
bool sortInput(ifstream &infile, StudentType students[], int &size)
{
StudentType temp;
//empty condition
if(size == 0)
{
infile >> temp.last >> temp.first >> temp.grade;
strcpy(students[0].last, temp.last);
strcpy(students[0].first, temp.first);
students[0].grade = temp.grade;
size++;
}
while(infile)
{
infile >> temp.last >> temp.first >> temp.grade;
if(temp.grade >= LOWGRADE && temp.grade <= MAXGRADE)
{
for(int i = size; i > 0; i--)
{
if(strcmp(temp.last, students[i-1].last) < 0)
{
students[i] = students[i-1];
students[i-1] = temp;
}
else if(strcmp(temp.last, students[i-1].last) == 0 && strcmp(temp.first, students[i-1].first) < 0)
{
students[i] = students[i-1];
students[i-1] = temp;
}
else
{
students[i] = temp;
break;
}
}
size++;
//tester loop to print contents every step of the way
for(int i = 0; i < size; i++)
{
cout << "TEST: " << students[i].last << " " << students[i].first << " " << students[i].grade << endl;
}
cout << "DONE" << endl;
} //end for loop
} //end while loop
return true;
}
However if the full code is necessary for further context then here it is:
// ----------------------------------------------------------------------------
// You write meaningful doxygen comments and assumptions
#include <string.h>
#include <iostream>
#include <iomanip>
#include <fstream>
using namespace std;
int const MAXSIZE = 100; // maximum number of records in total
int const MAXLENGTH = 31; // maximum string length
int const MAXGRADE = 100; // highest possible grade
int const LOWGRADE = 0; // lowest possible grade
int const GROUP = 10; // group amount
int const HISTOGRAMSIZE = (MAXGRADE-LOWGRADE)/GROUP + 1; // grouped by GROUP
struct StudentType { // information of one student
int grade; // the grade of the student
char last[MAXLENGTH]; // last name (MAXLENGTH-1 at most)
char first[MAXLENGTH]; // first name (MAXLENGTH-1 at most)
};
// prototypes go here
bool sortInput(ifstream &, StudentType [], int &);
void displayList(StudentType [], int);
void setHistogram(int [], StudentType [], int);
void displayHistogram(int []);
int findAverage(StudentType [], int);
//------------------------------- main ----------------------------------------
int main() {
StudentType students[MAXSIZE]; // list of MAXSIZE number of students
int size = 0; // total number of students
int histogram[HISTOGRAMSIZE]; // grades grouped by GROUP
int average = 0; // average exam score, truncated
// creates file object and opens the data file
ifstream infile("data1.txt");
if (!infile) {
cout << "File could not be opened." << endl;
return 1;
}
// read and sort input by last then first name
bool successfulRead = sortInput(infile, students, size);
// display list, histogram, and class average
if (successfulRead) {
displayList(students, size);
setHistogram(histogram, students, size);
displayHistogram(histogram);
average = findAverage(students, size);
cout << "Average grade: " << average << endl << endl;
}
return 0;
}
bool sortInput(ifstream &infile, StudentType students[], int &size)
{
StudentType temp;
//empty condition
if(size == 0)
{
infile >> temp.last >> temp.first >> temp.grade;
strcpy(students[0].last, temp.last);
strcpy(students[0].first, temp.first);
students[0].grade = temp.grade;
size++;
}
while(infile)
{
infile >> temp.last >> temp.first >> temp.grade;
if(temp.grade >= LOWGRADE && temp.grade <= MAXGRADE)
{
for(int i = size; i > 0; i--)
{
if(strcmp(temp.last, students[i-1].last) < 0)
{
students[i] = students[i-1];
students[i-1] = temp;
}
else if(strcmp(temp.last, students[i-1].last) == 0 && strcmp(temp.first, students[i-1].first) < 0)
{
students[i] = students[i-1];
students[i-1] = temp;
}
else
{
students[i] = temp;
break;
}
}
size++;
for(int i = 0; i < size; i++)
{
cout << "TEST: " << students[i].last << " " << students[i].first << " " << students[i].grade << endl;
}
cout << "DONE" << endl;
} //end for loop
} //end while loop
return true;
}
void displayList(StudentType students[], int size)
{
cout << "List of names sorted:" << endl;
for(int i = 0; i < size; i++)
{
cout << " " << students[i].grade << " " << students[i].last << " " << students[i].first << endl;
}
cout << endl;
}
void setHistogram(int histogram[], StudentType students[], int size)
{
int groupIndex;
for(int i = 0; i < size; i++)
{
groupIndex = (students[i].grade - LOWGRADE) / GROUP;
histogram[groupIndex]++;
}
}
void displayHistogram(int histogram[])
{
cout << "Histogram of grades: " << endl;
int bottomBin = LOWGRADE;
int binWidth = (MAXGRADE - LOWGRADE) / GROUP - 1;
int topBin = bottomBin + binWidth;
for(int i = 0; i < HISTOGRAMSIZE; i++)
{
cout << bottomBin << "--> " << topBin << ": ";
for(int j = 0; j < histogram[i]; j++)
{
cout << "*";
}
cout << endl;
bottomBin += binWidth + 1;
topBin = min(topBin + binWidth + 1, MAXGRADE);
}
}
int findAverage(StudentType students[], int size)
{
int total = 0;
for(int i = 0; i < size; i++)
{
total += students[i].grade;
}
return total / size;
}
// ----------------------------------------------------------------------------
// functions with meaningful doxygen comments and assumptions go here
You can combine the stream extraction and testing the stream state by changing:
while(infile)
{
infile >> temp.last >> temp.first >> temp.grade;
...
}
to
while(infile >> temp.last >> temp.first >> temp.grade)
{
...
}
This will read the stream and fail (return false) if the read fails for any reason, including EOF.
Note: read this related question for more explanation.
End-of-file indicator is set not when the last byte of file is read, but when an attempt is made to read the next byte, the byte that doesn't exist.
Thus, after the last line is read, while(infile) check still succeeds, but infile >> temp.last call fails, leaving the variable intact. You don't check for that failure, so you run one extra iteration of the loop, using values read by the previous iteration.

c++ arrays and functions and counters

My code is done and working. But i cant figure out how to count the number of attempts made by the user and invalid account numbers that were entered. I am supposed to do this in main starting after cin >> accountNum. After the user enters 9999 to quit, it is supposed to display the number of attempts made and the number of invalid charge account numbers that were entered. When i run it i get 0 for number of attempts and -1 for invalid numbers entered.
#include <iomanip>
#include <iostream>
#include <fstream>
using namespace std;
void getAccountNumbers(int[], int);
void displayAccountNumbers(int[], int);
void selectionSort(int[], int);
int binarySearch(const int[], int, int);
int main()
{
int accountNum;
int results;
int attempts = 0;
int invalidNumbers = 0;
const int ARRAY_SIZE = 18; // Array size
int numbers[ARRAY_SIZE]; // Array with 18 elements
int count = 0;
//ifstream inputFile;
getAccountNumbers(numbers, ARRAY_SIZE);
cout << "Original Order" << endl;
displayAccountNumbers(numbers, ARRAY_SIZE);
selectionSort(numbers, ARRAY_SIZE);
cout << "Sorted List" << endl;
displayAccountNumbers(numbers, ARRAY_SIZE);
cout << "********************" << endl;
cout << "Enter an Account number or 9999 to quit" << endl;
cin >> accountNum;
if(accountNum == 9999)
{
cout << "Thank You!" << endl;
}
while(accountNum != 9999)
{
results = binarySearch(numbers, ARRAY_SIZE, accountNum);
if(results == -1)
{
cout << "That number was not found" << endl;
invalidNumbers = results++;
}
else
{
cout << "That number is valid " << endl;
}
attempts = results++;
cin >> accountNum;
}
cout << "Number of attempts: " << attempts << endl;
cout << "Invalid numbers entered: " << invalidNumbers << endl;
system("pause");
return 0;
}
void getAccountNumbers(int nums[], int size)
{
ifstream inputFile;
int count = 0;
//Open the file
inputFile.open("charges.txt");
while(count < size && inputFile >> nums[count])
count ++;
//Close the file
inputFile.close();
}
void displayAccountNumbers(int nums[], int size)
{
for(int count = 0; count < size; count++)
cout << nums[count] << "\t";
cout << endl << endl;
}
void selectionSort(int nums[], int size)
{
int startScan, minIndex, minValue;
for(startScan = 0; startScan < (size - 1); startScan++)
{
minIndex = startScan;
minValue = nums[startScan];
for(int index = startScan + 1; index < size; index++)
{
if(nums[index] < minValue)
{
minValue = nums[index];
minIndex = index;
}
}
nums[minIndex] = nums[startScan];
nums[startScan] = minValue;
}
}
int binarySearch(const int nums[], int size, int value)
{
int first = 0, //First element
last = size - 1, // Last element
middle, // Midpoint
position = -1; //Position of search value
bool found = false;
while(!found && first <= last)
{
middle = (first + last) / 2; //Midpoint
if(nums[middle] == value)
{
found = true;
position = middle;
}
else if(nums[middle] > value) // Value is in lower half
last = middle - 1;
else
first = middle + 1; // Value is in upper half
}
return position;
}
Your problem is in the lines where you are trying to add to invalidNumbers and attempts. The ++ postfix operator adds one to the number before it. You needn't say invalidNumbers = results++;; you merely need invalidNumbers++;, and the same applies for attempts. What your code was doing was setting invalidNumbers (and attempts) to the value of results and then adding one to results instead.

C++ Permutation with a output length limit and special arguments

I am new to C++ and I am working on a program that will generate a list of all permutations of a string of characters, however I need the ability to limit the length of the output to lets say 5 characters (this will most likely become a variable number set by the user). I have been searching for about a week for something like this and the closest I have gotten is the following code.
Source.cpp:
#include <iostream>;
using namespace std;
void swap(char *fir, char *sec)
{
char temp = *fir;
*fir = *sec;
*sec = temp;
}
/* arr is the string, curr is the current index to start permutation from and size is sizeof the arr */
void permutation(char * arr, int curr, int size)
{
if(curr == size-1)
{
for(int a=0; a<size; a++)
cout << arr[a] << "";
cout << endl;
}
else
{
for(int i=curr; i<size; i++)
{
swap(&arr[curr], &arr[i]);
permutation(arr, curr+1, size);
swap(&arr[curr], &arr[i]);
}
}
}
int main()
{
string next;
char str[] = "abcdefghijklmnopqrstuvwxyz1234567890-";
permutation(str, 0, sizeof(str)-1);
cin.get();
cin.get();
}
This code works however it does not limit the length of the output. It sets the output length to the length of the given string. It also appears it might not account for multiple of the same letter/number in the output (this I am not 100% sure of).
Additionally, I will need to set special rules such as the hypen cannot be the first or last character in the output.
I have attempted to modify the above code by replacing sizeof(str)-1 with 5 however it will only "loop" through the first 5 characters in the string, so anything beyond "e" is not processed.
If anyone can assist on this it would be much appreciated.
EDIT:
Thank you to everyone for their excellent help I am now going to post my final product in case anyone else was trying to do the same thing.
Final Source:
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
using namespace std;
void swap(char *fir, char *sec)
{
char temp = *fir;
*fir = *sec;
*sec = temp;
}
void permutation(char * arr, int size, char* result, int depth, int limit)
{
ofstream myfile ("permutation.txt", fstream::app);
if(depth == limit)
{
for(int a=0; a<limit; a++){
myfile << result[a] << "";
cout << result[a] << "";
}
myfile << "\n";
cout << endl;
}
else
{
for(int i=0; i<size; i++)
{
result[depth] = arr[i];
permutation(arr, size, result, depth + 1, limit);
}
}
myfile.close();
}
int main()
{
ofstream myfile ("permutation.txt");
myfile << "";
myfile.close();
string answer;
char *rArray;
string startProcess = "N";
std::cout << "Welcome to permutation v1" << endl;
std::cout << "-------------------------" << endl;
std::cout << "Please enter how long the string should be: ";
std::getline (std::cin,answer);
int result = atoi(answer.c_str());
rArray = new char[result];
std::cout << "\n\nThank You!\n" << endl;
std::cout << "Please wait, generating possible character array for length of " << result << "." << endl;
std::cout << "Would you like to proceed? Y = yes & N = no: ";
std::getline (std::cin,startProcess);
char str[] = "abcdefghijklmnopqrstuvwxyz1234567890";
if(startProcess == "Y")
{
permutation(str, sizeof(str)-1, rArray, 0, result);
}
else
{
std::cout << "\n\nOperation Terminated. No permutations being generated..." << endl;
}
cin.get();
return EXIT_SUCCESS;
}
You need to limit the depth of the recursion
To give permutations of characters in the string, using each only once:
void permutation(char * arr, int currsize, intchar* sizeresult, int depth, int limit)
{
if(depth == limit)
{
for(int a=0; a<limit; a++)
cout << arr[a]result[a] << "";
cout << endl;
}
else
{
for(int i=curr;i=0; i<size; i++)
{
swap(&arr[curr],result[depth] &arr[i]);= arr[i];
permutation(arr, curr+1size, sizeresult, depth + 1, limit);
swap(&arr[curr], &arr[i]);
}
}
}
Call like this
permutation(str, 0, sizeof(str)-1, result, 0, 5);
To give permutations of characters in the string, using each character an unlimited number of times:
void permutation(char * arr, int size, char* result, int depth, int limit)
{
if(depth == limit)
{
for(int a=0; a<limit; a++)
cout << result[a] << "";
cout << endl;
}
else
{
for(int i=0; i<size; i++)
{
result[depth] = arr[i];
permutation(arr, size, result, depth + 1, limit);
}
}
}
Call like this
char result[5];
permutation(str, sizeof(str)-1, result, 0, sizeof(result));
This is not a tough job actually. If you can use recursion and a loop within that function you can solve it. I suggest use next_permutation function from the standard library.
The fact is time. Within 3 second you can process permutation for only 8 character. And the condition will be depended to requirement. Suppose in your example you can prune back if you need to omit hyphen in starting or ending.
Pseudo code of my implementation:
char array[] = "abcdee";
char eachPerm[6];
bool usedmatrix[6][6];
Recur(int depth, int n)
{
// you can return from here if this is not the right path, suppose '-'
// in first or last place.
if(depth == n)
{
print;
}
else
{
int i;
for(i= 0 to array.length)
{
if(array[i] is not used before)
eachPerm[depth] = array[i];
recur(depth+1, n);
}
}
}
Call this function initially recur(0, 5)