I've followed all the algorithm steps very carefully , but still this always outputs me the wrong answer. I don't understand why. I think something's wrong in the merge algorithm that's causing this but cannot pinpoint what. Please help. Also if there is anything that can be done to improve the code please suggest.
Thank you
INPUT - {5,6,1,8,9,7}
OUTPUT - {1,0,7,0,9,7}
#include<stdio.h>
#include<malloc.h>
void mergeSort(int array[],int length);
void merge(int *leftArray,int *rightArray,int *array);
void main()
{
int array[] = {5,6,1,8,9,7};
int length_of_array;
length_of_array = sizeof(array) / sizeof(array[0]);
mergeSort(array,length_of_array);
int i;
for(i=0;i<length_of_array;i++)
{
printf("%d->",array[i]);
}
}
void mergeSort(int array[],int length)
{
if(length < 2)
return;
int mid;
int i;
mid = length/2;
int *leftArray, *rightArray;
leftArray = (int*)malloc(mid*sizeof(int));
rightArray = (int*)malloc((length-mid)*sizeof(int));
for(i=0;i<mid;i++)
leftArray[i] = array[i];
for(i=mid;i<length;i++)
rightArray[i-mid] = array[i];
mergeSort(leftArray, mid);
mergeSort(rightArray, length-mid);
merge(leftArray,rightArray,array);
}
void merge(int *leftArray,int *rightArray,int *array)
{
int i,j,k;
i = j = k = 0;
int leftSize = sizeof(leftArray)/sizeof(leftArray[0]);
int rightSize = sizeof(rightArray)/sizeof(rightArray[0]);
while(i < leftSize && j < rightSize)
{
if(leftArray[i]<rightArray[j])
{
array[k] = leftArray[i];
k = k + 1;
i = i + 1;
}
else
{
array[k] = rightArray[j];
k = k + 1;
j = j + 1;
}
}
while(i<leftSize)
{
array[k] = leftArray[i];
k = k + 1;
i = i + 1;
}
while(j<rightSize)
{
array[k] = rightArray[j];
k = k + 1;
j = j + 1;
}
}
As commented by #molbdnilo, you can't get the size of an array from a pointer parameter. So merge needs to take the length of the left and right arrays as well as the pointers to them.
The issue is that arrays in C are not a 'complete' data type, but rather just a convenient syntax. In your merge function, the parameter int *leftArray is exactly what it says - a pointer to an integer. So sizeof will tell you the size of a pointer. In your main function, array is known to be an array, and its length is known (from the initial value given), so sizeof can give the actual size of memory allocated to that variable. But that size is not stored anywhere with the variable, so it is not passed into merge - the only thing passed in is the pointer to the block of memory.
In addition, while it won't be causing you problems in this case, you should be freeing the leftArray and rightArray pointers that you malloc. That way you can use your sorting function in an actual application without leaking memory.
Related
This is my code for merge sort in C. I'm not able to understand what the issue is here. My knowledge of pointers is not that much. The merge function takes in 2 arrays and merges them. the sort function is a recursive function which is supposed to sort the array.
int * merge(int *fir, int n, int *sec, int m){
int res[m+n];
int x=0, y=0;
for(int i = 0; i < m+n; i++){
if(*(fir+x)<=*(sec+y)){
res[i] = *(fir+x);
x++;
}else{
res[i] = *(sec+y);
y++;
}
}
return res;
}
int * sort(int A[], int n){
if(n == 1){
return A;
}
int mid = n/2;
int AL[mid], AR[n-mid];
for(int i = 0; i < mid; i++){
AL[i] = A[i];
}
for(int i = 0; i < n-mid; i++){
AR[i] = A[i+mid];
}
int *BL, *BR;
BL = sort(AL, mid);
BR = sort(AR, n-mid);
return(merge(BL, mid, BR, n-mid));
}
int main(){
int n;
scanf("%d", &n);
int A[n];
for(int i = 0; i < n; i++){
scanf("%d", &A[i]);
}
int *sortedArray;
sortedArray = sort(A, n);
for(int i = 0; i < n; i++){
printf("%d ", *(sortedArray+i));
}
return 0;
}
And this is the output
q8.c:16:9: warning: address of stack memory associated with local variable 'res' returned [-Wreturn-stack-address]
return res;
^~~
1 warning generated.
7
23 12 56 67 11 99 97
97 32766 539779418 32767 -2002825496 32767 6 %```
There are two issues here: First, you merge your partial arrays into a temporary local array, which yoes out of bounds after you return from merge. The pointer you return points to invlid memory. That's what the warning about.
Second, you don't check whether you are reading beyond the limits of the partial arrays when you merge: The condition x < n must be true when you access fir, likewise for y < m and sec.
You are also causing confusion by returning a pointer to the first element of the sorted or merged arrays. That suggests that you create new sorted and merged arrays (and that's what you try to do in merge). This is okay for garbage-collected morern languages, but C doesn't work that way.
In C, if you need new memory, you must allocate it and later free it explicitly. In a recursive function like yours, this is tedious, because you are interested only in the final sorted array, not in the intermediate results. Therefore, C sorting algorithms usually work "in place": The same memory is used thoughout the sorting and elements are swapped. The original order of the elements is lost unless you make a copy before sorting.
For merge sort, you need auxiliary memory. In your case, you use the temporary arrays AL and AR, which are copies of the contents of the original array, A. Now when you merge, you can merge AL and AR back into A.
So istead of creating a ephemeral local array, pass in A so that it can be filled with the sorted elements:
void sort(int A[], int n)
{
if (n > 1) {
int mid = n / 2;
int AL[mid], AR[n - mid];
for (int i = 0; i < mid; i++) AL[i] = A[i];
for (int i = 0; i < n - mid; i++) AR[i] = A[i + mid];
sort(AL, mid);
sort(AR, n - mid);
merge(A, AL, mid, AR, n - mid);
}
}
Your merge function is now very similar to the one you has before, only that you have the result array as parameter and that you must catch the out-of-bound cases before accessing elements with [].
void merge(int *res, const int *fir, int n, const int *sec, int m)
{
int x = 0, y = 0;
for(int i = 0; i < m + n; i++) {
if (x == n) res[i] = sec[y++];
else if (y == m) res[i] = fir[x++];
else if (fir[x] <= sec[y]) res[i] = fir[x++];
else res[i] = sec[y++];
}
}
Wrong output!
I have tried each and every condition but failed to get the real result
I tried to accomplish this from the clrs book pseudo-code but I failed.
I am trying to write merge sort using iterators to implement myself pseudo-code in c language, but for some reason, this code is compiling but the outcome is not sorted. Can someone figure out what is wrong with it? it seems perfectly fine to my untrained eyes.
#include <stdio.h>
#include<math.h>
#include <stdlib.h>
int a[] = {5,3,65,6,7,3,7,8};
void print_array(int a[], int size)
{
int i;
for(i = 0;i < size;i++)
{
printf("%d ",a[i]);
}
}
void merge(int a[],int p,int q,int r)
{
int n1,n2,i,j,k;
n1 = q - p + 1;
n2 = r - q;
int l[n1];
int m[n2];
for(i = 0; i < n1; i++)
l[i] = a[i+p];
for(j = 0; j < n2; j++)
m[j] = a[q+1+j];
l[n1] = 9999999;
m[n2] = 9999999;
i = 0;
j = 0;
for(k = p;k < r; k++)
{
if(l[i] <= m[j])
{
a[k] = l[i];
i = i+1;
}
else
{
a[k] = m[j];
j = j+1;
}
}
}
void merge_sort(int a[],int p,int r)
{
if(p < r)
{
int q = floor((p + r) / 2);
merge_sort(a,p,q);
merge_sort(a,q+1,r);
merge(a,p,q,r);
}
}
int main()
{
int size = (sizeof(a) / sizeof(a[0]));
print_array(a,size);
printf("\n");
merge_sort(a,0,size);
print_array(a,size);
return 0;
}
//for this input out put is showing
//-1 -1 3 3 3 -1 6 7
Please pay attention to array bounds and sizes:
Your parameter r is not the size of the array, but the index of the rightmost element, so you should call merge_sort(a, 0, size - 1);.
When you want to use a large sentinel value, after the actual array, you must allocate space for it, so:
int l[n1];
int m[n2];
Because your value r is the index of the last element, you must consider it when merging and your loop condition should be for(k = p; k <= r; k++).
(Not really a problem, but you don't need to use floor like in JavaScript. When a and b are integers, a / b will perform a division that results in an integer.)
In C, arrays (and ranges in general) have inclusive lower bounds and exclusive upper bounds: lo is the first valid index and hi is the first invalid index after the valid range. For array indices, lo and hi are zero and the array size.
Embrace this convention. The C indices lead to the following style:
The length of a range is hi - lo;
Forward loops are for (i = lo; i < hi; i++);
Adjacent ranges share the hi and lo values.
For example, in your merge function the middle value p would be the first value in the right range, but also the exclusive upper bound of the left range.
If pseudocode or code in other languages uses one-based indices, I recommend translating it to the zero-based, exclusive upper-bound style of C. After a while, you'll get suspicious of spurious - 1's and <='s. :)
In the Chapter 7 of Deitel's C how to program the author used bubble sort example to show that information hiding does not allow individual array elements to be known to the function, pointers can be used to pass the address around and used the same way.
Here is the swap function using pointer:
void swap( int *element1Ptr, int *element2Ptr ) {
int hold = *element1Ptr;
*element1Ptr = *element2Ptr;
*element2Ptr = hold;
}
Here is what I did:
void swap(int array[],int j) {
int hold = array[j];
array[j] = array[j + 1];
array[j + 1] = hold;
}
The main():
int main(void) {
int b[] = {2,6,4,8,10,12,89,68,45,37};
for (int i = 0; i < 9; i++) {
for (int n = 0; n < 9; n++) {
if (b[n] > b[n + 1]) {
swap(&b[n], &b[n+1]); // or swap(b,n);
}
}
}
for (int i = 0; i < 9; i++) {
printf("%d ", b[i]);
}
puts("");
return 0;
}
I ran the code and both sort the array correctly. So I thought my function actually gained the access to individual element. Which part am I understanding wrong? I need to make sure I understand every point before moving on as skipping one really makes the coming content difficult to grasp.
In C, pointers and arrays are interchangeable. When you access array elements by index, as in myArray[x], it means "the location of myArray + (x * the size of the elements in the array)". So you can get the same result by doing myArray + (x * sizeof(<type of myArray>));.
You may also want to check out this answer which goes into more depth on the differences between arrays and pointers.
I was writing a code the other day and I found it rather strange, that int** and int[][] does not behave the same way. Can anyone point out the differences between them? Below is my sample code, which fails with a segmentation fault, if I pass constant size 2d array, while it does work fine when I pass a dinamically allocated 2d array.
I am confused mainly because ant int[] array works the same as int*.
#include<stdio.h>
#include<stdlib.h>
void sort_by_first_row(int **t, int n, int m)
{
int i, j;
for(i = m-1 ; i > 0 ; --i)
{
for(j = 0 ; j < i; ++j)
{
if(t[0][j] < t[0][j+1])
{
int k;
for(k = 0 ; k < n ;++k)
{
int swap;
swap = t[k][j];
t[k][j] = t[k][j+1];
t[k][j+1] = swap;
}
}
}
}
}
int main(void) {
int i, j;
/* Working version */
/*int **t;
t =(int**) malloc(3*sizeof(int*));
for(i = 0; i < 3; ++i)
{
t[i] = (int*) malloc(6*sizeof(int));
}*/
/*WRONG*/
int t[3][6];
t[0][0] = 121;
t[0][1] = 85;
t[0][2] = 54;
t[0][3] = 89;
t[0][4] = 879;
t[0][5] = 11;
for( i = 0; i < 6; ++i )
t[1][i] = i+1;
t[2][0] = 2;
t[2][1] = 4;
t[2][2] = 5;
t[2][3] = 3;
t[2][4] = 1;
t[2][5] = 6;
sort_by_first_row(t, 3, 6);
for(i = 0; i < 3; ++i)
{
for(j = 0; j < 6; ++j)
printf("%d ", t[i][j]);
printf("\n");
}
return 0;
}
So based on the below answers I realize, that a multidimensional array is stored continuously in a row major order. After some modification, the below code works:
#include<stdio.h>
#include<stdlib.h>
void sort_by_first_row(int *t, int n, int m)
{
int i, j;
for(i = m-1 ; i > 0 ; --i)
{
for(j = 0 ; j < i; ++j)
{
if(t[j] < t[j+1])
{
int k;
for(k = 0 ; k < n ;++k)
{
int swap;
swap = t[k*m + j];
t[k*m + j] = t[k*m + j+1];
t[k*m + j+1] = swap;
}
}
}
}
}
int main(void) {
int i, j;
/* Working version */
/*int **t;
t =(int**) malloc(3*sizeof(int*));
for(i = 0; i < 3; ++i)
{
t[i] = (int*) malloc(6*sizeof(int));
}*/
/*WRONG*/
int t[3][6];
t[0][0] = 121;
t[0][1] = 85;
t[0][2] = 54;
t[0][3] = 89;
t[0][4] = 879;
t[0][5] = 11;
for( i = 0; i < 6; ++i )
t[1][i] = i+1;
t[2][0] = 2;
t[2][1] = 4;
t[2][2] = 5;
t[2][3] = 3;
t[2][4] = 1;
t[2][5] = 6;
sort_by_first_row(t, 3, 6);
for(i = 0; i < 3; ++i)
{
for(j = 0; j < 6; ++j)
printf("%d ", t[i][j]);
printf("\n");
}
return 0;
}
My new question is this: How to modify the code, so that the procedure works with int[][] and int** also?
Realize that int **t makes t a pointer to a pointer, while int t[3][6] makes t an array of an array. In most cases, when an array is used in an expression, it will become the value of the address of its first member. So, for int t[3][6], when t is passed to a function, the function will actually be getting the value of &t[0], which has type pointer to an array (in this case, int (*)[6]).
The type of what is being pointed at is important for how the pointer behaves when indexed. When a pointer to an object is incremented by 5, it points to the 5th object following the current object. Thus, for int **t, t + 5 will point to the 5th pointer, while for int (*t)[M], t + 5 will point to the 5th array. That is, the result of t + 5 is the same as the result of &t[5].
In your case, you have implemented void sort_by_first_row(int **t, int n, int m), but you are passing it an incompatible pointer. That is, the type of &t[0] (which is what t will become in main) is not the same as what the function wants, a int **t. Thus, when the sorting function starts to use that address, it will think its indexing into pointers, when the underlying structure is an array of arrays.
int** is quite different from int[][]. int** is simply a pointer to a pointer and would appear like the following:
in reality, you can access the entire multidimensional array with simply int* pointing to the first element, and doing simple math from that.
Here is the result of the separate allocations (in your commented code):
However when you allocate a multidimensional array, all of the memory is contiguous, and therefore easy to do simple math to reach the desired element.
int t[3][6];
int *t = (int*) malloc((3 * 6) * sizeof(int)); // <-- similarly
This will result in a contiguous chunk of memory for all elements.
You certainly can use the separate allocations, however you will need to walk the memory differently.
Hope this helps.
int t[3][6] is very nearly the same thing as int t[18]. A single contiguous block of 18 integers is allocated in both cases. The variable t provides the address of the start of this block of integers, just like the one-dimensional case.
Contrast this with the case you have marked as "working", where t gives you the address of a block of 3 pointers, each of which points to a block of memory with 6 integers. It's a totally different animal.
The difference between t[3][6] and t[18] is that the compiler remembers the size of each dimension of the array, and automatically converts 2D indices into 1D offsets. For example, the compiler automatically converts t[1][2] into *(t + 1*6 + 2) (equivalent to t[8] if it were declared as a one-dimensional array).
When you pass a multi-dimensional array to a function, there are two ways to handle it. The first is to declare the function argument as an array with known dimension sizes. The second is to treat your array like a 1D array.
If you are going to declare the size of your array, you would declare your function like this:
void sort_by_first_row(int t[][6], int n)
or this
void sort_by_first_row(int t[3][6])
You either have to declare all array dimension sizes, or you can leave out the first size. In both cases, you access elements of t using t[i][j]; you've given the compiler enough information to do the offset math that converts from 2D notation to a 1D index offset.
If you treat it as a 1D array, you have to pass the array dimensions and then do the offset math yourself.
Here's a full working example, where f and f2 both generate the same output:
void f(int* t, int m, int n)
{
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
std::cout << t[i * n + j] << " ";
std::cout << std::endl;
}
void f2(int t[][6], int m)
{
for (int i = 0; i < m; i++)
for (int j = 0; j < 6; j++)
std::cout << t[i][j] << " ";
std::cout << std::endl;
}
int main()
{
int t[3][6];
int val = 1;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 6; j++)
{
t[i][j] = val;
val++;
}
}
f(&(t[0][0]), 3, 6);
f2(t, 3);
return 0;
}
One thing to note is the hack-ish way I had to pass t to f. It's been a while since I wrote in C/C++, but I remember being able to pass t directly. Maybe somebody can fill me in on why my current compiler won't let me.
A int ** is a pointer to a pointer to an int, and can be a pointer to an array of pointers to arrays of ints. A int [][] is a 2-dimensional array of ints. A two-dimensional array is exactly the same as a one-dimensional array in C in one respect: It is fundamentally a pointer to the first object. The only difference is the accessing, a two-dimensional array is accessed with two different strides simultaneously.
Long story short, a int[][] is closer to an int* than an int**.
So.. I have something like this. It is supposed to create arrays with 10, 20, 50 100 .. up to 5000 random numbers that then sorts with Insertion Sort and prints out how many comparisions and swaps were done .. However, I am getting a runtime exception when I reach 200 numbers large array .. "Access violation writing location 0x00B60000." .. Sometimes I don't even reach 200 and stop right after 10 numbers. I have literally no idea.
long *arrayIn;
int *swap_count = (int*)malloc(sizeof(int)), *compare_count = (int*)malloc(sizeof(int));
compare_count = 0;
swap_count = 0;
int i, j;
for (j = 10; j <= 1000; j*=10) {
for (i = 1; i <= 5; i++){
if (i == 1 || i == 2 || i == 5) {
int n = i * j;
arrayIn = malloc(sizeof(long)*n);
fill_array(&arrayIn, n);
InsertionSort(&arrayIn, n, &swap_count, &compare_count);
print_array(&arrayIn, n, &swap_count, &compare_count);
compare_count = 0;
swap_count = 0;
free(arrayIn);
}
}
}
EDIT: ok with this free(arrayIn); I get this " Stack cookie instrumentation code detected a stack-based buffer overrun." and I get nowhere. However without it it's "just" "Access violation writing location 0x00780000." but i get up to 200numbers eventually
void fill_array(int *arr, int n) {
int i;
for (i = 0; i < n; i++) {
arr[i] = (RAND_MAX + 1)*rand() + rand();
}
}
void InsertionSort(int *arr, int n, int *swap_count, int *compare_count) {
int i, j, t;
for (j = 0; j < n; j++) {
(*compare_count)++;
t = arr[j];
i = j - 1;
*swap_count = *swap_count + 2;
while (i >= 0 && arr[i]>t) { //tady chybí compare_count inkrementace
*compare_count = *compare_count + 2;
arr[i + 1] = arr[i];
(*swap_count)++;
i--;
(*swap_count)++;
}
arr[i + 1] = t;
(*swap_count)++;
}
}
I am sure your compiler told you what was wrong.
You are passing a long** to a function that expects a int* at the line
fill_array(&arrayIn, n);
function prototype is
void fill_array(int *arr, int n)
Same problem with the other function. From there, anything can happen.
Always, ALWAYS heed the warnings your compiler gives you.
MAJOR EDIT
First - yes, the name of an array is already a pointer.
Second - declare a function prototype at the start of your code; then the compiler will throw you helpful messages which will help you catch these
Third - if you want to pass the address of a simple variable to a function, there is no need for a malloc; just use the address of the variable.
Fourth - the rand() function returns an integer between 0 and RAND_MAX. The code
a[i] = (RAND_MAX + 1) * rand() + rand();
is a roundabout way of getting
a[i] = rand();
since (RAND_MAX + 1) will overflow and give you zero... If you actually wanted to be able to get a "really big" random number, you would have to do the following:
1) make sure a is a long * (with the correct prototypes etc)
2) convert the numbers before adding / multiplying:
a[i] = (RAND_MAX + 1L) * rand() + rand();
might do it - or maybe you need to do some more casting to (long); I can never remember my order of precedence so I usually would do
a[i] = ((long)(RAND_MAX) + 1L) * (long)rand() + (long)rand();
to be 100% sure.
Putting these and other lessons together, here is an edited version of your code that compiles and runs (I did have to "invent" a print_array) - I have written comments where the code needed changing to work. The last point above (making long random numbers) was not taken into account in this code yet.
#include <stdio.h>
#include <stdlib.h>
// include prototypes - it helps the compiler flag errors:
void fill_array(int *arr, int n);
void InsertionSort(int *arr, int n, int *swap_count, int *compare_count);
void print_array(int *arr, int n, int *swap_count, int *compare_count);
int main(void) {
// change data type to match function
int *arrayIn;
// instead of mallocing, use a fixed location:
int swap_count, compare_count;
// often a good idea to give your pointers a _p name:
int *swap_count_p = &swap_count;
int *compare_count_p = &compare_count;
// the pointer must not be set to zero: it's the CONTENTs that you set to zero
*compare_count_p = 0;
*swap_count_p = 0;
int i, j;
for (j = 10; j <= 1000; j*=10) {
for (i = 1; i <= 5; i++){
if (i == 1 || i == 2 || i == 5) {
int n = i * j;
arrayIn = malloc(sizeof(long)*n);
fill_array(arrayIn, n);
InsertionSort(arrayIn, n, swap_count_p, compare_count_p);
print_array(arrayIn, n, swap_count_p, compare_count_p);
swap_count = 0;
compare_count = 0;
free(arrayIn);
}
}
}
return 0;
}
void fill_array(int *arr, int n) {
int i;
for (i = 0; i < n; i++) {
// arr[i] = (RAND_MAX + 1)*rand() + rand(); // causes integer overflow
arr[i] = rand();
}
}
void InsertionSort(int *arr, int n, int *swap_count, int *compare_count) {
int i, j, t;
for (j = 0; j < n; j++) {
(*compare_count)++;
t = arr[j];
i = j - 1;
*swap_count = *swap_count + 2;
while (i >= 0 && arr[i]>t) { //tady chybí compare_count inkrementace
*compare_count = *compare_count + 2;
arr[i + 1] = arr[i];
(*swap_count)++;
i--;
(*swap_count)++;
}
arr[i + 1] = t;
(*swap_count)++;
}
}
void print_array(int *a, int n, int* sw, int *cc) {
int ii;
for(ii = 0; ii < n; ii++) {
if(ii%20 == 0) printf("\n");
printf("%d ", a[ii]);
}
printf("\n\nThis took %d swaps and %d comparisons\n\n", *sw, *cc);
}
You are assigning the literal value 0 to some pointers. You are also mixing "pointers" with "address-of-pointers"; &swap_count gives the address of the pointer, not the address of its value.
First off, no need to malloc here:
int *swap_count = (int*)malloc(sizeof(int)) ..
Just make an integer:
int swap_coint;
Then you don't need to do
swap_coint = 0;
to this pointer (which causes your errors). Doing so on a regular int variable is, of course, just fine.
(With the above fixed, &swap_count ought to work, so don't change that as well.)
As I told in the comments, you are passing the addresses of pointers, which point to an actual value.
With the ampersand prefix (&) you are passing the address of something.
You only use this when you pass a primitive type.
E.g. filling the array by passing an int. But you are passing pointers, so no need to use ampersand.
What's actually happening is that you are looking in the address space of the pointer, not the actual value the pointer points to in the end. This causes various memory conflicts.
Remove all & where you are inputting pointers these lines:
fill_array(&arrayIn, n);
InsertionSort(&arrayIn, n, &swap_count, &compare_count);
print_array(&arrayIn, n, &swap_count, &compare_count);
So it becomes:
fill_array(arrayIn, n);
InsertionSort(arrayIn, n, swap_count, compare_count);
print_array(arrayIn, n, swap_count, compare_count);
I also note that you alloc memory for primitive types, which could be done way simpler:
int compare_count = 0;
int swap_count = 0;
But if you choose to use the last block of code, DO use &swap_count and &compare_count since you are passing primitive types, not pointers!