3-way mergesort stackoverflow error in c++ - c++

hi guys can anyone tell me what's wrong with my 3-way mergesort code?the code I wrote can only sort 4 numbers if you give it more than 4 numbers(by changing size) it ends up with stack overflow error,here is the code:
#include "stdafx.h"
#include <iostream>
#include <vector>
using namespace std;
const int size=4;
vector <int> s(size);
void merge(int,int,int);
void mergesort(int,int);
int main(){
for(int i=0;i<size;i++){
cout<<"enter number "<<i+1<<":";
cin>>s.at(i);
}
system("CLS");
cout<<"here are the unsorted numbers:\n";//prints the input values so U can see'em
for(int j=0;j<size;j++)
cout<<s.at(j)<<".";
mergesort(0,size-1);//calls mergesort
cout<<"\nhere are the sorted numbers:\n";
for(int j=0;j<size;j++)
cout<<s.at(j)<<".";
cin.get();
cin.get();
return 0;
}
void merge(int low,int one_third,int high){
int i=low;
int j=one_third+1;
int k=0;
int length=(high-low)+1;
vector <int> u(length,0);
if(k<length){
while((i<=one_third)&&(j<=high)){
if(s.at(i)<=s.at(j)){
u.at(k)=s.at(i);
i++;
k++;
}//end for
else{
u.at(k)=s.at(j);
j++;
k++;
}//end elseif
}//end while
if(j>high)
while(i<=one_third)
{
u.at(k)=s.at(i);
i++;
k++;
}
if(i>one_third)
while(j<=high)
{
u.at(k)=s.at(j);
j++;
k++;
}
for(int n=low;n<k;n++)
s.at(n)=u.at(n);
}
}//end if
void mergesort(int low,int high){
if(low<high){
int one_third=(high-low)/3;//division,it's 3-way mergesort so obviously it's divided by 3
int two_third=2*one_third;
mergesort(low,one_third);
mergesort(one_third+1,two_third);
mergesort(two_third+1,high);
merge(low,one_third,two_third);
merge(low,two_third,high);
}//end if
}
at this point I guess I'm done thinking,Any answer/idea would be appreciated.

Here's a partial inspection of your code. I believe there is an issue debugging a 3 way merge sort with 4 values. You should use more values, such as 6 or 7.
Spaces not tabs for StackOverflow
I'll take a guess that the indentation is because you use tab characters in your code and pasted directly. You'll want to expand the tabs in your next post.
Precompiled Headers
Is your project huge? Does it significantly reduce the build time when you change a header or modify the source code?
I find that stdafx usually is more of a hassle and the time spent resolve defects it causes negates any potential savings by having a precompiled header.
Function prototypes should use named parameters
Can you tell the purpose of the different parameters in your declaration of merge and mergeSort?
Ambiguity breeds defects. 'nuff said.
Main function declared wrong.
The main function always returns an int to the operating system, always. The OS can ignore it.
This mechanism is so that script files can execute your program and test for errors.
Readability prevents defects
Invest in spaces around operators. The time saved by sacrificing spaces is negligible. The debugging time saved by having easy to read code is tremendous, especially when having other people review or inspect your code.
Use intermediate variables
Intermediate variables help clarify your program. They don't cost memory when you tell the compiler to optimize. During debugging, they can help show values during calculations.
The typical idiom for reading into a vector is:
int value;
cin >> value;
s.push_back(value);
The at method may have an overflow issue (or at least your not checking for out of bounds issues). The push_back method will cause the vector to expand as necessary.
Meaningful variable names reduces defects
The variable s has no meaning. Something like original_values or number_container are more descriptive. And again, variable name lengths have nothing to do with improving performance. Readable names help reduce the defects injected.
Not checking state of cin
If I enter "Lion" in response to your 2nd prompt, what will be in the 2nd slot of the array?
Don't trust the Users, they aren't perfect.
Don't clear the screen
It may contain useful data, such as the actual numbers entered. So when you are debugging, and want to know what the User actually typed in, it will be lost and gone forever.
Why cin.get twice?
You are asking the User for input without prompting. And twice. Bad Karma between your program and the User.
See cin.ignore if you want to ignore characters until a specific one is received. Something like this perhaps:
cout << "Paused. Press Enter to continue.\n";
cin.ignore(100000, '\n');
Magic numbers
In function mergesort, you use the numbers 2 and 3. Why? What's their purpose?
Redundant comments
Most programmers realize that the '/' character in a math expression is division. The comment is redundant.
Also, why divide by 3? It's a nasty number. Do you realize you are performing integer division and your product will be truncated? For example: 1/3 == 2/3 == 0.
USE A DEBUGGER
Lastly, a lot of your program's functionality can be verified easier and quicker by using a debugger. A debugger allows you to execute a statement and see the variable values. You can set breakpoints to stop execution at different places. It's a worthwhile educational investment, start now.

