how to use char ** properly? - c++

I have two examples, which of these two is better and why? In both cases, I got the same result. I have chosen container simply to hold strings.
Example 1:
char *c_ptr[] = {};
int num;
if (fill_array(c_ptr, &num) != 0) {
cout << "Error" << endl;
}
for (int i = 0; i < num; i++) {
cout << "Str[" << i << "] = " << c_ptr[i] << endl;
}
// free pointer..
// Function implementation
int fill_array(char *c_ptr[], int *count) {
vector<string> v = {"haha", "hehe", "omg", "happy, learning!"};
*count = v.size();
int i = 0;
for (vector<string>::iterator it = v.begin(); it != v.end(); it++, i++) {
c_ptr[i] = (char*)malloc((*it).size() + 1);
strncpy(c_ptr[i], (*it).c_str(),(*it).size() + 1);
}
return 0;
}
Example 2:
char **c_ptr = NULL;
int num;
if (fill_array(&c_ptr, &num) != 0) {
cout << "Error" << endl;
}
for (int i = 0; i < num; i++) {
cout << "Str[" << i << "] = " << c_ptr[i] << endl;
}
// free double pointer..
// Function implementation
int fill_array(char ***c_ptr, int *num) {
vector<string> v = {"haha", "hehe", "omg", "happy, learning!"};
*num = v.size();
int i = 0;
*c_ptr = (char **)malloc(*num * sizeof(char *));
for (vector<string>::iterator it = v.begin(); it != v.end(); it++, i++) {
c_ptr[i] = (char*)malloc((*it).size() + 1);
strncpy(*c_ptr[i], (*it).c_str(),(*it).size() + 1);
}
return 0;
}
Result:
Str[0] = haha
Str[1] = hehe
Str[2] = omg
Str[3] = happy, learning!
Also What is the use of empty bracket in array? Is it good programming habit vs dynamic allocation?

** is pointer to a pointer or simply we can say it a double pointer.
Double pointers are better to use when we are passing a pointer variable from main() or simply a function to another function.
By looking at your code, I would like to suggest you one thing and that is, avoid using global variables.

Related

How to delete the new array in c++?

