Dynamically allocated array always set to size 1 [closed] - c++

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 months ago.
Improve this question
I am making a program to calculate the value of words for a friend who is interested in numerology.
In my program, I ask the user how many words they want to calculate, so I can dynamically allocate the size of the array to store the words.
It works perfectly the first time they run the program, but when I ask if they want to test more words, and if they hit yes, it reruns the while loop and it asks them for how many words to evaluate, but this time, no matter what number they type, it always sets the size of the array to 1, due to the number variable being set to 1 and not changing after user input. My friend has to rerun the program to make it work again.
I really want to fix this problem to make it easier for my friend.
(Yes, I do plan on fixing my code, and if you have seen this code in another question, that was me, and yes, I am going to improve my code based on the suggestions I got, but I want it to at least work before I improve on it.)
Here is my code:
#include <iostream>
#include <string>
#include <sstream>
void clear()
{
system("clear");
}
int main(int argc, char* argv[])
{
int number{1};
int total{0};
int value{0};
std::string number_str;
std::string response;
std::stringstream ss;
bool isDigit;
while (true)
{
clear();
number = 1;
total = 0;
value = 0;
number_str = "";
response = "";
isDigit = true;
clear();
std::cout << "How many words to evalute? (Default: 1):\n> ";
//std::cin >> number;
std::getline(std::cin, number_str);
//std::cin.ignore();
clear();
for (int i = 0; i < number_str.size(); ++i)
{
if (!(std::isdigit(number_str[i])))
isDigit = false;
break;
}
if (isDigit)
{
if (number_str.empty()) {
number = 1;
} else {
ss << number_str;
ss >> number;
}
}
if (std::isdigit(number)) {
if (number <= 0) {
number = 1;
}
}
std::string* pPhrase = new std::string[number];
int* pValue = new int[number]{}; // Initialized each element to 0
for (int i = 0; i < number; ++i) // could replace "number" with "sizeof(pPhrase)/sizeof(pPhrase[0])"
{
(i == 0) ? std::cout << "Enter Word #" << i+1 << " (or type your full phrase):\n> " :
std::cout << "Enter Word #" << i+1 << ":\n> ";
std::cin >> pPhrase[i];
for (char j : pPhrase[i])
{
value = 0;
if (std::isalnum(j) && j != '0')
{
if (std::isalpha(j))
j = std::tolower(j);
} else {
continue;
}
if (j == 'a' || j == 'i' || j == 'j'
|| j == 'q' || j == 'y' || j == '1')
value += 1;
if (j == 'b' || j == 'k' || j == 'r' || j == '2')
value += 2;
if (j == 'c' || j == 'g' || j == 'l'
|| j == 's' || j == '3')
value += 3;
if (j == 'd' || j == 'm' || j == 't' || j == '4')
value += 4;
if (j == 'e' || j == 'h' || j == 'n'
|| j == 'x' || j == '5')
value += 5;
if (j == 'u' || j == 'v' || j == 'w' || j == '6')
value += 6;
if (j == 'o' || j == 'z' || j == '7')
value += 7;
if (j == 'f' || j == 'p' || j == '8')
value += 8;
pValue[i] += value;
value = 0;
std::cout << '\n';
clear();
}
}
std::cin.ignore();
std::cin.clear();
std::cout << "\n\n";
for (int i = 0; i < number; ++i)
{
std::cout << "Value of \"" << pPhrase[i] << "\": " << pValue[i] << '\n';
total += pValue[i];
}
std::cout << "Total value: " << total << "\n\nPress \'Enter\' or \'Return\' to Continue... ";
//std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
//std::cin.clear();
std::cout << "\n\n\nWould you like to evaluate another phrase? (Y/n):\n> ";
std::getline(std::cin, response);
delete[] pPhrase;
delete[] pValue;
if (response[0] == 'y' || response[0] == 'Y'
|| response.empty() || response[0] == ' ')
continue;
break;
}
std::cout << "Exiting...";
try {
//system("killall Terminal");
} catch (std::exception& ex) {}
std::cout << "\n\n\n";
return 0;
}