A "classic" 3 way merge sort merges runs 3 at a time, alternating between a source and destination array (or vector or list). The code needs to perform up to 3 compares in order to determine the "smallest" of 3 values from each of the 3 runs, then move the smallest value from it's corresponding run to the destination array. The code also has to handle the case where the end of a run is reached, leaving only 2 runs to merge, then the case where the end of the second run is reached, in which case the rest of the third run is moved to the destination array.
For a ram based sort, I'm not sure this is any faster than a normal 2 way merge. For an external sort, with multiple devices or very large read and writes, then a k way merge with k up to 12 or 16 will be faster.

Related

How is static array expanding itself? [duplicate]

This question already has answers here:
Why is it that we can write outside of bounds in C?
(7 answers)
Is accessing a global array outside its bound undefined behavior?
(8 answers)
Undefined, unspecified and implementation-defined behavior
(9 answers)
Closed 11 months ago.
I wrote a code for entering element and displaying the array at the same time. The code works but since char A[4] is static memory why does not it terminate/throw error after entering more than four elements? Code:
#include <iostream>
using namespace std;
void display(char arr[],int n)
{
for(int i=0; i<n; i++)
cout<<arr[i]<<" ";
return;
}
int main()
{
char A[4];
int i=0;
char c;
for(;;)
{
cout<<"Enter an element (enter p to end): ";
cin>>c;
if(c=='p')
break;
A[i]=c;
i++;
display(A,i);
system("clear");
}
return 0;
}
Writing outside of an array by using an index that is negative or too big is "undefined behavior" and that doesn't mean that the program will halt with an error.
Undefined behavior means that anything can happen and the most dangerous form this can take (and it happens often) is that nothing happens; i.e. the program seems to be "working" anyway.
However maybe that later, possibly one million instructions executed later, a perfectly good and valid section of code will behave in absurd ways.
The C++ language has been designed around the idea that performance is extremely important and that programmers make no mistakes; therefore the runtime doesn't waste time checking if array indexes are correct (what's the point if the programmers never use invalid ones? it's just a waste of time).
If you write outside of an array what normally happens is that you're overwriting other things in bad ways, possibly breaking complex data structures containing pointers or other indexes that later will trigger strange behaviors. This in turn will get more code to do even crazier things and finally, some code will do something that is so bad that even the OS (that doesn't know what the program wants to do) can tell the operation is nonsense (for example because you're trying to write outside the whole address space that was given to the process) and kills your program (segfault).
Inspecting where the segfault is coming from unfortunately will only reveal what was the last victim in which the code is correct but that was using a data structure that was corrupted by others, not the first offender.
Just don't make mistakes, ok? :-)
The code works but since char A[4] is static memory why does not it terminate/throw error after entering more than four elements?
The code has a bug. It will not work correctly until you fix the bug. It really is that simple.

Array Function. Would appreciate a little clarification

I have a question regarding a school lab assignment and I was hoping someone could clarify this a little for me. I'm not looking for an answer, just an approach. I've been unable to fully understand the books explanations.
Question: In a program, write a function that accepts three arguments: an array, the size of the array, and a number n.
Assume that the array contains integers. The function should display
all of the numbers in the array that are greater than the number n .
This is what I have right now:
/*
Programmer: Reilly Parker
Program Name: Lab14_LargerThanN.cpp
Date: 10/28/2016
Description: Displays values of a static array that are greater than a user inputted value.
Version: 1.0
*/
#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;
void arrayFunction(int[], int, int); // Prototype for arrayFunction. int[] = array, int = size, int = n
int main()
{
int n; // Initialize user inputted value "n"
cout << "Enter Value:" << endl;
cin >> n;
const int size = 20; // Constant array size of 20 integers.
int arrayNumbers[size] = {5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24}; // 20 assigned values for the array
arrayFunction(arrayNumbers, size, n); // Call function
return 0;
}
/* Description of code below:
The For statement scans each variable, if the array values are greater than the
variable "n" inputted by the user the output is only those values greater than "n."
*/
void arrayFunction(int arrayN[], int arrayS, int number) // Function Definiton
{
for (int i=0; i<arrayS; i++)
{
if (arrayN[i] > number)
{
cout << arrayN[i] << " ";
cout << endl;
}
}
}
For my whole answer I assume that this:
Question: In a program, write a function that accepts three arguments: an array, the size of the array, and a number n. Assume that the array contains integers. The function should display all of the numbers in the array that are greater than the number n .
is the whole assignment.
void arrayFunction(int[], int, int); is probably the only thing you could write. Note however that int[] is in fact int*.
As others pointed out don't bother with receiving input. Use something along this line: int numbers[] = {2,4,8,5,7,45,8,26,5,94,6,5,8};. It will create static array for you;
You have parameter int n but you never use it.
You are trying to send variable to the function arrayFunction but I can't see definition of this variable!
Use something called rubber duck debugging (google for it :) ). It will really help you.
If you have some more precise question, ask them.
As a side note: there are better ways of sending an array to the function, but your assignment forces you to use this old and not-so-good solution.
Would you use an if else statement? I've edited my original post with the updated code.
You have updated question, then I update my answer.
First and foremost of all: do indent your code properly!!!
If you do that, your code will be much cleaner, much more readable, and it will be much easier understandable not only for us, but primairly for you.
Next thing: do not omit braces even if they are not required in some context. Even experienced programmers only rarely omit them, so as a beginner you should never do so (as for example with your for loop).
Regarding if-else statement the short answer is: it depends.
Sometimes I would use if (note: in your case else is useless). But other times I would use ternary operator: condition ? value_if_true : value_if_false; or even a lambda expression.
In this case you should probably settle for an if, as it will be easier and more intuitive for you.
Aside from the C++ aspect, think about the steps you need to do to figure out if a number is greater than a certain value. Then do that for all the numbers in the array, and print out the number if it's greater than n. Since you have a 'for' loop, it looks like you already know how to do a loop and compare numbers in C++.
Also, it looks like in your arrayFunction you are trying to input values? You can't input a whole array's worth of values in a single statement like you appear to be trying (also, 'values' is not the name of any variable in arrayFunction, so that would not be recognized when you try to compile it).