I have created a new point function in c++, where I create a new array by Dynamic memory allocation. However, when I want to delete the array in main function, it reports errors like:
'Assessment_1.exe' (Win32): Unloaded 'C:\Windows\SysWOW64\ucrtbased.dll'
'Assessment_1.exe' (Win32): Loaded 'C:\Windows\SysWOW64\ucrtbased.dll'.
The thread 0x22dc has exited with code 0 (0x0).
HEAP[Assessment_1.exe]: Invalid address specified to RtlValidateHeap( 00050000, 0005F25C )
Assessment_1.exe has triggered a breakpoint.
The return_array.cpp contains the function in which user inputs the keyboards.
#include<iostream>
#include <conio.h>
using namespace std;
//const static int length = 3;
int* input() {
//static int number[length]; fixed length for input
static int* number_array;
int number_length = 30;
int index = 0;
number_array = new int[number_length];
cout << "enter (ESC) to escape the program!" << endl;
while (_getch() != 27)
{
cout << "Input your number " << index << " elment: " << endl;
cin >> number_array[index];
index = index + 1;
cout << endl;
}
return number_array;
}
The practice.cpp contains the main function and the evaluation function of two vectors. The bug is when I add the delete []vector_1;.
#include <vector>
#include<iostream>
#include"myFunctions.h"
using namespace std;
const static int length = 3;
bool same_vec(vector<int> a, vector<int> b);
void main() {
vector<int> new_vector_1(length);
vector<int> new_vector_2(length);
int* vector_1 = input();
for (int i = 0; i < length; i++) {
new_vector_1[i] = *vector_1;
cout << *vector_1 << endl;
vector_1 = vector_1 + 1;
}
delete []vector_1;
for (int i = 0; i < length; i++) {
cout << " The result of vector_1: " << new_vector_1[i] << endl;
}
int* vector_2;
vector_2 = input();
for (int i = 0; i < length; i++) {
new_vector_2[i] = *vector_2;
vector_2 = vector_2 + 1;
}
delete []vector_2;
for (int i = 0; i < length; i++) {
cout << " The result of vector_2: " << new_vector_2[i] << endl;
}
bool qax = same_vec(new_vector_1, new_vector_2);
if (qax == false) {
cout << "the items are not match!"<<endl;
}
else {
cout << "the items are match!" << endl;
}
}
bool same_vec(vector<int> a, vector<int> b) {
//Evaluate the elements in the two vectors
bool flag = true;
int length_a = a.size();
int length_b = b.size();
vector<bool> new_bool(length_a);
for (int i = 0; i < length_a; i++) {
for (int j = 0; j < length_b; j++) {
if (a[i] == b[j]) {
new_bool[i] = true;
cout << a[i] << " " << b[j] << endl;
break;
}
}
}
for (int i = 0; i < new_bool.size(); i++) {
if (new_bool[i] == false) {
flag = false;
}
}
return flag;
}
And the myFunction.h is my head file.
#pragma once
int* getRandom();
int* input();
Can someone helps to solve the problem? I know one solution is delete the line of delete []vector_1;. The solution may cause memory-leak.
You are changing the address stored in the vector_1 pointer, then trying to delete[] something that no longer corresponds to the pointer returned by the new operator in your input function.
So, instead of this loop:
for (int i = 0; i < length; i++) {
new_vector_1[i] = *vector_1;
cout << *vector_1 << endl;
vector_1 = vector_1 + 1; // This line changes the pointer!
}
delete []vector_1; // And, here, the pointer is NOT what "new" gave you!
Use something like this, instead:
for (int i = 0; i < length; i++) {
new_vector_1[i] = vector_1[i]; // You can use the [] operator on the pointer
cout << *vector_1 << endl;
// vector_1 = vector_1 + 1; // Remove this line, as it's causing the problem!
}
delete []vector_1;
Also, you have exactly the same problem in the loop that deals with the vector_2 pointer - and the same 'fix' will work there, too.
Note: If you don't want to use the [i] index operator, but rather use pointer 'arithmetic', then you can change:
new_vector_1[i] = vector_1[i];
to:
new_vector_1[i] = *(vector_1 + i);
This way, you are adding the value of i to the pointer without changing that pointer.

Program is meant to count how many duplicates are in an array. However, it returns the wrong frequency values

