Sorting two arrays into a combined array - c++

I haven't done any programming classes for a few years, so please forgive any beginner mistakes/methods of doing something. I'd love suggestions for the future. With the code below, I'm trying to check the values of two arrays (sorted already) and put them into a combined array. My solution, however inefficient/sloppy, is to use a for loop to compare the contents of each array's index at j, then assign the lower value to index i of the combinedArray and the higher value to index i+1. I increment i by 2 to avoid overwriting the previous loop's indexes.
int sortedArray1 [5] = {11, 33, 55, 77, 99};
int sortedArray2 [5] = {22, 44, 66, 88, 00};
combinedSize = 10;
int *combinedArray;
combinedArray = new int[combinedSize];
for(int i = 0; i <= combinedSize; i+=2)
{
for(int j = 0; j <= 5; j++)
{
if(sortedArray1[j] < sortedArray2[j])
{
combinedArray[i] = sortedArray1[j];
combinedArray[i+1] = sortedArray2[j];
}
else if(sortedArray1[j] > sortedArray2[j])
{
combinedArray[i] = sortedArray2[j];
combinedArray[i+1] = sortedArray1[j];
}
else if(sortedArray1[j] = sortedArray2[j])
{
combinedArray[i] = sortedArray1[j];
combinedArray[i+1] = sortedArray2[j];
}
}
}
for(int i = 0; i < combinedSize; i++)
{
cout << combinedArray[i];
cout << " ";
}
And my result is this
Sorted Array 1 contents: 11 33 55 77 99
Sorted Array 2 contents: 0 22 44 66 88
5 77 5 77 5 77 5 77 5 77 Press any key to continue . . .
In my inexperienced mind, the implementation of the sorting looks good, so I'm not sure why I'm getting this bad output. Advice would be fantastic.

what about this:
int i=0,j=0,k=0;
while(i<5 && j<5)
{
if(sortedArray1[i] < sortedArray2[j])
{
combinedArray[k]=sortedArray1[i];
i++;
}
else
{
combinedArray[k]=sortedArray2[j];
j++;
}
k++;
}
while(i<5)
{
combinedArray[k]=sortedArray1[i];
i++;k++;
}
while(j<5)
{
combinedArray[k]=sortedArray2[j];
j++; k++;
}