Special Fibonacci and SIGSEGV

#include<bits/stdc++.h>
#define big 1000000007
using namespace std;
long long n,k;
int fobo(int);
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
k=fobo(n)%big;
printf("%d",k);
printf("\n");
}
return 0;
}
int fobo(int m)
{
if(m==1)
return 0;
if(m==2)
return 1;
return 3*fobo(m-1)+2*fobo(m-2)+5;
}
The above code is for printing the sum of a special kind of Fibonnacci series following the relation given in the recurrence relation inside the function fobo . The code works fine on my machine but on testing in any online judge , the same code shows SIGSEGV error. There is no use of any arrays in the program , accessing unknown memory that i know of. I guess these are the some of the major requirements for having a SIGSEGV error. I cant find any in here . Please help me in resolving or finding the error.
If I had to guess, this looks like a stack overflow error. Try feeding 0 into fobo. When that happens, your base cases don't trigger because neither one checks for zero. You then call fobo(-1) and fobo(-2), which will start a chain of recursive calls of the form fobo(-2), fobo(-3), fobo(-4), etc. until you eventually overflow the stack.
To fix this, consider adding in a new base case for 0 in your code, or alternatively put in a general check to handle the case where the input is negative.
EDIT: Based on the comments, I think the main issue here is that if you call this function with a large input, you'll get a stack overflow before the recursion terminates. To address this, consider computing your values bottom-up using dynamic programming. I suspect that's what the question is ultimately trying to get at. Alternatively, use a different recursive formulation amenable to tail call elimination. If you're not familiar with these techniques, look online - you'll learn a lot in the process!

