Beginner code looking for improvements [closed] - c++
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 4 years ago.
Improve this question
I'm very new to C++. The code below is something I made and functions just fine. However, it seems rather long and I feel like it could be reduced - perhaps to increase efficiency.
The purpose of this code is to translate any DNA sequence into its respective amino acid sequence. It includes a portion where the DNA sequence is verified by the user. Three ORFs are generated using the inputted sequence.
Although it is functional, I have some issues with my program.
One, I would like to make the size of the amino acid array (AA_string1, 2, and 3) as large as they need to be. No concrete memory allocation (so I don't have to change the code all the time) and no wasted memory. Could this be accomplished by pointer arrays?
Two, if the user inputs something that is not expected (like a 2 where you were supposed to enter a 1 or 0), my program encounters an "out_of_range" memory error. I believe I could fix this by adding an error message upon invalid input and returning to a line of code just prior to where the error occurred. I attempted using the "goto" command to do this, laying out various labels for where I'd like the code to reset. This doesn't seem to be working. I continue to encounter an out_of_range memory error upon invalid input.
If you guys have any suggestions on the issues I mentioned or the code itself, let me know in the comments below!
P.S. I put asterisks around the lines of code that I mentioned in my issues.
int main()
{
// Key for converting DNA sequence to amino acid sequence.
string codons[64] = { "UUU","UUC","UUA","UUG","UCU","UCC","UCA","UCG","UAU","UAC","UAA","UAG","UGU","UGC","UGA","UGG",
"CUU","CUC","CUA","CUG","CCU","CCC","CCA","CCG","CAU","CAC","CAA","CAG","CGU","CGC","CGA","CGG",
"AUU","AUC","AUA","AUG","ACU","ACC","ACA","ACG","AAU","AAC","AAA","AAG","AGU","AGC","AGA","AGG",
"GUU","GUC","GUA","GUG","GCU","GCC","GCA","GCG","GAU","GAC","GAA","GAG","GGU","GGC","GGA","GGG" };
string aminoAcids[64] = { "Phe(F)","Phe(F)","Leu(L)","Leu(L)", "Ser(S)","Ser(S)","Ser(S)","Ser(S)","Tyr(Y)","Tyr(Y)", "Stop(*)","Stop(*)", "Cys(C)","Cys(C)","Stop(*)", "Trp(W)",
"Leu(L)","Leu(L)","Leu(L)","Leu(L)","Pro(P)","Pro(P)","Pro(P)","Pro(P)","His(H)","His(H)","Gln(Q)","Gln(Q)","Arg(R)","Arg(R)","Arg(R)","Arg(R)",
"Ile(I)","Ile(I)","Ile(I)","Met(M)","Thr(T)","Thr(T)","Thr(T)","Thr(T)","Asn(N)","Asn(N)","Lys(K)","Lys(K)","Ser(S)","Ser(S)","Arg(R)","Arg(R)",
"Val(V)","Val(V)","Val(V)","Val(V)","Ala(A)","Ala(A)","Ala(A)","Ala(A)","Asp(D)","Asp(D)","Glu(E)","Glu(E)","Gly(G)","Gly(G)","Gly(G)","Gly(G)" };
// Variable declaration.
string DNA_string;
*string AA_string1[100];*
*string AA_string2[100];*
*string AA_string3[100];*
// User inputs DNA sequence.
cout << "Enter DNA sequence here: " << endl;
cin >> DNA_string;
cout << "\n";
// Preparing for sequence conversion.
int dnaLength = DNA_string.length();
int numberofCodons = dnaLength / 3;
int i = 0;
int j = 0;
int baseError;
string baseCorrect;
bool isCorrect = 0;
// Verifies if DNA sequence is inputted correctly.
while (isCorrect == 0)
{
// Enters codons into the amino acid string array.
j = 0;
while (j <= numberofCodons)
{
for (i = 0; i <= dnaLength; i += 3)
{
AA_string1[j] = DNA_string.substr(i, 3);
j += 1;
}
}
// Displays the DNA sequence as sets of codons.
for (i = 0; i <= numberofCodons; i++)
{
cout << AA_string1[i] << " ";
// Indicates base position.
if ((i + 1) % 10 == 0)
{
cout << ((i + 1) * 3) << " ";
}
}
*UserVerify:*
// Asks user to verify sequence.
cout << "\nIs the following sequence correct?\n";
cout << "Type 1 for yes and 0 for no: ";
cin >> isCorrect;
*if (isCorrect != 0 && isCorrect != 1)
{
cout << "Invalid Input: Please enter 1 or 0.";
goto UserVerify;
}*
else if (isCorrect == 0)
{
cout << "\nPlease enter the base position you would like to change:
";
cin >> baseError;
cout << "What should the base be changed to? If it should be
deleted, type 0: ";
cin >> baseCorrect;
if (baseCorrect == "0")
{
DNA_string = DNA_string.erase(baseError - 1, 1);
}
else
{
DNA_string = DNA_string.replace(baseError - 1, 1, baseCorrect);
}
}
cout << "\n";
}
*DNA_Conversion:*
// Converts DNA sequence into AA sequence over three ORFs.
// computeORF is a void function I made.
computeORF(AA_string1, 0, DNA_string, codons, aminoAcids);
computeORF(AA_string2, 1, DNA_string, codons, aminoAcids);
computeORF(AA_string3, 2, DNA_string, codons, aminoAcids);
system("Pause");
return 0;
}
You have some issues with your program. First of all, indexes range from 0...n-1. If you have an array of length 10, the only indexes within that range are 0...9. Essentially all of your <= operators need to become < operators (since index 9 is the 10th allocated spot in an array).
Since you are iterating in steps of three, you will need to set your upper bound lower:
for (i = 0; i <= dnaLength; i += 3)
becomes
for (i = 0; i < dnaLength - 3; i += 3)
Futhermore, you can use pointers for this assignment but that will only affect algorithm speed and will not allow dynamically allocated arrays. If you wish to change the length of a list in C++, I would recommend using std::vector.
To declare a pointer:
int *myPointer = 10;
Now myPointer is a memory address pointing to where the value 10 is stored.
&myPointer;
Will retrieve the value 10.
Additionally, regarding
(isCorrect != 0 && isCorrect != 1)
please check out this link: http://www.cplusplus.com/forum/beginner/139177/
Related
Program only works with inclusion of (side effects free) cout statements?
So I've been working on problem 15 from the Project Euler's website , and my solution was working great up until I decided to remove the cout statements I was using for debugging while writing the code. My solution works by generating Pascal's Triangle in a 1D array and finding the element that corresponds to the number of paths in the NxN lattice specified by the user. Here is my program: #include <iostream> using namespace std; //Returns sum of first n natural numbers int sumOfNaturals(const int n) { int sum = 0; for (int i = 0; i <= n; i++) { sum += i; } return sum; } void latticePascal(const int x, const int y, int &size) { int numRows = 0; int sum = sumOfNaturals(x + y + 1); numRows = x + y + 1; //Create array of size (sum of first x + y + 1 natural numbers) to hold all elements in P's T unsigned long long *pascalsTriangle = new unsigned long long[sum]; size = sum; //Initialize all elements to 0 for (int i = 0; i < sum; i++) { pascalsTriangle[i] = 0; } //Initialize top of P's T to 1 pascalsTriangle[0] = 1; cout << "row 1:\n" << "pascalsTriangle[0] = " << 1 << "\n\n"; // <-------------------------------------------------------------------------------- //Iterate once for each row of P's T that is going to be generated for (int i = 1; i <= numRows; i++) { int counter = 0; //Initialize end of current row of P's T to 1 pascalsTriangle[sumOfNaturals(i + 1) - 1] = 1; cout << "row " << i + 1 << endl; // <-------------------------------------------------------------------------------------------------------- //Iterate once for each element of current row of P's T for (int j = sumOfNaturals(i); j < sumOfNaturals(i + 1); j++) { //Current element of P's T is not one of the row's ending 1s if (j != sumOfNaturals(i) && j != (sumOfNaturals(i + 1)) - 1) { pascalsTriangle[j] = pascalsTriangle[sumOfNaturals(i - 1) + counter] + pascalsTriangle[sumOfNaturals(i - 1) + counter + 1]; cout << "pascalsTriangle[" << j << "] = " << pascalsTriangle[j] << '\n'; // <-------------------------------------------------------- counter++; } //Current element of P's T is one of the row's ending 1s else { pascalsTriangle[j] = 1; cout << "pascalsTriangle[" << j << "] = " << pascalsTriangle[j] << '\n'; // <--------------------------------------------------------- } } cout << endl; } cout << "Number of SE paths in a " << x << "x" << y << " lattice: " << pascalsTriangle[sumOfNaturals(x + y) + (((sumOfNaturals(x + y + 1) - 1) - sumOfNaturals(x + y)) / 2)] << endl; delete[] pascalsTriangle; return; } int main() { int size = 0, dim1 = 0, dim2 = 0; cout << "Enter dimension 1 for lattice grid: "; cin >> dim1; cout << "Enter dimension 2 for lattice grid: "; cin >> dim2; latticePascal(dim1, dim2, size); return 0; } The cout statements that seem to be saving my program are marked with commented arrows. It seems to work as long as any of these lines are included. If all of these statements are removed, then the program will print: "Number of SE paths in a " and then hang for a couple of seconds before terminating without printing the answer. I want this program to be as clean as possible and to simply output the answer without having to print the entire contents of the triangle, so it is not working as intended in its current state.
There's a good chance that either the expression to calculate the array index or the one to calculate the array size for allocation causes undefined behaviour, for example, a stack overflow. Because the visibility of this undefined behaviour to you is not defined the program can work as you intended or it can do something else - which could explain why it works with one compiler but not another. You could use a vector with vector::resize() and vector::at() instead of an array with new and [] to get some improved information in the case that the program aborts before writing or flushing all of its output due to an invalid memory access. If the problem is due to an invalid index being used then vector::at() will raise an exception which you won't catch and many debuggers will stop when they find this pair of factors together and they'll help you to inspect the point in the program where the problem occurred and key facts like which index you were trying to access and the contents of the variables. They'll typically show you more "stack frames" than you expect but some are internal details of how the system manages uncaught exceptions and you should expect that the debugger helps you to find the stack frame relevant to your problem evolving so you can inspect the context of that one.
Your program works well with g++ on Linux: $ g++ -o main pascal.cpp $ ./main Enter dimension 1 for lattice grid: 3 Enter dimension 2 for lattice grid: 4 Number of SE paths in a 3x4 lattice: 35 There's got to be something else since your cout statements have no side effects. Here's an idea on how to debug this: open 2 visual studio instances, one will have the version without the cout statements, and the other one will have the version with them. Simply do a step by step debug to find the first difference between them. My guess is that you will realize that the cout statements have nothing to do with the error.
Program not running with Array during Initialization
I'm just practicing using arrays. So my program consist of inputting numbers of data type double into the array and have them print out. Simple. I only limited the numbers down to 4. So the array, num_List[3] is in the code. I've made sure to use the for loops properly for reading and printing out the result. The first few times I tested the code. I realized that the 4th number in the array was in scientific notation, telling me that I forgot to initialize the array to 0, in this case 0.0, since I'm using double. So I put in this code. for (index = 0; index <= 3; index++) num_List[index] = 0.0; This code should have initialized the arrays of num_List to 0.0. However, when I tested this, nothing came up, after I inputted the 4 numbers. So I made a logical error here or it's something else with the for loop that's causing it to be trapped and not continue the execution. I've read in the books about this particular way to initialize. #include <iostream> using namespace std; int main() { double num_List[3]; // These are my variables int index; //double num; // Ignore these two for now, for they are to be modified later on. //double result; cout << "This program will summarize the numbers you've inputted print out the result. \n"; cout << "And also print out the address of the 1st and 4th address in the array." << endl; cout << "Please enter the four numbers to be summarized."; for (index = 0; index <= 3; index++) { // I put this in after I realized my mistake of not initializing my arrays to 0.0. num_List[index] = 0.0;} // This is where the problem is, I think. for (index = 0; index <= 3; index++) // This reads in the user the input cin >> num_List[index]; cout << "The numbers you have inputted is:\n"; for (index = 0; index <= 3; index++) // This prints out the array. cout << num_List[index] << ", " << endl; return 0; } If you focus on the aforementioned code, and try to compile it, you'll see that my code unfortunately doesn't continue on from there after you input 4 numbers, regardless of whether or type a number and space it up to 4 numbers, or input a number, press the enter key for those numbers. Most likely I've made a obvious mistake, but I'm having some trouble seeing it. I use Code Blocks, so things are a little different compared to the Bloodshed C++ compiler I used to use to practice codes on.
double num_List[3]; This declares an array with 3 elements, indexed 0 through 2. for (index = 0; index <= 3; index++) This loops through 4 indices, 0 through 3. When you do something with num_List[3], you get undefined behavior. In your trial, the undefined behavior fortunately resulted in just some garbage output.
Any suggestions to why this loop isn't executing?
I have written the function below, which groups charterers together before encountering a space and saves each group in a vector, once a space is encountered it should look for another group and do the same thing over and over! My debugging so far indicates that the for loop within the if statement is not executing for some reason. char const* MathematicaLib::IsThisAnEquation(char const* equation){ // execute PEMDAS here vector <char const*> SeperatedValues; char *TempGH = ""; int temp = 0; int SOG = 0; //start of group //cout << equation[2] << endl; // used to test whether the funcion is reading the input parameter for (int j = 0; j < strlen(equation); j++) { if (isspace(equation[j])) { //cout << "processing" << endl; // used to confirm that its reading values until a space is encountered for (int n = SOG; n < j - 1; n++){ TempGH[temp] = equation[n]; temp++; SOG = j + 1; //skip charecter cout << "test"; //this does not print out meaning that the loop dosen't execute } temp = 0; SeperatedValues.push_back(TempGH); } } for (unsigned int p = 0; p < SeperatedValues.size(); p++){ // used for debugging only cout << SeperatedValues[p] << endl; cout << "This should be reading the vector contents" << endl; } return ""; }// end of IsThisAnEquation Assume that the value I am passing to the function is "123 1", also assume that the first character of the parameter is never a space. This means that when a space is detected then n == 0 AND j-1 == 2 (j-1 indicates the end of the group of characters while n = the start) the loop should cause the characters in position 0 to 2 (123) to be pushed into the vector, thus j is not == 0 or -1. The loop is not directly embedded under the first for loop rather it is under the if statement, shouldn't this force to only execute if the condition within the if statment is true? rather than follow the rules of embedded loops execution? Any suggestions to why this loop isn't executing? I have reviewed the code over and over to spot any logical errors, but I couldn't find any so far!
My bad if (isspace(equation[j]) was the root of all evil, this condition was not being met because std::cin >> equation does not register spaces, replacing it with this std::getline(std::cin, equation); managed to solve the problem, the for loop now executes. Thanks to #PaulMcKenzie and #Joachim Pileborg for pointing out the issue of modifying string literals. Sorry I didn't mention that I was passing the parameter through std::cin>> !
Variable not being set and returning a unusual number [closed]
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 years ago. Improve this question I have a function that is being used to calculate the damage caused towards an object string Weapon::attack(int Damage, int ExtraDamage, string Type) { srand(time(NULL)); int totalDamage = 0; int percentileDie = rand() % 100 + 1; if (percentileDie <= ChanceToHit) { for (int i = 0; i <= Damage; i++) { int sixSidedDie = rand() % 6 + 1; totalDamage = totalDamage + sixSidedDie; } totalDamage = totalDamage + ExtraDamage; } else { totalDamage = 0; } Result = totalDamage; if (Type == "Crossbow") { return "Twang! "; } else if (Type == "Dagger" || Type == "Sword") { return "Swing! "; } } However, when I go and call the variable Result in my program, I get the number -858993460. I changed Result = totalDamage to Result = 6 to see if it would return 6 but it once again returned -858993460. Can anyone help me out? If I do this: Weapon t; t.attack(2, 4, "Sword"); cout << t.attack(2, 4, "Sword") << t.Result << endl; I get the correct number, but if I do this: Weapon t; cout << t.attack(2, 4, "Sword") << t.Result << endl; I get the number -858993460 again! Also, Result is declared in a class: class Weapon { public: string Name; int Damage, ExtraDamage, Result; float ChanceToHit; string attack(int,int,string); };
The order of evaluation of cout << X << Y is not ordered for X and Y. So this code: Weapon t; cout << t.attack(2, 4, "Sword") << t.Result << endl; will evaluate either t.attack() or t.Result first - based on your post, it would seem that t.Result is evaluated first. The solution is to force the compiler to do things in the correct order, e.g. Weapon t; std::string str = t.attack(2, 4, "Sword"); cout << str << t.Result << endl;
If you look into what exactly is going on here, then you will realize that operator "<<" is being used to add data to output stream. The "<<" operator is defined to add data on stream and return a reference of modified stream for further use, this is the reason we can use multiple "<<" in single "cout" So the order of putting values on stream is reverse of the order in which you read it. So it is like cout<<firstOperand<<secondOperand<<thirdOperand; is evaluated as cout(<<firstOperand(<<secondOperand(<<thirdOperand))); Which in turn means that "thirdOperand" is added to output stream first then updated stream is returned. Now "secondOperand" is pushed to the same returned stream similarly and then "firstOperand" is pushed to the output stream. Now all "<<" operators are done. Now cout puts the stream content on the output file. So, in your case, because t.Result is getting added to output stream before its calculation in class function, the value that you get is random value of Result initialized during object construction.
Parse int and string
Hi I'm not sure if this is the right place to ask this question. Anyway I have written this code to parse a molecule formula and split it into atoms and amount of each atoms. For instance if I input "H2O" I will for the atom array get {"H", "O"} and in the amount array I will get {2, 1}. I haven't taken account for amount that is larger than 9, since I don't think there are molecule which can bind to something that is larger than 8. Anyway I'm quite newbie, so I wonder if this piece of code can be made better? string formula = "H2O"; int no, k = 0, a = 0; string atom[10]; int amount[10]; bool flag = true; stringstream ss(formula); for(int i = 0; i < formula.size(); ++i) { no = atoi(&formula[i]); if(no == 0 && (flag || islower(formula[i]) ) ) { cout << "k = " << k << endl; atom[k] += formula[i]; flag = false; cout << "FOO1 " << atom[k] << endl; amount[a] = 1; } else if(no != 0) { amount[a] = no; cout << "FOO2 " << amount[a] << endl; a++; flag = true; k++; } else { k++; a++; atom[k] = formula[i]; cout << "FOO3 " << atom[k] << endl; amount[a] = 1; flag = false; } cout << no << endl; }
Have you considered an approach with regular expressions? Do you have access to Boost or TR1 regular expressions? An individual atom and its count can easily be represented as: (after edits based on comments) ([A-Z][a-z]{0,2})([0-9]*) Then you just need to repeatedly find this pattern in your input string and extract the different parts.
There are many potential improvements that could be made, of course. But as a newbie, I guess you only want the immediate ones. The first improvement is to change this from a program that has a hard coded formula to a program that reads a formula from the user. Then try testing yout program by inputting different formulae, and check that the output is correct.
What if you modified it to be like this algorithm? This would maybe be less code, but would definitely be more clear: // while not at end of input // gather an uppercase letter // gather any lowercase letters // gather any numbers // set the element in your array This could be implemented with 3 very simple loops inside of your main loop, and would make your intentions to future maintainers much more obvious.