Firstly, there are some immediate problems with how you use C++:
You use = instead of == for equality check (hence causing undesired value assignments and the if-condition to return true when it shouldn't);
Your outer loops upper boundary is defined as i <= 10, while the correct boundary check would be i < 10;
You have a memory leak at the end of the function because you fail to de-allocate memory. You need a delete [] combinedArray at the end.
Secondly, your outer loop iterates through all values of the destination array, and in each step uses an inner loop to iterate through all values of the source arrays. That is not what you want. What you want is one loop counting from j=0 to j<5 and iterating through the source arrays. The positions in the destination array are then determined as 2*j and 2*j+1, and there is no need for an inner loop.
Thirdly, as explained in the comment, a correct implementation of sorted-list merge needs two independent counters j1 and j2. However, your current input is hardwired into the code, and if you replace 00 with 100, your current algorithm (after the corrections above are made) will actually work for the given input.
Finally, but less importantly, I wonder why your destination array is allocated on the heap using new. As long as you are dealing with small arrays, you may allocate it on the stack just like the source arrays. If, however, you allocate it on the heap, better use a std::unique_ptr<>, possibly combined with std::array<>. You'll get de-allocation for free then without having to think of putting a delete [] statement at the end of the function.

Before even looking at the implementation, check the algorithm and write it down with pen and paper. The first thing that pops is that you are assuming that the first two elements in the result will come one from each source array. That need not be the case, consider two arrays where all elements in one are smaller than all elements in the other and the expected result:
int a[] = { 1, 2, 3 };
int b[] = { 4, 5, 6 };
If you want the result sorted, then the first three elements come all from the first array. With that in mind think on what you really know about the data. In particular, both arrays are sorted, which means that the first elements will be smaller than the rest of the elements in the respective array. The implication of this is that the smaller element is the smaller of the heads. By putting that element into the result you have reduced the problem to a smaller set. You have a' = { 2, 3 }, b = { 4, 5, 6 } and res = { 1 } and a new problem that is finding the second element of res knowing that a' and b are sorted.
Figure out in paper what you need to do, then it should be straight forward to map that to code.

So, I modified your code to make it work. Actually it would be good idea to have two pointer/index for two sorted arrays. So that you can update your corresponding pointer after adding it to your combinedArray. Let me know if you don't understand any part of this code. Thanks.
int sortedArray1 [5] = {11, 33, 55, 77, 99};
int sortedArray2 [5] = {0, 22, 44, 66, 88};
int combinedSize = 10;
int *combinedArray;
combinedArray = new int[combinedSize];
int j = 0;
int k = 0;
for(int i = 0; i < combinedSize; i++)
{
if (j < 5 && k < 5) {
if (sortedArray1[j] < sortedArray2[k]) {
combinedArray[i] = sortedArray1[j];
j++;
} else {
combinedArray[i] = sortedArray2[k];
k++;
}
}
else if (j < 5) {
combinedArray[i] = sortedArray1[j];
j++;
}
else {
combinedArray[i] = sortedArray2[k];
k++;
}
}
for(int i = 0; i < combinedSize; i++)
{
cout << combinedArray[i];
cout << " ";
}
cout<<endl;

The else if(sortedArray1[j] = sortedArray2[j]), did you mean else if(sortedArray1[j] == sortedArray2[j])?
The former one will assign the value of sortedArray2[j] to sortedArray1[j] -- and that's the reason that why you get 5 77 5 77...
But where's the 5 come from? There's no 5 in either sortedArray, yet I find for(int j = 0; j <= 5; j++) must be something wrong. The highest index of a size N array is N-1 rather than N in C/C++(but not in Basic).. so use j<5 as the condition, or you may fall into some situation which is hard to explain or predict..
After all, there's problem in your algorithm itself, every time the outer loop loops, it will at last compare the last elements in the two arrays, which makes the output to repeat two numbers.
So you need to correct your algorithm too, see Merge Sort.

Slightly different approach, which is IMHO a bit cleaner:
//A is the first array, m its length
//B is the second array, n its length
printSortedAndMerged(int A[], int m, int B[], int n){
int c[n+m];
int i=0, j=0;
for(int k=0; k < n+m; k++){
if(i < m && j < n){
if(A[i] < B[j]){
c[k] = A[i];
i++;
}
else{
c[k] = B[j];
j++;
}
continue; //jump to next iteration
}
if(i < m){ // && ~(j < n)
//we already completely traversed B[]
c[k] = A[i];
i++;
continue;
}
if(j < n){ // %% ~(i < m)
//we already completely traversed A[]
c[k] = B[j];
j++;
continue;
}
//we should never reach this
cout << "Wow, something wrong happened!" << endl;
}//for
for(int i=0; i<n+m; i++){
cout << c[i] << endl;
}
}
Hope it helps.

Related

Determine duplicates/pairs in an array in C++

I have been doing this problem for 2 days now, and I still can't figure out how to do this properly.
In this program, I have to input the number of sticks available (let's say 5). Then, the user will be asked to input the lengths of each stick (space-separated integer). Let's say the lengths of each stick respectively are [4, 4, 3, 3, 4]. Now, I have to determine if there are pairs (2 sticks of same length). In this case, we have 2 (4,4 and 3,3). Since there are 2 pairs, we can create a canvas (a canvas has a total of 2 pairs of sticks as the frame). Now, I don't know exactly how to determine how many "pairs" there are in an array. I would like to ask for your help and guidance. Just note that I am a beginner. I might not understand complex processes. So, if there is a simple (or something that a beginner can understand) way to do it, it would be great. It's just that I don't want to put something in my code that I don't fully comprehend. Thank you!
Attached here is the link to the problem itself.
https://codeforces.com/problemset/problem/127/B
Here is my code (without the process that determines the number of pairs)
#include<iostream>
#include<cmath>
#define MAX 100
int lookForPairs(int numberOfSticks);
int main(void){
int numberOfSticks = 0, maxNumOfFrames = 0;
std::cin >> numberOfSticks;
maxNumOfFrames = lookForPairs(numberOfSticks);
std::cout << maxNumOfFrames << std::endl;
return 0;
}
int lookForPairs(int numberOfSticks){
int lengths[MAX], pairs = 0, count = 0, canvas = 0;
for(int i=0; i<numberOfSticks; i++){
std::cin >> lengths[i];
}
pairs = floor(count/2);
canvas = floor(pairs/2);
return count;
}
I tried doing it like this, but it was flawed. It wouldn't work when there were 3 or more integers of the same number (for ex. [4, 4, 3, 4, 2] or [5. 5. 5. 5. 6]). On the first array, the count would be 6 when it should only be 3 since there are only three 4s.
for(int i=0; i<numberOfSticks; i++){
for (int j=0; j<numberOfSticks; j++){
if (lengths[i] == lengths[j] && i!=j)
count++;
}
}
Instead of storing all the lengths and then comparing them, count how many there are of each length directly.
These values are known to be positive and at most 100, so you can use an int[100] array for this as well:
int counts[MAX] = {}; // Initialize array to all zeros.
for(int i = 0; i < numberOfSticks; i++) {
int length = 0;
std::cin >> length;
counts[length-1] += 1; // Adjust for zero-based indexing.
}
Then count them:
int pairs = 0;
for(int i = 0; i < MAX; i++) {
pairs += counts[i] / 2;
}
and then you have the answer:
return pairs;
Just an extension to molbdnilo's answer: You can even count all pairs in one single iteration:
for(int i = 0; i < numberOfSticks; ++i)
{
if(std::cin >> length) // catch invalid input!
{
pairs += flags[length] == 1; // add a pair if there is already a stick
flags[length] ^= 1; // toggle between 0 and 1...
}
else
{
// some appropriate error handling
}
}
Note that I skipped subtracting 1 from the length – which requires the array being one larger in length (but now it can be of smallest type available, i.e. char), while index 0 just serves as an unused sentinel. This variant would even allow to use bitmaps for storing the flags, though questionable if, with a maximum length that small, all this bit fiddling would be worth it…
You can count the number of occurrences using a map. It seems that you are not allowed to use a standard map. Since the size of a stick is limited to 100, according to the link you provided, you can use an array, m of 101 items (stick's minimum size is 1, maximum size is 100). The element index is the size of the stick. The element value is the number of sticks. That is, m[a[i]] is the number of sticks of size a[i]. Demo.
#define MAX 100
int n = 7;
int a[MAX] = { 1,2,3,4,1,2,3 };
int m[MAX + 1]; // maps stick len to number of sticks
void count()
{
for (int i = 0; i < n; ++i)
m[a[i]]++;
}
int main()
{
count();
for (int i = 1; i < MAX + 1; ++i)
if (m[i])
std::cout << i << "->" << m[i] << std::endl;
}
Your inner loop is counting forward from the very beginning each time, making you overcount the items in your array. Count forward from i , not zero.
for(int i=0; i<numberOfSticks; i++)
{
for (int j=i; j<numberOfSticks; j++) { // count forward from i (not zero)
if (lengths[i] == lengths[j] && i!=j)
{ // enclosing your blocks in curly braces , even if only one line, is easier to read
count++; // you'll want to store this value somewhere along with the 'length'. perhaps a map?
}
}
}

Remove duplicates from array C++

Input: int arr[] = {10, 20, 20, 30, 40, 40, 40, 50, 50}
Output: 10, 30
My code:
int removeDup(int arr[], int n)
{
int temp;
bool dupFound = false;
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
if(arr[i] == arr[j]){
if(!dupFound){
temp = arr[i];
dupFound = true;
}
else{
arr[i] = temp;
}
}
}
}
//shift here
}
First of all, I don't know if this is the most efficient way of doing this.
I'm trying to find the first duplicate element, assign it to every duplicate element and shift them to the end of the array, which doesn't work because the last duplicate element cannot be compared.
I need some help with finding the last duplicate element, so I can assign temp to it.
I do not understand the logic of your code. When you find the second element arr[j] that equals arr[i] you will assign temp to arr[i]. However, temp has been assigned arr[i] when you found the first duplicate. Essentially you do arr[i] = arr[i]. Its not clear how this is supposed to find unique elements.
You can use a map to count frequency of elements, then print those with frequency 1:
#include <unordered_map>
#include <iostream>
int main()
{
std::unordered_map<int,size_t> freq;
int arr[] = {10, 20, 20, 30, 40, 40, 40, 50, 50};
// count frequencies
for (auto e : arr) { ++freq[e]; }
// print the elements e where freq[e] == 1
for (const auto& f : freq) {
if (f.second == 1) {
std::cout << f.first << "\n";
}
}
}
Only small modifications needed to add the unique elements to a vector.
Instead of trying to do everything at once, let us focus on correctness first:
int removeDup(int* arr, int n) {
// Note: No i++! This depends on whether we find a duplicate.
for (int i = 0; i < n;) {
int v = arr[i];
bool dupFound = false;
for (int j = i+1; j < n; j++) {
if (v == arr[j]) {
dupFound = true;
break;
}
}
if (!dupFound) {
i++;
continue;
}
// Copy values to the sub-array starting at position i,
// skipping all values equal to v.
int write = i, skipped = 0;
for (int j = i; j < n; j++) {
if (arr[j] != v) {
arr[write] = arr[j];
write++;
} else {
skipped++;
}
}
// The previous loop duplicated some non-v elements.
// We decrease n to make sure these duplicates are not
// considered in the output
n -= skipped;
}
return n;
}
Let's start with logistics (so to speak). An array always contains a fixed number of items. There's simply no way to start with an array of 5 items, and turn it into an array of 2 items. Simply can't be done.
So, as a starting point, you need to either return something like an std::vector that keeps track of its size along with the data it contains, or else you're going to need to track the size, and return something to indicate how many elements in the array are valid after the processing.
Probably the simplest way to do things would be to use something like an std::unoredered_map to count the items, then walk through the map, and insert an item in the output if (and only if) its count is 1.
std::unordered_map<int, std::size_t> counts;
for (int i=0;i<n; i++)
++counts[arr[i]];
std::vector<int> output;
for (auto item : counts)
if (item.second == 1)
output.push_back(item.first);
return output;
If you want to modify the data in place, I'd start by sorting the input data. Then you'll start with two indices: one for your "input" position, and one for your "output" position. output starts as zero, and input as 1.
The general idea from there is pretty simple: we look at data[input] and see if it's different from both the preceding and succeeding elements. If so, we copy it to data[output], and increment the output position.
Since this tries to look at both the preceding and succeeding elements, we have to include special cases for the beginning and end of the array. The first element is unique if it's different from the following, and the end is unique if it's different from the preceding. Code can look like this:
#include <algorithm>
#include <iostream>
unsigned remove_dupe(int *data, unsigned n) {
if (n < 2) {
return n;
}
std::sort(data, data+n);
unsigned output = data[0] != data[1];
for (unsigned input = output+1; input<n-1; input++)
if (data[input] != data[input-1] && data[input] != data[input+1])
data[output++] = data[input];
if (data[n-1] != data[n-2]) {
data[output++] = data[n-1];
}
return output;
}
template <class T, std::size_t N>
void test(T (&arr)[N]) {
unsigned end = remove_dupe(arr, N);
for (int i=0; i<end; i++)
std::cout << arr[i] << "\t";
std::cout << "\n";
}
int main() {
int arr0[] = {10, 20, 20, 30, 40, 40, 40, 50, 50};
int arr1[] = { 1, 2};
int arr2[] = { 1, 1};
test(arr0);
test(arr1);
test(arr2);
}
Result:
10 30
1 2
Another option that might be available is to sort() the array. When this is done, all duplicate values throughout the array are now adjacent. You simply compare element [n] with element [n+1] to see if they are the same. You can now find and count all duplicates in a single linear pass through the sorted array.
Sorting is one of the most heavily-studied class of algorithms in computer science, and very efficient processes can be developed which rely upon things being sorted a certain way.

iterating over vector elements backwards

I am trying to implement a small program that iterates over a 2d vector backwards and adds the value of the element.
If that element have already been added then I want to overwrite the value of the vector with 99.
So for example if number of climbs is four then add the of the program points should have the value 5 and the vector should look like this at the end
{1, 1 ,1},
{99, 1, 1},
{99(should start here), 99, 99}
But I keep getting a segmentation fault and I don't know whether I am iterating over the vector backwards incorrectly.
This is my full code
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<vector<int>> vect
{ {3}, //finish here
{1, 1 ,1},
{2, 1, 1},
{1, 1, 1} //start here
};
int points = 0;
for (int i = 0; i < vect.size(); i++)
{
for (int j = 0; j < vect[i].size(); j++)
{
cout << vect[i][j] << " ";
}
cout << endl;
}
int visited = 99;
int number_of_climbs = 4;
for(int i = 4; i >= 0; i--)
for (int j = 0; j < number_of_climbs; j++)
{
if(vect[i][j] != 99)
{
points += vect[i][j];
vect[i][j] = 99;;
continue;
}
}
return 0;
}
Looping over things backwards always trips me up too, especially when I accidentally declare my loop using an unsigned int. Your backwards loop is close to correct, but can be simplified into:
for (int i = vect.size() - 1; i >= 0; --i)
{
for (int j = vect[i].size() - 1; j >= 0; --j)
{
}
}
You need to start at size() - 1 because the only indices available are [0, size) (that is EXCLUSIVE of size), so in a vector of 4 elements, that's 0, 1, 2 and 3 (and you need to start at 3), which is likely the cause of your segmentation fault since you start your initial loop at 4 so it's immediately out-of-bounds.
Here in the inner loop you can see we account for the vectors being different sizes by just using the size of each vector.
It's also possible to use reverse iterators, but iterators can be confusing to people:
for (auto outer = vect.rbegin(); outer != vect.rend(); ++outer)
{
for (auto inner = outer->rbegin(); inner != (*outer).rend(); ++inner)
{
}
}
Note I've shown both ways to access the iterator, using it-> or (*it). Within the inner loop, you will simply use *inner to get the actual value held by the vector, so if you simply had std::cout << *inner << " "; that would print the 2d vector on one line in reverse order.
Even though we're looping in reverse, we still use ++