Array causes stack overflow error

My program is this:
#include<iostream>
#include<fstream>
using namespace std;
int main()
{
char choice;
int o,i,marks[i],ttlcredit=0;
double ttlGPA=0,finalGPA=0,credit[7][2],clsavg;
cout<<"Please enter what you want to calculate"<<endl;
cout<<"A for calculating Class Average GPA"<<endl;
cout<<"B for calculating a Specific GPA"<<endl;
cout<<"Your choice is? ";
cin>>choice;
cout<<endl;
if (choice == 'A'||choice == 'a')
{
cout<<"=========================================="<<endl;
cout<<" Class Average GPA"<<endl;
cout<<"=========================================="<<endl<<endl;
cout<<"Please enter the number of students in the class: ";
cin>>number;
for(i=0;i<number;i++)
{
cout<<"\nEnter student #"<<i+1<<"'s marks: ";
cin>>marks[i];
ttlGPA=ttlGPA+marks[i];
}
clsavg=ttlGPA/number;
cout<<"\nThe Average is: "<<clsavg<<endl;
}
else
{
}
}
It is half completed. When I build and run on CodeBlocks, an error instantly appeared:
I tried finding the source of error and I think that it is caused by the following in the code:
int o,i,marks[i],ttlcredit=0;
What makes me think so is because when I remove the [i] from marks[i], I will be not receive that error.
I think is stack overflow because I use Microsoft Visual Studio to help me debug and this is the error they gave me:
Unhandled exception at 0x0041419e in Project (1).exe: 0xC00000FD: Stack overflow.
My question is...
Is that the main cause of problem?
How do I resolve this issue?
You have to initialize the marks array with a positive length.
Get the number of students first, THEN create the array using that number.
Also, you need to declare the variable number.
As the other answers stated correctly, the problem is that int i is used uninitialized. However, the proposed fix
// initialze i
int marks[i];
is not standard C++, but only available through a compiler extension. In C++, the length of a built-in array must be a compile time constant. The better solution would be using std::vector:
// initialize i (better make it std::size_t instead of int)
std::vector<int> marks (i);
This will create a variable length array in a safe and standard conforming way.
First thing to say is that you simply shouldn't use arrays. They just are too weird in C and C++, and we have superior alternatives in modern C++.
Anyway, whether you use arrays or vectors, there are some important issues. Before discussing marks[i], it's simpler to look at credit[7][2] in this code.
int o,i,marks[i],ttlcredit=0;
double ttlGPA=0,finalGPA=0,credit[7][2],clsavg;
The dimensions are explicit in this declaration of credit. It's seven-times-two. Simple enough. You can read and write to credit[0][0] and credit[6][1] and many other values. But if you go outside the range, e.g. try to use credit[7][0], your program will compile and will probably appear correct for a while, but it could behave very badly and it is undefined how it will behave. It could decide to delete all the files on your computer, it is (seriously) entitled to do anything random and crazy. This is Undefined Behaviour.
Anyway, the really weird line is the declaration of marks.
int marks[i];
This definitely doesn't do what you think it does. It doesn't create an array that can be "indexed with arbitrary i". No, it allocates an array whose size is the initial value of i. But i is undefined at this stage so this is meaningless.
But i isn't relevant here anyway. How big do you want this array to be? The answer is number, isn't it? That is the number of people you'll store in your array.
So, a small improvement is to do this instead of int marks[i].
int marks[number];
But even this isn't correct. The value of number isn't set until the line cin >> number;, therefore you must declare int marks[number] after the line cin >> number; in order to ensure that marks has the correct size.
But, but, but, even after all this, we still don't have standard C++. It's OK to do int credit[7][2] because the size is fixed at compile time. You are normally not allowed to set the size of an array at runtime, e.g. int marks[number]. You might be able to use it if your compiler allows this extension (it's called Variable Length Array, from C).
So, this is not standard C++, and it's potentially very dangerous (see the Undefined Behaviour). What's the solution?
The solution is the standard solution for any problem involving arrays. Stop using arrays. (Really advanced programmers, in particular situations, might use std::array in modern C++, or even write their own clone of std:: array in older C++. But raw C [] arrays are to be avoided where possible.)
#include<vector>
int o,i,ttlcredit=0;
std::vector<int> marks;
marks is initially empty. We don't do cin >> marks[i];. Instead we use push_back to append new items to the end of the list.
int next_mark;
cin >> next_mark;
marks.push_back(next_mark);
Also, don't use marks[i] with a vector. It might look OK, but it is dangerous. Better to use marks.at(i) to read or write the element. at will do bounds checking for you, giving you a proper error message if i is too small (less then 0) or too big for the size of the vector.
int o,i,marks[i],ttlcredit=0;
i is not initialized. initialize i first.
If you are not sure of the size of the array, allocate it dynamically.
use new
refer this link on how to use new - cpluspluss

C++ Using rand with if statement

I started C++ literally one day ago and I've been having a problem trying to create a rock, paper, scissors game. This code is not exactly how it will look when it's done, but I made this to demonstrate my issue.
I've made brps, meaning: bot rock paper scissors, a random number from 1-3 where the corresponding number will result in a cout stating what item the bot chose.
The rand part of the code was made from viewing different forums and answers to previous questions, but I can't seem to get this to work out. Whenever I run the program it says "Bot chose the rock" no matter what I do. However if I remove the if statemets, and simply print brps it shows a random number each time. So I need help to figure out why the program chooses the rock every single time when that choice should be defined by what number rand chooses.
Feel free to comment on other parts of the code as well, since I'm expecting it all to be somewhat poorly written :L
EDIT: urps is where the user inputs an answer. I didn't use it in this example.
#include <iostream>
#include <stdlib.h>
#include <time.h>
using namespace std;
int main()
{
cout<<"Hi! Welcome to ROCK PAPER SCISSORS!\n";
cout<<"To play, press enter.\n";
cin.get();
system("cls");
int game();
{
srand(time(NULL));
int brps = rand()>>4, urps;
brps = brps % 3 + 1;
cout<<"Bot chose ";
if (brps = 1){
cout<<"the rock.\n";}
else if (brps = 2){
cout<<"the paper.\n"; }
else if (brps = 3){
cout<<"the scissors.\n"; }
else{
cout<<"invalid.\n.";}
cin.get();
}
}
You should use == to compare, not =.
If you write brps = 1, you assign the value 1 to the variable brps, and the value of the assignment expression is then the same as the value that was assigned, that is, 1. This is non-zero, and gets converted to true, so you always get "the rock".
Also note that if your intension was to create a function called game, that is not what your code does. The extra semicolon makes it a declaration, saying that there is a function called game somewhere else, and then the { } block is just that, a { } block, not a function body.
And, as chris says in his comment, do turn on the compiler warnings. Different compilers give different warnings, but g++ gives the warning suggest parentheses around assignment used as truth value for your uses of = instead of ==. Compiler warnings is the compiler trying to help you, and programming is difficult enough that you shouldn't turn down any help.
You use the assignment operator = in your if statements which will assign the value 1 to brps and return a true value.
Use the operator == instead.
By the way: You do'nt call your game();.
Edit:
#include <iostream>
#include <stdlib.h>
#include <time.h>
using namespace std;
int game(); // This one declares the subroutine game()
int main()
{
int exit; /* 0 to continue, something else to exit the game */
cout<<"Hi! Welcome to ROCK PAPER SCISSORS!\n";
cout<<"To play, press enter.\n";
cin.get();
system("cls");
do { // This block will execute at least once
exit = game(); // This one calls the subroutine game()
} while (exit == 0); // ...and will execute again and again until exit != 0
return 0; // Or something useful
}
int game() // This implements the subroutine game()
{
srand(time(NULL));
int brps = rand()>>4, urps;
brps = brps % 3 + 1;
cout<<"Bot chose ";
if (brps == 1) {
cout<<"the rock.\n";
} else if (brps == 2) {
cout<<"the paper.\n";
} else if (brps == 3) {
cout<<"the scissors.\n";
} else{
cout<<"invalid.\n.";
}
cin.get();
if (some_kind_of_exit_condition) {
return 1; // results in exit == 1
}
return 0; // results in exit == 0
}
What I changed in your code:
The line int game(); in your code is neither a function call (since the syntax would be invalid) nor a implementation (because of the ;). The curly braces behind that line simply open a block in your code. This block is not necessary (but not forbidden, though). I changed the code to what I think you wanted to write:
I added a line int game(); at the very beginning that defines the subroutine game() that will enable the compiler to verify the call (in 2.)
I added a line game(); which actually calls the subroutine that is defined in 1.
I removed the ; after your int game(); to make a subroutine implementation of the block below.
I removed the } at the end and moved it to the end of main().
I added return statements at the end of both the main and the game routine.
I changed = to ==
Added a loop
Also note that the system("cls") will only work on systems where such a call exists. This is not very good code, since it it is platform dependent and will spawn at least one new process (perhaps more). In the abstract model of output streams there is no clear screen, since the output may also be a file or a printer (if you call your program with output redirection for example).
If you want to clear your screen, this can not be done with the standard output mechanism (except outputting a bunch of newlines - which is not very good since you don't know how many lines have to be written to clear the screen). If you want to do it better, you may use the Win32 Console API or libncurses. These libraries will enable you to control a visual terminal instead of the abstract line output the standard library gives to you. While the standard output is simple, these libraries aren't, so i'd recommend to continue using the cls but remember to change that later when you are more familar with c++.
You should only call srand() once, at the start of your program. Don't call it every time you need a random number, since this effectively re-initialized the generator.
There are other problems with the code:
1) The if (brps = 1) et al are assignments, not comparisons.
2) The
int game();
{
looks like it's defining a nested function, but it's not. Here game() is a prototype, and the stuff inside the curly braces is simply a nested block directly inside main(). I suspect this is not what you're trying to do.
This page covers the basics of randomization using rand(), srand(), etc. It may be worth a gander for you:
Furthermore, you should use the comparison operator (==), not the assignment operator (=) in your if comparisons; using = will actually set and change the value, and the comparison will be true every time since the result will be assigned to a non-zero value. Since your first if-comparison check succeeds every time for this reason, none of the other tests will even execute, and you'll get rock each time.
Please also note, to get as close to truly random number as possible you have to seed your random number generator with a changing number this is accomplished with: srand(time(0));
This can be placed anywhere before the actual call of the random number.
You will also have to #include <ctime> In order to be able to call time(0).