for (int i = 0; i < number; ++i) // could replace "number" with "sizeof(pPhrase)/sizeof(pPhrase[0])"
Actually, you can't use the sizeof(array)/sizeof(array[0]) trick on a pointer to an array. It only works when you use it directly on the actual array itself. There are numerous questions on StackOverflow that explain this, including (just to name a few):
How to get the size of an array using a pointer to the first element and properties of "\0"?
Pointer to an array get size C++
getting size of array from pointer c++
In any case, one problem I do see in your code is that on each iteration of the outer while loop, you are not resetting the std::stringstream that you use to convert the user's input to the number variable. Each iteration is just pushing more and more data into the stream without removing the old data first.
Also, using std::isdigit(number) is useless. You already validated the user entered only digits, and then converted those digits to the number variable. What you didn't do is validate that the conversion to int was actually successful before using number. You must validate that the extraction of the number from the stringstream is successful, ie in case the user enters a large value that can't fit into an int.
Try this instead:
while (true)
{
clear();
number = 1;
total = 0;
value = 0;
number_str = "";
response = "";
isDigit = true;
// ADD THIS!
ss.str("");
ss.clear();
//
...
if (isDigit)
{
ss << number_str;
if (!(ss >> number) { // <-- ADD THIS!
number = 1;
}
}
...
}
That being said, you could just get rid of the stringstream altogether, you don't actually need it. You can extract the number value directly from std::cin itself (which you are already aware of, because you commented out that code), eg:
std::cout << "How many words to evalute? (Default: 1):\n> ";
if (!(std::cin >> number)) {
number = 1;
std::cin.clear();
}
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
// no need for the `isdigit() check at all...

Related

Infinite Loop when Entering 2 very basic C-strings

The following code produces an infinite loop when I enter 2 cstrings of entirely 1s and 0s.
What have I done?
char input1[9] = {'\0'};
char input2[9] = {'\0'};
bool reEnter = false;
do
{
reEnter = false;
cout << "The numbers to be added are: "<< endl;
cin.ignore();
cin.getline(input1, 9, '\0');
cin.ignore();
cin.getline(input2, 9, '\0');
for (int i = 0; i<8; i++)
{
if((input1[i] != '0') && (input1[i] != '1') || (input2[i] != '0') && (input2[i] != '1'))
{
reEnter = true;
}
}
if(reEnter == true)
cout << "Must be an 8 bit binary" << endl;
}while(reEnter == true);
This got it. For some reason it didn't like the ignores, and terminating the cin.getline functions with null characters was creating the infinite loop.
char input1[9] = {'\0'};
char input2[9] = {'\0'};
bool reEnter = false;
do
{
reEnter = false;
cout << "The numbers to be added are: "<< endl;
cin.getline(input1, 9);
cin.getline(input2, 9);
for (int i = 0; i<8; i++)
{
if((input1[i] != '0') && (input1[i] != '1') || (input2[i] != '0') && (input2[i] != '1'))
{
reEnter = true;
}
}
if(reEnter == true)
cout << "Must be an 8 bit binary" << endl;
}while(reEnter == true);

C++ a function call is not called again after the loop iterates

Hey so I am relatively a beginner at programming. I am trying to create a very simple minesweeper game over a 2D array, the issue I am running into is after the player steps on a mine (game over) they are given the option to play again. After this the set difficulty function is supposed to be called a second time (since it is within the loop) and a new minefield is to be generate. Unfortunately none of that is happening and the program skips that process.
Here is my code:
#include <iostream>
#include <string>
#include <cstdlib>
#include <ctime>
using namespace std;
int choose_difficulty(int x);
int generator();
int main()
{
//create initial variables
string Ans;
int Rounds;
int NewPosition_x = 0;
int NewPosition_y = 0;
//ask user if he wants to run the program and expect input
cout << "Would you like to play a game? Y/N" << endl;
cin >> Ans;
//based on user input the program will run or not
if (Ans == "Y" || "y") {
while (Ans == "Y" || "y")
{
//Create position variables to be checked
int Position_x;
int Position_y;
//ask user how many rounds in the game they want
cout << "How many chances do you want to give yourself?" << endl;
cin >> Rounds;
//Generate minefield could not be done as separate function since you cannot output an array
int a = choose_difficulty(a);
int mines;
int n,m;
srand (time (0));
if(a == 0) {
mines = 3;
n = 4;
m = n;
}
else if (a == 1){
mines = 5;
n = 4;
m = n;
}
else if (a == 2){
mines = 7;
n = 4;
m = n;
}
int minefield[n][m] = { };
int g, h;
for (int num = 0; num < mines; num++) {
g = rand()%n;
h = rand()%n;
minefield[g][h] = 1;
}
for (int x = 0; x < Rounds; x++)
{
//Begin Game
cout << "Where are you at to avoid the mines? (Enter a 2 numbers 0 through 3)" << endl;
cin >> NewPosition_x >> NewPosition_y;
//check if the player has entered a new position
while (NewPosition_x == Position_x && NewPosition_y == Position_y) {
cout << "You have to move somewhere, put a valid location" << endl;
cin >> NewPosition_x >> NewPosition_y;
}
//check to see if that position is valid
while ((NewPosition_x < 0 || NewPosition_x > 3) || (NewPosition_y < 0 || NewPosition_y > 3)) {
cout << "I'm sorry, but that place doesn't exist. Try somewhere else" << endl;
cin >> NewPosition_x >> NewPosition_y;
}
//Assign Player Position and check position vs mines
Position_x = NewPosition_x;
Position_y = NewPosition_y;
if (minefield[Position_y][Position_x] == 1) {
cout << "You stepped on a mine, Game Over" << endl;
cout << "You minefield was this:" << endl;
for (int i=0; i < n; i++){
for (int j=0; j < n; j++){
cout << minefield[i][j] << "\t";
}
cout << endl;
}
cout << "Would you like to play again? Y/N" << endl;
cin >> Ans;
if (Ans == "n" || Ans == "N"){
return 0;
}
}
else if ((minefield[Position_x + 1][Position_y] == 1) || (minefield[Position_x - 1][Position_y] == 1) || (minefield[Position_x][Position_y + 1] == 1) || (minefield[Position_x][Position_y - 1] == 1)) {
cout << "You're hot right now, you better watch your step. Continue to the next round" << endl;
}
else {
cout << "You're safe. Continue to the next round" << endl;
}
}
}
}
return 0;
}
int choose_difficulty(int a)
{
do{
string difficulty;
//Difficulty Selection
cout << "Choose the game difficulty: Easy, Medium, Hard" << endl;
cin >> difficulty;
if (difficulty == "easy" || difficulty == "Easy"){
a = 0;
}
else if (difficulty == "medium" || difficulty == "Medium"){
a = 1;
}
else if (difficulty == "hard" || difficulty == "Hard"){
a = 2;
}
else {
cout << "Invalid input";
a = 3;
}
}while (a == 3);
return a;
}
You should be careful on this kind of error:
//based on user input the program will run or not
if (Ans == "Y" || "y") {
while (Ans == "Y" || "y")
{
This, above, will always be true being "y" different from 0 (false).
Instead you need to check that Ans is either equal to "Y" or "y" in this way:
//based on user input the program will run or not
if (Ans == "Y" || Ans == "y") {
while (Ans == "Y" || Ans == "y")
{
Or use, as suggested in the comments, std::toupper()
UPDATE
It seems you have a problem on your buffer you should use cin.ignore() in order to clean it;

Encrypting and decrypting part of the ASCII table

I have made small encryption program that uses to keys rot7 and rot13. Everything works fine except two 6 letters uvwxyz.
If I type ABCDEFGHIJKLMNOPQRSTUVWXYZ it encrypts and decrypts no problem. However, if I enter the same in lower case letters then uvwxyz do not work.
Having said this, I have allowed all the writable characters within the ascii table as the valid range as follows:
// allow all writable characters from 32 to 255
if ((str[i] >= 32 ) && (str[i] <=255))
{
str[i] -= key;
}
Here is the process of encryption:
cout << endl;
cout << "Encrypting process started " << endl << endl;
cout << "--------------------------- " << endl;
//get the string length
int i = 0;
int length = str.length();
int key = rot13 ;
int k = 5;
int multiple = 0;
int count = 0;
cout << "the text to encrypt is: " << str << endl;
cout << "text length is: " << length << endl;
cout << "using rot13"<<endl;
cout <<"---------------------------" << endl;
cout << "using rot13" << endl;
//traverse the string
for(i = 0; i < length; i++)
{
count ++;
cout << left;
//if it is a multiple of 5 not the first character change the key
if((multiple = (( i % 5 ) == 0)) && (count != 1) && (key == rot13)){
key = rot7;
}
//if it is a multiple of 5 not the first character change the key
else if((multiple = (( i % 5 ) == 0)) && (count != 1) && (key == rot7) ) {
key = rot13;
}
// Capital letters are 65 to 90 (a - z)
if ((str[i] >= 32) && (str[i] <= 255))
{
str[i] += key;
}
}
return str;
How is it possible that the capital letters work and not the lower case if I have allowed this range? Can it be because of something else? I have added these captures with what happens step by step... hopefully this helps
In your code :
if ((str[i] >= 32) && (str[i] <= 255))
{
if (str[i] + key > 255)
str[i] = ((str[i] + key) % 255 )+ 32;
else
str[i] += key;
}
if key has a value of 13 and str[i] is 'u' or greater, str[i] has a value higher than 255.
You should use modulo % operator in this case, this is rotation, not only a shift

Check instances of 3 paired letters

Say i have an array char myArrray[5] = {'T','T','T','T','T'} And i want to check how many instances of 3 pairs of T i have.
I have a forloop below that checks for all 3 instances of T. There should be 3 instances, but for some reason its not even entering the if statement that checks it.
Maybe im just lost im really sleepy.
There are 3 isntances of TTT throughout the array. Thats what we have to get the number 3 in the counter but we arent getting it. (T{T[T)T}T]
full code here: http://ideone.com/AWyOkH
Any ideas?
for(int k = 0; k < lineInputs; k++)
{
int counter=0;
cout << (k+1) << " ";
for(int u=0; u<arrayElements; u++)
{
//cout << myArray[u];
if(myArray[u] == 'T' && myArray[u+1] == 'T' && myArray[u+2] == 'T')
{
counter++;
cout << counter << " ";
}
}
}
Does the issue lay with if(myArray[u] == 'T' && myArray[u+1] == 'T' && myArray[u+2] == 'T') ?
Seems to work fine.
char myArray[5] = {'T','T','T','T','T'};
int lineInputs=1;
for(int k = 0; k < lineInputs; k++)
{
int counter=0;
cout << (k+1) << " ";
int arrayElements=5;
for(int u=0; u<(arrayElements-2); u++)
{
//cout << myArray[u];
if(myArray[u] == 'T' && myArray[u+1] == 'T' && myArray[u+2] == 'T')
{
counter++;
cout << counter << " ";
}
}
}
Output I get is:
1 1 2 3
It works fine, although the code you posted should have:
for(int u=0; u<arrayElements-2; u++)
Instead of:
for(int u=0; u<arrayElements; u++)
The output will be 1 1 2 3 because you first print k+1, and then the counter each time you find three consecutive "T"'s. What you have programmed is correct!

i wanted to create a function where i can enter a string and it would output a a jumbled version of the string

i cant seem to figure out what wrong
for some reason it wont compile and it think theres a problem on my jumbleString function
#include <iostream>
#include <iomanip>
#include <string>
#include <istream>
using namespace std;
int main ()
{
int lengthofstring, x, countWords(string str), countConsonant(string str, int), consonant, jumbleString(string str);
string str, str2, wordone;
char options;
cout << "Please enter a word, a sentence, or a string of numbers." << endl;
getline(cin, str);
//cin >> str;
lengthofstring = str.length();
str2=str;
bool another= true;
while (another)
{
cout << '\n' << "USE THIS MENU TO MANIPULATE YOUR STRING" << endl;
cout << "---------------------------------------" << endl;
cout << "1) Inverse String" << endl;
cout << "2) Reverse String" << endl;
cout << "3) To Uppercase" << endl;
cout << "4) Jumble String" << endl;
cout << "5) Count Number Words" << endl;
cout << "6) Count Consonants" << endl;
cout << "7) Enter a Different String" << endl;
cout << "8) Print the String" << endl;
cout << "Q) Quit" << endl;
cin >> options;
switch (options)
{
case '1':
for (x = 0; x < lengthofstring; x++)
{
if (islower(str[x]))
str[x] = toupper(str[x]);
else if (isupper(str[x]))
str[x] = tolower(str[x]);
}
cout<< str;
break;
case '2':
for (x = 0; x < lengthofstring; x++)
{
str2[x] = str[lengthofstring-1-x];
}
cout<< str2;
break;
case '3':
{
for (x = 0; x < lengthofstring; x++)
{
if (islower(str[x]))
str[x] = toupper(str[x]);
}
cout<< str;
}
break;
case '4':
jumbleString(str);
break;
case '5':
cout << countWords(str);
break;
case '6':
consonant = 0;
cout<< countConsonant(str, consonant);
break;
case '7':
cout << "Please enter another word, a sentence, or a string of numbers." << endl;
cin.ignore();
getline(cin, str);
cout << str <<endl;
break;
case '8':
cout<< str2;
break;
case 'q':
another = false;
break;
}
}
cin.get();
cin.get();
return 0;
}
void jumbleString(string str)
{
int length = str.length();
int j, k;
for(int i = 0; i < length; j++)
{
k = rand() % length;
j = rand() % length;
char c = str[j];
str[j] = str[k];
str[k] = c;
}
cout << str<<endl;
}
int countWords(string str)
{
int length = str.length();
int words = 1;
for(int size = 1; length > size; size++)
{
if (str[size] == ' ' && str[size-1] != ' ')
words++;
}
if (str[0] == ' ')
words--;
return words;
}
int countConsonant(string str, int consonant)
{
int length = str.length();
consonant = 0;
for (int i = 0; i < length; i++)
{
if (str[i] != 'a' && str[i] != 'e' && str[i] != 'i' &&
str[i] != 'o'&& str[i] != 'u' && str[i] != 'A' && str[i] != 'E'
&& str[i] != 'I' && str[i] != 'O' && str[i] != 'U' && str[i] != ' '&& str[i] != '1'
&& str[i] != '2' && str[i] != '3' && str[i] != '4' && str[i] != '5' && str[i] != '6'
&& str[i] != '7' && str[i] != '8' && str[i] != '9' && str[i] != '0')
consonant = consonant + 1;
}
return consonant;
}
the problem is changing i inside the loop (I guess you meant to change k):
if you did mean to set k, change i = rand() % length; into k = rand() % length;
also, your question is a variant of the permutation problem, which Fisher-Yates solves. I would suggest looking at it, you will probably get better "randomness" by using it.
You are mistakenly using the loop variable, i , twice here. Also you might want to seed the random number generator if you want truly random jumbling of the strings.
For an idiomatic way of doing this in c++ you can use the standard algorithms to do this as follows:
#include <iostream>
#include <algorithm>
#include <ctime>
#include <cstdlib>
int main(void){
srand ( unsigned ( time (NULL) ) );//seed the random shuffle
std::string test = "abcdef";
std::cout << "original string: " << test << std::endl;
std::random_shuffle(test.begin(),test.end());
std::cout << "shuffled string: " << test << std::endl;
return 0;
}
You are using i, j for your two random indices whereas these should be j, k.
It should be:
j = rand() % length;
k = rand() % length;
You are using i as loop variable but at the same time assign a random value to it within the loop.
A possible solution would be not to use two randoms at all but instead the iterating variable i itself [online example].
for(int i = 0; i < length; i++)
{
j = i + (rand() % (length-i));
char c = str[j];
str[j] = str[i];
str[i] = c;
}