Incomplete input from user - c++

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.

Related

Why is the breakpoint showing the second value of my array to be a large number? Extra Credit work

Using nested while loops to count the number of each character in a given string and put those numbers in an array. Then finding the largest number in the array to determine the most common character. Returning this character to the caller.
When placing a breakpoint |down (noted below) Im getting the first array value to be correct, and the second to be incorrect.
I don't know where I'm going wrong. I do have to admit I'm quite burned out right now, so it could be something easy I'm overlooking. I don't know.
#include <iostream>
using namespace std;
#include <string>
#include <string.h>
char median(char *);
int main() {
const int SIZE = 50;
char thing[SIZE];
char *strPtr;
cout << " give me a string: " << endl;
cin.getline(thing, SIZE);
strPtr = thing;
char mostcommon = median(strPtr);
cout << mostcommon;
}
char median(char *strPtr) {
char holder = 'x';
int numberof[50];
int counter = 0;
int arrayspacecounter = 0;
int thirdcounter;
int fourthcounter;
while (*strPtr != '\0') {
holder = *strPtr;
while (*strPtr != '\0') {
strPtr++;
if (holder == *strPtr) {
counter++;
}
}
numberof[arrayspacecounter] = counter; //counts the number of each character.
arrayspacecounter++;
strPtr++;
counter = 0;
}
v
// break point set HERE
^
//find the largest number in numberof[]
int largest = 0;
for (thirdcounter = 0; thirdcounter <= 100; thirdcounter++) {
for (fourthcounter = 1; fourthcounter <= 100; fourthcounter++) {
if (largest < numberof[fourthcounter]) {
largest = numberof[fourthcounter];
}
}
}
return *(strPtr + (largest));
}
numberof is not initialised so will initially contain junk values, any unused entries will still contain junk values where your breakpoint is. Use:
int numberof[50] = { 0 };
Next fourthcounter goes up to 100 but you only have 50 elements in numberof, replace the magic number 50 with a constant like MAX_ELEMENTS:
const size_t MAX_ELEMENTS = 50;
int numberof[MAX_ELEMENTS] = { 0 };
....
for (thirdcounter = 0; thirdcounter < MAX_ELEMENTS; thirdcounter++)
{
for (fourthcounter = 1; fourthcounter < MAX_ELEMENTS; fourthcounter++)
{
Alternatively just use the arrayspacecounter you have created already:
for (thirdcounter = 0; thirdcounter < arrayspacecounter; thirdcounter++)
{
for (fourthcounter = 1; fourthcounter < arrayspacecounter; fourthcounter++)
{
I'm not sure why you have two for loops at the end? The outer one seems redundant. Fixing various other bugs results in the working function:
char median(const char* strPtr)
{
const size_t MAX_ELEMENTS = 50;
int numberof[MAX_ELEMENTS] = { 0 };
int counter = 0;
int arrayspacecounter = 0;
int fourthcounter;
const char* temp = strPtr;
while (*temp != '\0')
{
const char* holder = temp;
while (*temp != '\0')
{
temp++;
if (*holder == *temp)
{
counter++;
}
}
numberof[arrayspacecounter] = counter; //counts the number of each character.
arrayspacecounter++;
temp = holder;
temp++;
counter = 0;
}
//find the largest number in numberof[]
int largest = 0;
for (fourthcounter = 1; fourthcounter < arrayspacecounter; fourthcounter++)
{
if (numberof[largest] < numberof[fourthcounter])
{
largest = fourthcounter;
}
}
return *(strPtr + (largest));
}
Your code could be much simpler though:
#include <iostream>
#include <string>
#include <map>
#include <algorithm>
char median(const char*);
int main()
{
char mostcommon = median("test");
std::cout << mostcommon;
}
char median(const char* strPtr)
{
std::map<char, int> frequencies;
for (auto ch = strPtr; *ch != '\0'; ch++)
{
frequencies[*ch]++;
}
auto max = std::max_element(frequencies.begin(), frequencies.end(), [](const auto& a, const auto& b) { return a.second < b.second; });
return max->first;
}
Your program segfaults in median somewhere, my guess is that you're trying to use a position outside of the boundaries of your array somewhere.
If all you're wanting to count frequency try something simpler, like this for example.
#include <string>
#include<iostream>
int main()
{
std::string phrase;
std::cout << "Enter a phrase \n";
std::getline(std::cin,phrase);
int a = 'A'; //index 0 of your array
int count=0;int max=0;
int counter[26] = {0}; //array that will hold your frequencies
char highestFreq;
for(char c:phrase) {
if(!isspace(c)) count = ++counter[int(toupper(c))-a];
if(count>max) max=count, highestFreq=c;
}
std::cout << "max is: "<<max << ". The letter is '"<< highestFreq << "'.\n"<< std::endl;
}

Having issues eliminating duplicates and sorting from C++ array outfile

Trying to create a list of unique grades from a text file. Having issues with the output eliminating duplicates. Currently, I am trying to compare the value of each previous array entry to the next and if they are different, output the result to the outfile, but is just outputs an empty file.
I am also curious if there is an easy fix to change the sorting from 'low to high' into 'high to low'. Thank you in advance.
#include <iostream>
#include <string>
#include <limits>
#include <cmath>
#include <iomanip>
#include <fstream>
using namespace std;
int testScoreArray[100];
void selectSort(int testScoreArray[], int n);
void fileOutput(int testScoreArray[]);
int main()
{
int n = 100;
ifstream infile;
infile.open("testscoresarrayhomework.txt");
for (int i = 0; i < 100; i++) {
infile >> testScoreArray[i];
}
selectSort(testScoreArray, n);
fileOutput(testScoreArray);
infile.close();
return 0;
}
void selectSort(int testScoreArray[], int n)
{
//pos_min is short for position of min
int pos_min, temp;
for (int i = 0; i < n - 1; i++) {
pos_min = i; //set pos_min to the current index of array
for (int j = i + 1; j < n; j++) {
if (testScoreArray[j] < testScoreArray[pos_min])
pos_min = j;
//pos_min will keep track of the index that min is in, this is needed when a swap happens
}
//if pos_min no longer equals i than a smaller value must have been found, so a swap must occur
if (pos_min != i) {
temp = testScoreArray[i];
testScoreArray[i] = testScoreArray[pos_min];
testScoreArray[pos_min] = temp;
}
}
};
void fileOutput(int testScoreArray[])
{
ofstream outfile;
int gradeEvent = 0;
int previousGrade = 0;
outfile.open("testscoresoutput.txt");
outfile << "Test Score Breakdown: ";
outfile << endl
<< "Score / Occurance";
for (int i = 0; i < 100; i++) {
previousGrade = i;
if (previousGrade && previousGrade != i) {
outfile << '\n' << testScoreArray[i] << " / " << gradeEvent;
}
}
outfile.close();
};
You have declared a global variable testScoreArray and the function names use the same variable name for their parameters. It's best to avoid using global variables when possible. You can remove global declaration, then declare testScoreArray in main, and pass it to your functions. Example:
//int testScoreArray[100]; <=== comment out
void selectSort(int *testScoreArray, int n);
void fileOutput(int *testScoreArray, int n); //add array size
int main()
{
int testScoreArray[100]; //<== add testScoreArray in here
int n = sizeof(testScoreArray) / sizeof(testScoreArray[0]);
selectSort(testScoreArray, n);
fileOutput(testScoreArray, n);
...
}
In fileOutput you are basically checking to see if i != i, you need to examine the array, not indexing in the loop:
void fileOutput(int *testScoreArray, int n)
{
ofstream outfile("testscoresoutput.txt");
for(int i = 0; i < n; i++)
if(i && testScoreArray[i] != testScoreArray[i-1])
outfile << testScoreArray[i] << "\n";
};
To revers the sort, simply change the condition in this comparison
if (testScoreArray[j] < testScoreArray[pos_min])
pos_min = j;
To:
if(testScoreArray[j] > testScoreArray[pos_min])
pos_min = j;
Technically you would rename the variable to pos_max

my code error type Warning 1 warning C4018 and more error

two errors:
1:Warning 1 warning C4018: '<' : signed/unsigned mismatch
2:Error 2 error C3861: 'funcNewStr': identifier not found
how can i fix that?
I will be happy to help you and explain where my mistake is in order for the code to work properly.
The program receives a sentence and takes the first letter from each word and composes a new string.
#include <iostream>
#include <string>
using namespace std;
int main(){
int size = 50;
char* ptr = new char[size];
for(int i = 0; i < size; i++){
ptr[i] = NULL;
}
cout << "Enter a string: " << endl;
string str;
getline(cin, str);
for (int i = 0; i<str.length(); i++)
ptr[i] = str[i];
funcNewStr(ptr, size);
system("pause");
return 0;
}
char funcNewStr(char* ptr,int size){//my function
char* newStr = new char[size];
for (int i = 0; i < size; i++){
newStr[i] = NULL;
}
newStr[0] = ptr[0];
int j = 1;
for (int i = 0; i < size; i++){
if (ptr[i] == ' '){
newStr[j] = ptr[i + 1];
j++;
}
}
return *newStr;
}
thank's.
str.length() is an unsigned, so you can fix the warning replacing this:
for (int i = 0; i<str.length(); i++)
by
for (unsigned i = 0; i<str.length(); i++)
And you can add a prototype of the function funcNewStr before the main:
char funcNewStr(char* ptr,int size);
int main(){
...
}
You need to add prototype for your function before main()
like this:
char funcNewStr(char* ptr,int size);
int main(){..}
Also str.length() is unsigned so you need to declare i as unsigned.
And one more thing
using namespace std;
is bad practice. Here's link to explanation.

c++ permutations high numbers (convert code)

I am trying to convert this code that works for '0' - '3' strings to integer so that it will work for higher numbers
#include <string>
#include <iostream>
using namespace std;
void permutate(char[], int );
bool recurse(char[], int );
int main()
{
int strLength;
cout << "Enter your desired length: ";
cin >> strLength;
char strArray[strLength];
for (int i = 0; i<strLength; i++)
strArray[i] = '0';
permutate(strArray, sizeof(strArray));
return 0;
}
void permutate(char charArray[], int length)
{
string wait;
length--;
bool done = false;
while(!done)
{
for (int i = 0; i <= length; i++)
cout << charArray[i];
cout << endl;
if (charArray[length] == '3')
done = recurse(charArray, length);
else
charArray[length] = (char)(charArray[length]+1);
}
}
bool recurse(char charArray[], int length)
{
bool done = false;
int temp = length;
if (temp > 1)
{
charArray[temp] = '0';
if (charArray[temp-1] == '3')
{
temp--;
done = recurse(charArray, temp);
}
else
(charArray[temp-1] = (char)(charArray[temp-1] + 1));
}
else
{
charArray[temp] = '0';
if (charArray[temp-1] == '3')
done = true;
else
charArray[temp-1] = (char)(charArray[temp-1]+1);
}
return done;
}
I changed every char to int,
every '0' = 0, '3' = 3
every (charArray[temp-1] = (char)(charArray[temp-1] + 1)); to charArray[temp-1]++;
I tried to debug but I still can`t make it work :(
Manged to fix it( works for high numbers):
#include <string>
#include <iostream>
using namespace std;
void permutate(int[], int, int );
bool recurse(int[], int, int );
int main()
{
int strLength, nrElem;
cout << "Enter your desired length: ";
cin >> strLength;
cout << "Enter nr elem: ";
cin >> nrElem;
int strArray[strLength];
for (int i = 0; i<strLength; i++)
strArray[i] = 0;
permutate(strArray, strLength, nrElem );
cout << "\nSTOP";
return 0;
}
void permutate(int charArray[], int length, int nrElem)
{
// length--;
bool done = false;
while(!done)
{
for (int i = 0; i < length; i++)
cout << charArray[i] << " ";
cout << endl;
if (charArray[length - 1] == nrElem)
//done = true;
done = recurse(charArray, length, nrElem);
else
charArray[length - 1]++;
}
}
bool recurse(int charArray[], int length, int nrElem)
{
bool done = false;
int temp = length ;
if (temp > 1)
{
charArray[temp] = 0;
if (charArray[temp-1] == nrElem)
{
temp--;
done = recurse(charArray, temp, nrElem);
}
else
charArray[temp-1]++;
}
else
{
charArray[temp] = 0;
if (charArray[temp-1] == nrElem)
done = true;
else
charArray[temp-1]++;
}
return done;
}
In your permutate function, you're incrementing charArray[length] but checking to see if charArray[length - 1] is equal to nrElem, so you never end up calling recurse.
Here is a short piece of code to do the same (not an answer, however it did not look right in a comment field), not sure if you need the recursion, if you do not this code may be of interest:
#include <iostream>
#include <sstream>
using namespace std;
string output(int firstIntSize, int secondIntSize)
{
std::ostringstream oss;
for (int i = 0; i<firstIntSize; i++)
{
for (int j = 0; j< secondIntSize; j++)
{
oss << i << j << " ";
}
}
return oss.str();
}
int main()
{
cout << output(2,3);
return 0;
}
hmmm... Why not simply make a Permutations algorithm and then use a generic function to print whatever you are permutating. Here's how I would do it for strings:
#include <iostream>
#include <string>
template<class T>
void print(T * A, unsigned n){ //for printing purposes
for(unsigned i=0;i<n;i++){
std::cout<<A[i]<<" ";
}
std::cout<<std::endl;
}
void generate_permutations(unsigned k, std::string str, char *A, bool *U){
// k is the position that we need to fill, starts from 0 and goes to the end.
if(k<str.size()) //if k==str.size() then we will print it
for(unsigned i=0;i<str.size();i++){
if(U[i]==0){
A[k]=str[i]; U[i]=1;
generate_permutations(k+1, str, A,U);
U[i]=0; //after the recursion is finished and printed, we can release the letter.
}
}
else
print(A,str.size());
}
int main(){
std::string str;
std::cout<<"Enter the string to be permutated: \n";
std::cin>>str;
int n;
n = str.length(); // You don't really need to ask the user the size of the string he/she wants to enter.
bool *U; // we will keep track of the used letters with the help of this boolean vector
char *A; // we will copy the contents of str here, so that we keep the str intact
U = new bool[n];
for (int i=0;i<n;i++) U[i]=false;
A = new char[n];
for (int i=0;i<n;i++) A[i]=str[i];
generate_permutations(0,str,A,U);
return 0;
}
Now if you want to convert to numbers (ints), it's almost the same:
#include <iostream>
template<class T>
void print(T * A, int n){
for(int i=0;i<n;i++){
std::cout<<A[i]<<" ";
}
std::cout<<std::endl;
}
void generate_permutations(int k, int *A, bool *U, int n){
if(k==n)
print(A,n);
else {
for(int i=0;i<n;i++){
if(U[i]==0){
A[k]=i; U[i]=1;
generate_permutations(k+1,A,U,n);
U[i]=0;
}
}
}
}
int main(){
int n;
std::cout<<"Permutations of how many objects? \n";
std::cin>>n;
int * A;
bool *U;
A = new int[n];
U = new bool[n];
for (int i=0;i<n;i++) U[i]=false;
print(U, n);
generate_permutations(0,A,U,n);
return 0;
}

Trouble filling a c++ array, only last item at every index

Firstly, this is for a class so there are limitations on what we can and can't do, plus I am extremely new to c++ and programming in general, so that is why the code is probably a little crap.
I am at my wits end trying to understand why when I display the item_list using the first set of cout lines within the first for loop, it displays each individual item as it should be (its a list of skyrim ingredients and their effects).
However, when the second for loop executes, the item_list is filled with nothing but the last item that should have been inserted (wisp wrappings and their effects).
Even just pointing me in the right direction would be GREATLY appreciated :)
cheers
int client::fill_list(int size_in, int h1size, int h2size)
{
char temp[ASIZE] = {'\0'};
int j = 0;
ifstream ifile;
ifile.open("test.txt");
if(ifile.is_open())
{
for(int i = 0; i < size_in; ++i)
{
if(ifile.good())
{
j = 0;
do
{
temp[j] = char(ifile.get());
++j;
}while(ifile.peek() != '*');
temp[j] = char(ifile.get());
copy(client_item.name, temp, j);
}
if(ifile.good())
{
j = 0;
do
{
temp[j] = char(ifile.get());
++j;
}while(ifile.peek() != '*');
temp[j] = char(ifile.get());
copy(client_item.effect1, temp, j);
}
if(ifile.good())
{
j = 0;
do
{
temp[j] = char(ifile.get());
++j;
}while(ifile.peek() != '*');
temp[j] = char(ifile.get());
copy(client_item.effect2, temp, j);
}
if(ifile.good())
{
j = 0;
do
{
temp[j] = char(ifile.get());
++j;
}while(ifile.peek() != '*');
temp[j] = char(ifile.get());
copy(client_item.effect3, temp, j);
}
if(ifile.good())
{
j = 0;
do
{
temp[j] = char(ifile.get());
++j;
}while(ifile.peek() != '*');
temp[j] = char(ifile.get());
copy(client_item.effect4, temp, j);
}
reference.into_list(i,client_item);
cout << reference.item_list[i].name;
cout << reference.item_list[i].effect1;
cout << reference.item_list[i].effect2;
cout << reference.item_list[i].effect3;
cout << reference.item_list[i].effect4;
getchar();
}
}
for(int k = 0; k < SIZE; ++k)
{
cout << reference.item_list[k].name;
cout << reference.item_list[k].effect1;
cout << reference.item_list[k].effect2;
cout << reference.item_list[k].effect3;
cout << reference.item_list[k].effect4;
}
getchar();
return 0;
}
...
int table::into_list(int index, item&item_in)
{
if(index < SIZE)
{
item_list[index] = item_in;
return 0;
}
else
return 1;
}
...
Header for the table class
#include "hash.h"
class table
{
public:
table()
{
item_list = new item [SIZE];
}
~table();
int fill(item*);
int insert(item&, nHash&);
int insert(item&, eHash&, int);
int retrieve(char*,item*,int);
int remove(int,item&);
int remove(int);
int check_hash(int,int,int);
int keygen(char*, int);
int from_list(int, item&);
int into_list(int, item&);
//private:
item * item_list;
nHash name_table;
eHash ef1_table;
eHash ef2_table;
eHash ef3_table;
eHash ef4_table;
};
....
Beginning of main
#include "client.h"
int main()
{
client program;
program.fill_list(SIZE,HNSIZE,HESIZE);
for(int i = 0; i < SIZE; ++i)
{
cout << program.reference.item_list[i].name;
cout << program.reference.item_list[i].effect1 << endl;
cout << program.reference.item_list[i].effect2 << endl;
cout << program.reference.item_list[i].effect3 << endl;
cout << program.reference.item_list[i].effect4 << endl;
}
....
item header
#include <iostream>
#include <fstream>
#include <cctype>
#include <cstdlib>
#include <cstring>
#include <cmath>
using namespace std;
const int ASIZE = 30;
const int SIZE = 92;
const int HNSIZE = 41;
const int HESIZE = 17;
struct item
{
item();
~item();
char * name;
char * effect1;
char * effect2;
char * effect3;
char * effect4;
int count;
//int keygen(int,int);
/*int name_key;
int ef1_key;
int ef2_key;
int ef3_key;
int ef4_key;*/
};
It's possible that part of the problem is how you make copies of client_item here:
reference.into_list(i,client_item);
This just assigns client_item to item_list like so:
item_list[index] = item_in;
...but since item is defined like this:
struct item
{
item();
~item();
char * name;
char * effect1;
...
...all of the items in item_list will have pointers (like name, etc.) that point to the same memory as the memory in client_item.
For example, after each assignment, the pointers item_list[index].name and item_in.name will have the same value. (You can check that by printing both pointers, if you're curious.) Since they both point to the same memory, if you change what's stored at that memory, both objects will appear to change at the same time.
That means that subsequent changes to client_item -- like copying a new string into one of the places that it points -- will affect all of the saved items as well.