Is there any way to make this sorting algorithm have a linear time complexity?

I am doing this homework assignment in my data structures & algorithms class that asks me to make an array of random numbers, an array of counters, and make our own sorting algorithm using both arrays in C++.
The array of counters would basically contain the index of where each element is supposed to go when the array of numbers is sorted, such that the value of counters[i] would be the index where array[i] would go after it's sorted. It uses this code, and it was given by our professor:
for (int i = 1; i < arraySize; i++)
for (int j = 0; j < i; j++)
{
if (array[i] < array[j])
counters[j]++;
else
counters[i]++;
}
I thought that using both of the arrays, we would be able to design a sorting algorithm that would have a O(n) time complexity, so I tried to think of a way to do this, and I came up with this:
for (int i = 0; i < arraySize; i++)
{
int index = counters[i];
swap(array[i], array[counters[i]]);
swap(counters[i], counters[index]);
}
For every iteration, I am swapping array[i] with array[counters[i]] because counters[i] determines the index for array[i], and then I am also swapping the values in the counters to make sure that the counters stay in the same index as their corresponding value.
For some reason, this is not achieving the sorting correctly, but I don't understand why.
I'm thinking to use another sorting algorithm, but I wanted to try this one first because it would be O(n).
Anyone could help?
Thanks.
Since the professor gave you the counting (which btw even handles duplicates correctly), I agree that you should use it to finish the sorting in additional O(n).
To do that, keep swapping what's at array[i] to where it belongs until array[i] contains what belongs there. Only then go to i+1. This way you know array[0..i] all contain what belongs there (and thus in the everything is where it belongs).
for (int i = 0; i < arraySize; i++) {
int belongs_at = counters[i];
while (belongs_at != i) {
swap(array[i], array[belongs_at]);
swap(counters[i], counters[belongs_at]);
belongs_at = counters[i];
}
}
This is O(n), since every iteration of the inner loop puts one (or two) more value to where it belongs, and overall you can't put more than n values to where they belong, so overall you can't have more than n inner loop iterations.
Let's take {20, 50, 60, 70, 10, 40, 30} as an example and see what the array looks like at the end of each iteration of the for-loop:
10 20 60 70 50 40 30 # The while-loop fixed the cycle 20->50->10
10 20 60 70 50 40 30 # 20 was already where it belongs, so nothing happened
10 20 30 40 50 60 70 # The while-loop fixed the cycle 60->40->70->30
10 20 30 40 50 60 70 # 40 was already where it belongs, so nothing happened
10 20 30 40 50 60 70 # 50 was already where it belongs, so nothing happened
10 20 30 40 50 60 70 # 60 was already where it belongs, so nothing happened
10 20 30 40 50 60 70 # 70 was already where it belongs, so nothing happened
Let's see an example where yours goes wrong: {1, 2, 3, 0}. You'll first swap the 1 to where it belongs: {2, 1, 3, 0}. This still leaves 2 not where it belongs! You rely on it hopefully getting fixed later on. But that never happens, as you then swap 1 with itself, then 3 with 0, and then 3 with itself. But if at i=0 you keep going until array[i] contains what belongs there, then you don't leave that 2 there dangerously out-of-place but fix it right away.
Full code, also at repl.it (this produced the above output):
#include <iostream>
using namespace std;
int main() {
// Sample array
int arraySize = 7;
int array[7] = {20, 50, 60, 70, 10, 40, 30};
// Count
int counters[7] = {};
for (int i = 1; i < arraySize; i++)
for (int j = 0; j < i; j++)
if (array[i] < array[j])
counters[j]++;
else
counters[i]++;
// Sort
for (int i = 0; i < arraySize; i++) {
int belongs_at = counters[i];
while (belongs_at != i) {
swap(array[i], array[belongs_at]);
swap(counters[i], counters[belongs_at]);
belongs_at = counters[i];
}
// Show
for (int i = 0; i < arraySize; i++)
cout << array[i] << ' ';
cout << endl;
}
}
If you want to achieve linear time, the input array must be comes with some kind of the assumption, ie, input array is integer and within some kind of the range for counting sort and radix sort.
In the bottom solution, counterSort assume the input array is from 0-9, and insert the number to a pair,
vector< pair<vector<int>,int> >
the pair will keep tracking of the vector and its' counter.
#include <stdlib.h>
#include <iostream>
#include <vector>
using namespace std;
// counterSort
void counterSort(int sze, int* arrp, vector<pair< vector<int>,int> >& v)
{
// pair will store a map between list and counter,
for(int i = 0; i < sze; i++)
{
int numb = arrp[i];
v[numb].first.push_back(numb);
v[numb].second++;
}
}
// method for print out
void printOut(vector< pair<vector<int>,int> >& v)
{
for(auto& item: v)
{
cout << "counter:" << item.second << "| ";
for(auto& i:item.first)
{
cout << i << " ";
}
cout << endl;
}
}
int main()
{
int* arrp = new int[50];
for(int i = 0; i < 50; i++)
{
int r = rand() % 10;
arrp[i] = r;
cout << arrp[i] << " ";
}
cout << endl;
int sze = 50;
vector<pair<vector<int>,int> > v( sze,make_pair(vector<int>(0),0) );
counterSort(sze,arrp, v);
printOut(v);
delete [] arrp;
return 0;
}