Normally I would use other methods to fix this program but I am not allowed to use advanced techniques for this project, and so what I have is more or less as far as I'm allowed to go.
So my program is meant to take in an array with 10 numbers and then output how many of each value is in the array. For example, {1, 1, 1, 1, 1, 2, 2, 2, 2, 2} is meant to return
5 1
5 2
However, it returns
6 1
4 2
I've made sure that the finalData and Data arrays are holding the proper values.
cout << count(data, data + MAX_VALUE, finalData[i+1]) << " " << data[i] << "\n";
seems to be outputting the wrong value.
for some reason. I believe the error is in my last function, getResults, more specifically the last for loop. Here is that function.
void getResults(int finalData[], int data[])
{
int temp[MAX_VALUE];
int j = 0;
for (int i = 0; i < MAX_VALUE - 1; i++)
if (finalData[i] != finalData[i + 1])
temp[j++] = finalData[i];
temp[j++] = finalData[MAX_VALUE - 1];
for (int i = 0; i < j; i++)
{
finalData[i] = temp[i];
}
for (int i = 0; i < j; i++)
{
cout << count(data, data + MAX_VALUE, finalData[i+1]) << " " << data[i] << "\n";
}
}
This is my complete code.
#include<iostream>
#include<iomanip>
#include<string>
#include<cmath>
#include <algorithm>
using namespace std;
void printHeader();
int getData(string);
void getResults(int finalData[], int data[]);
const int MAX_VALUE = 10;
int main(void)
{
int countValue = 0;
int freq = 0;
printHeader();
int data[MAX_VALUE] = {};
int frequency[MAX_VALUE] = {};
for (int i = 0; i < MAX_VALUE; i++)
{
cout << "Please enter data position " << i + 1 << "\n";
data[i] = getData("\nPlease enter a valid integer.\n");
}
sort(data, data + MAX_VALUE);
int values[MAX_VALUE] = {};
int secondData[MAX_VALUE] = {};
for (int i = 0; i < MAX_VALUE; i++)
{
secondData[i] = data[i];
}
getResults(data, secondData);
return 0;
}
void printHeader()
{
}
int getData(string error)
{
int userInput = 0;
do
{
cin >> userInput;
if (cin.fail())
{
cout << error;
}
} while (cin.fail());
return userInput;
}
void getResults(int finalData[], int data[])
{
int temp[MAX_VALUE];
int j = 0;
for (int i = 0; i < MAX_VALUE - 1; i++)
if (finalData[i] != finalData[i + 1])
temp[j++] = finalData[i];
temp[j++] = finalData[MAX_VALUE - 1];
for (int i = 0; i < j; i++)
{
finalData[i] = temp[i];
}
for (int i = 0; i < j; i++)
{
cout << count(data, data + MAX_VALUE, finalData[i+1]) << " " << data[i] << "\n";
}
}
Got the right answer. Made the changes I listed at the top as well as the following change to the count function.
cout << count(data, data + MAX_VALUE, finalData[i]) << " " << finalData[i] << "\n";
You have done a simple error. When you call getResults you pass the same array(pointer) to 2 different parameters. Now when you update finalData the unwanted side effect update also data(they are the same pointer(with different name). So when you call count will not return the expected result.
To solve this problem you can do a copy of the input array and give it as second parameter of getResults(...) function.

Search a sequence in a string. DNA

I need to do a program that separate from 3 to the size of a string and compare to the others sequences of 3 in the same string given. I'm going to explain it.
User introduce this DNA string = "ACTGCGACGGTACGCTTCGACGTAG" For example.
We start with n = 3, this is, we take the first three caracters for comparing in the DNA.
The first characters are: "ACT", and we need to compare it with the other sequences of three, like, [CTG,TGC,GCA... until the end].
If we find another sequence equal to "ACT", we save the position.
Here is another example:
DNA: "ACTGCGACGGTACGCTTCGACGTAG" and we find this sequences in his positions:
ACG: 7 - 12 - 20
CGA: 5 - 18
GAC: 6 - 19
GTA: 10 - 22
CGAC: 5 - 18
GACG: 6 - 19
CGACG: 5 - 18
The number is the position of the start of the sequence:
ACTGCGACGGTACGCTTCGACGTAG
You can see that the n = 3, increment in 1 when the we end to find by n = 3, the variable pass to n=4, until n = DNA.size().
My problem is that i have one function for divide the string in a little sequences of the DNA, and I do a push_back() for saving in the vector, and then I can see if there is more sequences or not, but i don't know how can i get the position.
I can use the library algorithm, and for sure, in this library there is a function that do this but i don't know so much this library.
Here is my code:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
const string DNA = "ACTGCGACGGTACGCTTCGACGTAG";
const size_t taille = DNA.size();
size_t m = 3;
vector<string> v;
/*
struct DNA{
const string dna; // chaine saisie pour l'utilisateur
size_t taille; // Taille de la chaine
string chaine; // Chaine à chercher
};
*/
// what kind of structs can i create? for me it's stupid to make any struct in this program.
bool checkDNA(string &s);
string takeStrings(const string &s,size_t i, size_t m);
void FindSequenceDNA(vector<string>&s,string sq);
size_t incrementValue(size_t &m);
int main(){
string DNAuser;
cout << "Introduce the DNA: ";
cin >> DNAuser;
bool request;
cout << boolalpha;
request = DNAuser.find_first_not_of("AGCT");
cout << request << endl;
vector<string> vectorSq;
size_t auxiliar = 0;
string r;
size_t ocurrencies = DNA.size()-2;
cout << "DNA: " << DNA << endl;
while(auxiliar<ocurrencies){ // This gonna be works with the ocurriences, from 1 to end.
r = takeStrings(DNA,auxiliar,auxiliar+m);
auxiliar++;
if(r.size()==m){
vectorSq.push_back(r);
}
}
// string res = takeStrings(DNA,0,3);
// cout << "res: " << res << endl;
// cout << "Printing vector: " << endl;
// I just need to find the other, the practice is almost done.
for(size_t i = 0; i< vectorSq.size(); i++){
cout << vectorSq[i] << endl;
}
return 0;
}
string takeStrings(const string &s,size_t i, size_t m){
string result;
size_t aux=i;
if(s.size()==0){
cout << "String is empty." << endl;
}
else{
for(;i<s.size()&&i!=m;i++){
result+=s[i];
aux++;
}
}
return result;
}
void FindSequenceDNA(vector<string>&s,string sq){
if(s.size()==0){
cout << "DNA invalid." << endl;
}
else{
for(size_t i=0;i<s.size();i++){
if(sq==s[i]){
cout << "function: " << endl;
cout << s[i] << endl; // I need to calculate the real position in the string, not in the vector
}
}
}
}
bool checkDNA(string &s){
bool res;
if(s.size()==0 || s.size()<3){
cout << "DNA invalid" << endl;
}
else{
for(size_t i=0;i<s.size();i++){
if(s[i]=='A' || s[i]=='C' || s[i]=='G' || s[i]=='T')
{
res = true;
}
else{
res= false;
}
}
}
return res;
}
size_t incrementValue(size_t &m){
if(m<DNA.size()){
m++;
}
return m;
}
Based on Mohit's answer but re-uses pointers to possibly, get better performance (vs string.substr)
#include <iostream>
#include <cstring>
#include <vector>
#include <string>
using namespace std;
static const char* DNAdata = "ACTGCGACGGTACGCTTCGACGTAG";
static const size_t len = strlen(DNAdata);
vector< vector< string > > uniqueKeys(len);
vector< vector< vector<size_t> > > locations(len);
void saveInfo(const char* str, size_t n, size_t loc) {
vector<string>& keys = uniqueKeys[n-1];
vector<vector<size_t> >& locs = locations[n-1];
bool found = false;
for (size_t i=0; i<keys.size(); ++i) {
if (keys[i] == str) {
locs[i].push_back(loc);
found = true;
break;
}
}
if (!found) {
vector<size_t> newcont;
newcont.push_back(loc);
keys.push_back(str);
locs.push_back(newcont);
}
}
void printInfo(const char* str) {
cout << str << endl;
size_t len = strlen(str);
vector<string>& keys = uniqueKeys[len-1];
vector<vector<size_t> >& locs = locations[len-1];
for (size_t i=0; i<keys.size(); ++i) {
if (keys[i] == str) {
vector<size_t>& l = locs[i];
vector<size_t>::iterator iter = l.begin();
for (; iter != l.end(); ++iter) {
cout << *iter << endl;
}
break;
}
}
}
int main() {
char* DNA = new char[len+1];
strcpy(DNA, DNAdata);
char* end = DNA+len;
char* start = DNA;
for (size_t n =3; n<=len; ++n) {
size_t loc = 0;
char* p = start;
char* e = p+n;
while (e <= end) {
char save = *e;
*e = 0;
saveInfo(p++, n, loc++);
*e = save;
++e;
}
}
delete[] DNA;
printInfo("GTA");
printInfo("ACTGCGACGGTACGCTTCGACGTA");
return 0;
}
To print all:
void printAll() {
for (size_t n=3; n<=len; ++n) {
cout << "--> " << n << " <--" << endl;
vector<string>& keys = uniqueKeys[n-1];
vector<vector<size_t> >& locs = locations[n-1];
for (size_t i=0; i<keys.size(); ++i) {
cout << keys[i] << endl;
vector<size_t>& l = locs[i];
vector<size_t>::iterator iter = l.begin();
for (; iter != l.end(); ++iter) {
cout << *iter << endl;
}
}
}
}
How about:
std::map< std::string, std::vectpr<int> > msvi;
std::size_t len = dna.size();
for(size_t from = 0; from < len; ++from) {
for(size_t sz = 3; sz < len; ++sz) {
msvi[ dna.substr(from, sz ].push_back(from);
}
}
This creates all strings of size 3 and saves there position in a map.
Live demo link
Print only the items with 2 or more instances
As you don't want to use std::map, you can construct a trie as shown on this page written in C. Change your tree node to:
struct tree_node {
vector<int> starts;
struct tree_node *children[26]; /* A to Z */
};

Debugging a merge sort

void CensusData::mergeSort(int type) {
if(type == 0)
MERGE_SORT(type, 0, data.size());
}
void CensusData::MERGE_SORT(int type, int p, int r){
//int q;
//cout << "data size " << data.size() << endl;
std::cout << "MERGE_SORT START ///("<< p << ", " << r << ")" <<std::endl;
if(p < r)
{
int q = (p + r)/2;
MERGE_SORT(type, p, q);
MERGE_SORT(type, q + 1, r);
MERGE(type, p, q ,r);
}
}
void CensusData::MERGE(int type, int p, int q, int r){
if(type == 0)
{
std::cout << "MERGING" << std::endl;
//int n1;
//int n2;
int n1 = q - p + 1;
int n2 = r - q;
int L[n1 + 1];
int R[n2 + 1];
for(int i = 1; i < n1; i++)
{
cout << "filling Left Array" << endl;
L[i] = data[p + i - 1]->population;
}
for(int j = 1; j < n2; j++)
{
cout << "filling Right Array" << endl;
R[j] = data[q + j]->population;
}
int i = 1;
int j = 1;
for(int k = p; p < r; p++)
{
cout << "for loop: " << endl;
if(L[i] <= R[j])
{
cout << "TRUE" << endl;
data[k]->population = L[j];
i = i + 1;
}
/*else if(data[k]->population == R[j])
{
cout << "FALSE" << endl;
j = j + 1;
}*/
else
{
data[k]->population = R[j];
j = j + 1;
}
}
}
}
do not worry about type, it wont effect this program at all. basically i am trying to make a merge sort that will take a vector containing an integer, the vector looks like this:
class Record { // declaration of a Record
public:
std::string* city;
std::string* state;
int population;
Record(std::string&, std::string&, int);
~Record();
};
std::vector<Record*> data;
basically i have been trying to get it to actually sort, but it doesn't seem to work at all, i have even seen garbage in the program.
example input:
237 812826 68642
output:
4484540 812826 68642
Note: all of the rest of the program works fine (tested it with an insertion sort) only this part is not working.
Take a look at lecture 15 of the excellent Stanford Universities course Programming Abstractions. It covers all kinds of sorts including merge:
http://see.stanford.edu/see/lecturelist.aspx?coll=11f4f422-5670-4b4c-889c-008262e09e4e
You can even get the source code from SourceForge:
http://sourceforge.net/projects/progabstrlib/files/

Merge sort code debugging

I am trying to write a code for merge sort. I am not getting the correct output. I am following this pseudocode link Following is my code. I pass my unsorted array into merge_sort function and call merge function recursively to sort and combine the sub arrays.I know there are more simpler and efficient ways to write code for merge sort but I want to try on my own otherwise I won't learn. Thanks in advance.
int* merge_sort(int* a,int size)
{
//cout<<size;
//cout<<"hi";
if(size == 1)
{
//cout<<"less";
//cout<<a[0];
return a;
}
int* left;
int* right;
int middle = ceil(size/2);
left = new int(middle);
right = new int(middle);
for(int i=0;i<middle;i++)
{
left[i]=a[i];
//cout<<left[i];
}
cout<<"\t";
for(int j=middle;j<size;j++)
{
right[j]=a[j];
//cout<<right[j];
}
cout<<"\t";
left = merge_sort(left,middle);
//if(size==2)
//cout<<left[0];
right = merge_sort(right,middle);
//if(size==2)
//cout<<right[0];
return merge(left,right,middle);
}
int* merge(int* l,int* r,int m)
{
int* result;
result = new int(2*m); //to store the output
int lsize=m; // to keep track of left sub list
int rsize=m; // to keep track of right sub list
int counter = 0; // will use to index result
//cout<<m;
while(lsize>0 || rsize>0)
{
if(lsize>0 && rsize>0)
{
if(l[0]<=r[0])
{
result[counter]=l[0];
counter++; //to store next value in result
lsize--;
l=&l[1]; //decrementing the size of left array
}
else
{
result[counter]=r[0];
counter++;
rsize--;
r=&r[1]; //dec. size of right array
}
}
else if(lsize>0)
{
result[counter]=l[0];
counter++;
lsize--;
l=&l[1];
}
else if(rsize>0)
{
result[counter]=l[0];
counter++;
lsize--;
l=&l[1];
}
}
return result;
}
Your code:
int *left = new int(middle);
allocates a single integer initialized to middle. You need:
int *left = new int [middle];
which allocates an array of middle integers. Rinse and repeat for int *right. Actually, you need to use:
int *right = new int [size - middle];
This gets the correct size for the right array. You then have to modify the recursive call to merge_sort() for the right sub-array:
merge_sort(right, size - middle);
Finally, you have to rewrite merge() to take the size of the left array and the size of the right array independently, because they may be of different sizes. For example, if you sort 10 elements,
you then end up with a call to merge two arrays of 5 (which is fine), but at the next level you need to merge an array of 2 and an array of 3 elements (and you're hosed).
The allocation of result also has the () vs [] allocation problem. And there are some other as yet unresolved problems. But these are important steps in the right direction.
As mentioned in a comment to the question, you have a monumental memory leakage problem, too. What's more, it is not trivial to fix because merge_sort() does an early exit without allocating new memory, so it isn't as simple as 'delete the memory returned by merge_sort()'.
Copy and paste is wonderful until you forget to edit the pasted copy correctly:
else if (lsize > 0)
{
result[counter] = l[0];
counter++;
lsize--;
l = &l[1];
}
else if (rsize > 0)
{
result[counter] = l[0];
counter++;
lsize--;
l = &l[1];
}
Methinks you should be using r and rsize in the second of these blocks.
This still isn't the whole story...
And the residual problem (apart from memory management, which is still 100% leaky and problematic) is:
for(int j=middle;j<size;j++)
{
right[j]=a[j];
//cout<<right[j];
}
You're copying into parts of right that you've not allocated. You need something more like:
for(int j = 0; j < size - middle; j++)
{
right[j] = a[j + middle];
//cout<<right[j];
}
This code works as long as you always sort at least two items at the top level (you crash freeing unallocated space if you sort 1 item — that's part of the memory management problem).
#include <iostream>
using namespace std;
namespace {
int *merge(int *l, int m, int *r, int n);
void dump_array(int *a, int size)
{
int i;
cout << size << ": ";
for (i = 0; i < size; i++)
{
cout << ' ' << a[i];
if (i % 10 == 9)
cout << '\n';
}
if (i % 10 != 0)
cout << '\n';
}
};
int *merge_sort(int *a, int size)
{
cout << "-->> merge_sort:\n";
dump_array(a, size);
if (size <= 1)
{
cout << "<<-- merge_sort: early return\n";
return a;
}
int middle = size/2;
int *left = new int[middle];
int *right = new int[size - middle];
cout << middle << ": ";
for (int i = 0; i < middle; i++)
{
left[i] = a[i];
cout << ' ' << left[i];
}
cout << "\n";
cout << (size - middle) << ": ";
for (int j = 0; j < size - middle; j++)
{
right[j] = a[j + middle];
cout << ' ' << right[j];
}
cout << "\n";
cout << "MSL:\n";
int *nleft = merge_sort(left, middle);
cout << "NL: ";
dump_array(nleft, middle);
cout << "OL: ";
dump_array(left, middle);
cout << "OR: ";
dump_array(right, size - middle);
cout << "MSR:\n";
int *nright = merge_sort(right, size - middle);
cout << "NR: ";
dump_array(nright, size - middle);
cout << "NL: ";
dump_array(nleft, middle);
cout << "OL: ";
dump_array(left, middle);
cout << "OR: ";
dump_array(right, size - middle);
int *result = merge(nleft, middle, nright, size - middle);
cout << "<<-- merge_sort:\n";
dump_array(result, size);
return result;
}
namespace {
int *merge(int *l, int m, int *r, int n)
{
int *result = new int[m + n];
int lsize = m;
int rsize = n;
int counter = 0;
cout << "-->> merge: (" << m << "," << n << ")\n";
dump_array(l, m);
dump_array(r, n);
while (lsize > 0 || rsize > 0)
{
if (lsize > 0 && rsize > 0)
{
if (l[0] <= r[0])
{
result[counter] = l[0];
cout << "C: " << counter << "; L = " << l[0] << "; LS = " << lsize << '\n';
counter++;
lsize--;
l++;
}
else
{
result[counter] = r[0];
cout << "C: " << counter << "; R = " << r[0] << "; RS = " << rsize << '\n';
counter++;
rsize--;
r++;
}
}
else if (lsize > 0)
{
result[counter] = l[0];
cout << "C: " << counter << "; L = " << l[0] << "; LS = " << lsize << '\n';
counter++;
lsize--;
l++;
}
else if (rsize > 0)
{
result[counter] = r[0];
cout << "C: " << counter << "; R = " << r[0] << "; RS = " << rsize << '\n';
counter++;
rsize--;
r++;
}
}
cout << "<<-- merge:\n";
dump_array(result, m+n);
return result;
}
};
int main()
{
for (int i = 2; i <= 10; i++)
{
int array1[] = { 9, 3, 5, 7, 1, 8, 0, 6, 2, 4 };
cout << "\nMerge array of size " << i << "\n\n";
int *result = merge_sort(array1, i);
delete[] result;
}
return 0;
}
This is the debug-laden code. It's the level to which I went to get the result. I could perhaps have used a debugger. Were I on a machine where valgrind works, it might have helped too (but it does not work on Mac OS X 10.8.x, sadly).
There are still many, many ways to improve the code — including the memory management. You'd probably find it easiest to pass the input array to merge() for use as the result array (avoiding the memory allocation in that code). This would reduce the memory management burden.
When you remove the debug code, you'll need to call the dump_array() function in the main() program to get the before and after sorting array images.
Code converted to template functions and leak-free
I've simplified the code a fair bit, especially in the merge() function. Also, more as a matter of curiosity than anything else, converted it to a set of template functions, and then used them with 4 different array types (int, double, std::string, char). The amount of debugging has been dramatically reduced, and the main debugging is conditional on being compiled with -DTRACE_ENABLED now.
The code is now leak-free; valgrind on a Linux box (virtual machine) gives it a clean bill of health when there are no exceptions. It is not guaranteed exception-safe, though. In fact, given the naked uses of new and delete, it is pretty much guaranteed not to be exception-safe. I've left the namespace control in place, but I'm far from convinced it is really correct — indeed, I'd lay odds on it not being good. (I'm also curious if anyone has any views on how to layout code within a namespace { … }; block; it seems odd not indenting everything inside a set of braces, but …)
#include <iostream>
using namespace std;
namespace {
#if !defined(TRACE_ENABLED)
#define TRACE_ENABLED 0
#endif
enum { ENABLE_TRACE = TRACE_ENABLED };
template <typename T>
void merge(T *l, int m, T *r, int n, T *result);
template <typename T>
void dump_array(const char *tag, T *a, int size)
{
int i;
cout << tag << ": (" << size << ") ";
for (i = 0; i < size; i++)
{
cout << " " << a[i];
if (i % 10 == 9)
cout << '\n';
}
if (i % 10 != 0)
cout << '\n';
}
};
template <typename T>
void merge_sort(T *a, int size)
{
if (size <= 1)
return;
if (ENABLE_TRACE)
dump_array("-->> merge_sort", a, size);
int middle = size/2;
T *left = new T[middle];
T *right = new T[size - middle];
for (int i = 0; i < middle; i++)
left[i] = a[i];
for (int j = 0; j < size - middle; j++)
right[j] = a[j + middle];
merge_sort(left, middle);
merge_sort(right, size - middle);
merge(left, middle, right, size - middle, a);
delete [] left;
delete [] right;
if (ENABLE_TRACE)
dump_array("<<-- merge_sort", a, size);
}
namespace {
template <typename T>
void merge(T *l, int m, T *r, int n, T *result)
{
T *l_end = l + m;
T *r_end = r + n;
T *out = result;
if (ENABLE_TRACE)
{
cout << "-->> merge: (" << m << "," << n << ")\n";
dump_array("L", l, m);
dump_array("R", r, n);
}
while (l < l_end && r < r_end)
{
if (*l <= *r)
*out++ = *l++;
else
*out++ = *r++;
}
while (l < l_end)
*out++ = *l++;
while (r < r_end)
*out++ = *r++;
if (ENABLE_TRACE)
dump_array("<<-- merge", result, m+n);
}
};
#include <string>
int main()
{
for (size_t i = 1; i <= 10; i++)
{
int array1[] = { 9, 3, 5, 7, 1, 8, 0, 6, 2, 4 };
if (i <= sizeof(array1)/sizeof(array1[0]))
{
cout << "\nMerge array of type int of size " << i << "\n\n";
dump_array("Original", array1, i);
merge_sort(array1, i);
dump_array("PostSort", array1, i);
}
}
for (size_t i = 1; i <= 10; i++)
{
double array2[] = { 9.9, 3.1, 5.2, 7.3, 1.4, 8.5, 0.6, 6.7, 2.8, 4.9 };
if (i <= sizeof(array2)/sizeof(array2[0]))
{
cout << "\nMerge array of type double of size " << i << "\n\n";
dump_array("Original", array2, i);
merge_sort(array2, i);
dump_array("PostSort", array2, i);
}
}
for (size_t i = 1; i <= 10; i++)
{
std::string array3[] = { "nine", "three", "five", "seven", "one", "eight", "zero", "six", "two", "four" };
if (i <= sizeof(array3)/sizeof(array3[0]))
{
cout << "\nMerge array type std::string of size " << i << "\n\n";
dump_array("Original", array3, i);
merge_sort(array3, i);
dump_array("PostSort", array3, i);
}
}
for (size_t i = 1; i <= 10; i++)
{
char array4[] = "jdfhbiagce";
if (i <= sizeof(array4)/sizeof(array4[0]))
{
cout << "\nMerge array type char of size " << i << "\n\n";
dump_array("Original", array4, i);
merge_sort(array4, i);
dump_array("PostSort", array4, i);
}
}
return 0;
}