I am trying to merge two sorted arrays using pointers. The third loop is working food upto first arr[5] but then show garbage values afterwards. is the sorting techniqure wrong or am I using pointers incorrectly?
#include<iostream>
using namespace std;
int main() {
int arr1[] = { 1,3,4,6 };
int arr2[] = { 2,3,4,5 };
int n1 = 4;
int n2 = 4;
int arr3[10];
int* endptr = &arr1[0];
int* endptr2 = &arr2[0];
int* endptr3 = arr3;
int k = 0;
while (endptr < &arr1[n1-1] &&endptr2 < &arr2[n2-1]) {
if (endptr[0] < endptr2[0]) {
endptr3[k++] = endptr[0];
endptr++;
}
else {
endptr3[k++] = endptr2[0];
endptr2++;
}
}
while (endptr < &arr1[n1 - 1]) {
endptr3[k++] = endptr[0];
endptr++;
}
while (endptr2 < &arr2[n2 - 1]) {
endptr3[k++] = endptr[0];
endptr2++;
}
cout << arr3[5];
}
I got the results up to first 6 elements and then get garbage values.
The way you are using the pointers is negatively affecting your thought process.
Let’s abstract it to a function to help make it cleaner:
void merge(
int * first1, int * last1, // elements of array1
int * first2, int * last2, // elements of array2
int * dest ) // where to put sorted data
This is the “iterator” idiom used by C++ algorithms. first points to the first element. last points to one-past the last element. (And we assume that dest points to enough space to contain the results.) So:
int array1[] = { 1,3,4,6 };
int array2[] = { 2,3,4,5,7 };
int array3[9]; // enough room for array1+array2
merge(
array1, array1+4, // first array has 4 elements
array2, array2+5, // second array has 5 elements
array3 ); // destination array has 4+5=9 elements
C++ actually gives us a couple of functions to get the first and last pointers to whatever underlying sequence container you’ve got:
merge(
std::begin(array1), std::end(array1),
std::begin(array2), std::end(array2),
std::begin(array3) );
Now we can reconsider our merge algorithm.
void merge(...)
{
// while both array1 and array2 have elements:
while ((first1 != last1) and (first2 != last2))
{
if (*first2 < *first1)
*dest++ = *first2++;
else
*dest++ = *first1++;
}
// if array1 has any leftover elements:
while (first1 != last1)
*dest++ = *first1++;
// if array2 has any leftover elements:
while (first2 != last2)
*dest++ = *first2++;
}
In particular, notice:
We can easily check whether an array has elements by comparing the first and last pointers directly. When first == last, there are no elements, since last is one-past the end of the source array.
Comparison is simple enough. We could have written that as if (first2[0] < first1[0]) but that is less idiomatic than just using the * operator.
Copying a value is as simple as a dereference and increment on both sides of the assignment.
The three loops of the merge all work on a simple “are there elements left?” check.
Note also how we kept the test condition to a strict less-than comparison. That has ramifications for generic programming (for example, merge sorting in non-increasing order), but I’ll leave it at that for today...
Related
I'm working on a program that modifies the data of an array using only pointers. I'm trying to return the index where array[ix]==0. However, I keep getting stuck in an infinite loop. What am I doing wrong?
int firstprime(int size, int arr[]){
int* end = arr + size;
int* begin = arr;
while(begin<end){
if(*begin==0)
return *begin;
begin++;
}
return -1;
}
You can use std::distance quite easily to get the index.
More info on std::distance here
Btw, the function name is also very misleading. If the function is meant to return the index of a value in the array, then consider changing that function name, like getIndex() or find(). Just pick something more meaningful.
#include <iostream>
int firstprime(int size, int *arr)
{
int *begin = arr;
int *end = begin + size;
while( begin < end )
{
if(*begin==0)
return std::distance(arr, begin);
begin++;
}
return -1;
}
int main()
{
int array[10] = {1,2,3,4,0,6,7,8,9,10};
int p = firstprime(10, array);
std::cout<< "0 found at index: " << p <<std::endl;
}
The result is:
0 found at index: 4
Online example: https://rextester.com/KVCL75042
To get the "distance" between two pointers (in the number of elements) you can either use std::distance:
return std::distance(arr, begin); // Return the distance between current element and the beginning of the array
You can also subtract the pointers:
return begin - arr; // Return the distance between the current element and the beginning of the array
The "distance" returned by the above two statements will be in the number of elements, and since you take the distance from the first element it will be the index of the "current" element.
Question
I do not want to pass the size of the array as an index parameter.
For my merge_sort, I want to optimize my parameters using the iterator range concept. I can't seem to figure out how to deference the iterator range and access my array. I can deference to access the indices like low and high in recursive_merge_sort, but there does not seem to be an intuitive way to access the array itself. I've been using this great guide on C++ Pointers and Arrays as a starting point.
My Merge Sort C++11 C++17 question brought this concept to light and I like the idea of using iterator ranges to reduce the number of parameters for my sort.
Code
void recursive_merge_sort(int* low, int* high) {
// deference to get starting index "low" and ending index "high"
if(*(low) >= *(high) - 1) { return; }
int mid = *(low) + (*(high) - *(low))/2;
// what's the correct syntax to access my array from the iterator range
// int* d = some how deference low or how to get the data array they iterate on
recursive_merge_sort_v(d + low, d + mid);
recursive_merge_sort_v(d + mid, d + high);
merge(d + low, mid, d + high);
// delete d;
}
void merge_sort(int* data) {
// what's the correct syntax to access my array from the passed in iterator range
// is this event possible? incorrect syntax below
recursive_merge_sort(data + 0, data + std::size(*(data)));
}
int main()
{
int data[] = { 5, 1, 4, 3, 65, 6, 128, 9, 0 };
int num_elements = std::size(data);
std::cout << "unsorted\n";
for(int i=0; i < num_elements; ++i) {
std::cout << data[i] << " ";
}
merge_sort(data);
std::cout << "\nsorted\n";
for(int i=0; i < num_elements; ++i) {
std::cout << data[i] << " ";
}
}
Comment section Solution from the bayou
Remy Lebeau: "When you pass an array by pointer, you lose all information about it. You can't get back to the original array given only a pointer/iterator, as dereferencing will only give you a single element of the array, not the array itself. When passing an array by pointer, you have no choice but to pass the array size as another parameter. Otherwise, pass the array by reference instead, and if you need to support arrays of different sizes then use a template so the compiler can deduce the array size for the reference."
Iterators are modeled to act like pointers. They have the same type of overloaded operators: dereferencing and increment at the very least (some also have decrement, random access, etc.).
The most advanced iterator interface is random access, which functions exactly like a raw pointer (by design).
So all (raw) pointers are basically random access iterators into a C-style (contiguous) array. Look at the following to visualize begin/end iterators for a C-style array:
int vals[] = { 0, 1, 2, 3, 4 };
int *begin = vals;
int *end = vals + 5;
v vals[]
0 1 2 3 4 ...
^ begin ^ end (1 past the end of array)
vals[2] == begin[2]
vals[4] == begin[4]
etc.
So basically, you just treat the begin iterator as the front of the array, and you just don't dereference anywhere before the begin iterator, nor at or past the end iterator, as standard C++ convention dictates the end iterator is 1 past the end of the range.
Here's an example of using pointers like iterators:
void print(int *begin, int *end)
{
// for each element in the range (starting at begin, up to but not including end)
for (; begin != end; ++begin)
{
// print the element
std::cout << *begin << '\n';
}
}
int main()
{
// declare a C-style array
int arr[] = { 10, 5, 2, 6, 20 };
// for the sake of example, print only the middle 3 elements
// begin = arr + 1
// end = arr + 4
print(arr + 1, arr + 4);
return 0;
}
I have an object containing some data such as:
class Employee{
private:
int employee_number;
// +more objects and data
public:
int get_number() {
return employee_number;
}
};
The objects are stored in a pointer array:
Employee* employees[MAX + 1];
The first element in Employee is not used, so the algorithm skips employees[0]
The sorting algorithm is called each time a new employee has been added, here is what the sorting algorithm looks like:
int to = employees.length - 1;
for (int from = 1; from < to; from++) {
if (employees[from]->get_number() > employees[from + 1]->get_number()) {
Employee *tmp = employees[from + 1];
int i = from;
while (i >= 1 && employees[i]->get_number() > tmp->get_number()) {
employees[i + 1] = employees[i];
i--;
}
employees[i + 1] = tmp;
}
}
I'm not sure why this doesn't sort the employees array, as this algorithm works well with regular int arrays. Also keep in mind my entire code is written in my own language, so I had to translate into English here.
Assuming that you want to sort the Employee pointers in ascending order by the data member employee_number (i.e., employee_number is the key) of the objects they are pointing to, you could define the following predicate using a lambda expression:
auto cmp = [](auto a, auto b) {
return a->get_number() < b->get_number();
};
Then, use the std::sort() algorithm with the predicate above:
auto begin = &employees[1]; // skip 1st element
std::sort(begin, employees + num, cmp);
where num above is 1 (since you said that the 1st entry is not used) plus the number of Employee pointers inserted so far.
I'm not really sure what you want to achieve, but if you have the intention of calling std::sort() on the array every time a new Employee is added to the array, you might want to consider using another container like std::set instead of an array.
I'm trying out "code golf" type problems to prepare for interviews. At the moment I'm trying to do the one where you move the odd elements of an array to the back (without necessarily preserving the order). I've looked over my logic many times and can't think of any case that could cause an infinite loop. However, I'm getting a Timeout when I try to run it. I've commented out my thought process for you to see.
#include <iostream>
void int_swap (int *pi1, int *pi2)
{
int temp = *pi1;
*pi1 = *pi2;
*pi2 = temp;
}
void odds_to_back (int *arr, size_t n)
{
int * end = arr + n; // get pointer to 1 off the end of the array
if (arr == end) return; // handle case of empty array
--end; // move pointer to last element of the array
while (arr != end)
{
if (*arr % 2) // if first pointer is odd
{
if (!(*end % 2)) // if second pointer is even
{
int_swap(arr, end); // swap first and second
++arr; // increment first
}
else // second pointer is odd
{
while ((*end % 2) && arr != end) --end; // move second pointer towards first until second pointer is even or hits the first
}
}
else // if first is even
{
++arr; // increment first
}
}
}
int main ( )
{
int myArray [] = {1, 3, 5, 6, 19, 1, 2, 2};
size_t N = sizeof(myArray)/sizeof(int);
odds_to_back(myArray, N);
for (size_t i = 0; i < N; ++i) std::cout << myArray[i] << " ";
return 0;
}
Oh, that is a hard one. You are calling swap (arr, end) and not your own int_swap. So, at least with my test code the function std::swap which is changing the pointers (and not the values pointed to) is called.
Changing the call to your int_swap looks promising.
I made a simple routine to sort an array witch accepts as a parameter an array of ints the problem is that when i compare the values array[i] shows the correct value in the debugger but array[i + 1] shows a bogus value ... i guess is a pointer issue but i can't figure it out what i am doing wrong.
Here is the code :
typedef int vector[10];
void task1(vector * param)
{
bool ordered = false;
while (!(ordered))
{
int tmp = 0;
ordered = true;
for (int i = 0; i < 9 ; i++)
{
if (*param[i] > *param[i+1])
{
tmp = *param[i];
*param[i] = *param[i + 1];
*param[i + 1] = tmp;
ordered = false;
}
}
}
}
int _tmain(int argc, _TCHAR* argv[])
{
vector tavi = {10,88,77,192,7,27,82,1,882,13};
task1(&tavi);
for (int i = 0 ; i < 10 ; i ++)
printf("%d ",tavi[i]);
_getch();
return 0;
}
The subscript-operator ([]) has a higher precedence than the derefence-operator (*), so *param[i] is actually *(param[i]). This means, you first go to the i-th element of param, and then dereference it - that is not what you want (param is not a pointer into an array). You want to dereference param and then go to the i-th element - this would be (*param)[i].
First of all: Why would you write the sorting yourself (not to mention that bubblesort is not exactly fast).
So why not simply use
std::sort(tavi, tavi + 10, std::less<int>());
Of course if you have C++11 or boost its also a good idea to forget about c style arrays and use std::array or boost::array instead:
std::array<int, 10> tavi = {10,88,77,192,7,27,82,1,882,13};
std::sort(tavi.begin(), tavi.end(), std::less<int>());
for (int i = 0 ; i < tavi.size(); i ++)
std::cout<<tavi[i]<<" ";
If however you really want to do it like that, *param[i] is the same as *(param[i]), while you want to use (*param)[i].
vector is type int[10]. Therefore, vector* is type int(*)[10]. That is, a pointer to an array of 10 ints. So the distance between param[i] and param[i+1] is sizeof(int) * 10
When you do this:
if (*param[i] > *param[i+1])
You are comparing one array of 10 ints to the next array of 10 ints. I wish this would simply not compile, unfortunately, what happens is that the arrays are implicitly converted to pointers to their first element. Since i < i+1, the above comparison will never be true.