sort array without conditional

I need a program that sorts an array of integers without using conditional statements. Numbers are in the range from 0 to 100 and don't repeat.
#include <iostream>
using namespace std;
int main() {
int arr[] = { 34, 12, 24, 65, 63, 22 };
int arraySize = (sizeof(arr) / sizeof(*arr));
unsigned char buf[101] = { 0 };
for (int k = 0; k < arraySize; k++) {
buf[arr[k]]++;
}
unsigned char i = 0;
for (int k = 0; k <= 100; k++) {
arr[i] = k;
i += buf[k];
}
for (int a : arr) {
cout << a << endl;
}
system("pause");
return 0;
}
This program works but I get the error after closing of the command prompt:
Run-Time Check Failure #2 - Stack around the variable 'arr' was corrupted.
Is there a way to fix it?
The problem is that your code writes past the end of the array. It happens after you have encountered the last element in the counted sequence, but before the array buf has been exhausted, i.e.
for (int k = 0; k <= 100; k++) {
arr[i] = k;
i += buf[k];
}
When you add the highest element, which is 65, to the result, i reaches 6, so assigning a[i] becomes illegal. See what's going on by adding an extra element to your array, setting it to -1, and watching what happens to it (it gets set to 100; demo 1).
You can fix it by adding an early exit condition to stop as soon as you filled the array back, i.e.
for (int k = 0; i < arraySize && k <= 100; k++) {
arr[i] = k;
i += buf[k];
}
Now the -1 past the end of "active" part of our array remains -1 (demo).
The logic of the second loop is wrong. You have six numbers in arr, no doubles, which means that a total of six elements in buf will be set to 1.
That means that after a while, the value of i will be 6, which you then use as an index into arr, but index 6 is the seventh element in an array, leading you to write out of bounds.