K&R Quicksort issue - c

I seem to be having a problem understanding where the issue is in the qsort implementation by K&R (C Programming Language second edition).
void qsort_1(int v[], int left, int right)
{
int i, last;
void swap(int v[], int i, int j);
if (left >= right)
return;
swap(v, left, (left + right)/2);
last = left;
for (i = left + 1; i <= right; i++)
if (v[i] < v[left])
swap(v, ++last, i);
swap(v, left, last);
qsort_1(v, left, last-1);
qsort_1(v, last+1, right);
}
This is their version, I only renamed it to qsort_1 so that I could use the built in one at the same time.
int arr_len = 9;
int main() {
int a[] = { 5, 5, 4, 6, 3, 7, 8, 13, 17 };
int b[] = { 5, 5, 4, 6, 3, 7, 8, 13, 17 };
print_a(a, arr_len); // print first array
print_a(b, arr_len); // print second array
putchar('\n'); // space
qsort(b, arr_len, sizeof(int), cmpfunc); // sort second array with standard qsort
qsort_1(a, 0, arr_len); // sort first array with K&R qsort
print_a(a, arr_len); // print first array
print_a(b, arr_len); // print second array
return 0;
}
print_a is a mini function for displaying an array, just one for loop.
qsort is the official standard implementation.
The output I get is:
gcc -O2 -lm -o qsort qsort.c
5 5 4 6 3 7 8 13 17
5 5 4 6 3 7 8 13 17
0 3 4 5 5 6 7 8 13
3 4 5 5 6 7 8 13 17
There seems to be a leading 0 and the last element is removed in the K&R qsort everytime. ...Help
void print_a(int a[], int len) {
for (int i = 0; i < len; i++) {
printf("%d ", a[i]);
}
printf("\n");
}
int cmpfunc (const void * a, const void * b) {
return ( *(int*)a - *(int*)b );
}
If needed, here are the cmpfunc and print_a.
Tried googling the problem but no one seemed to have the same issue.
EDIT:
The code changed in the main function:
int main() {
int a[] = { 5 , 5 ,4 ,6 ,3 ,7 ,8, 13, 17 };
int b[] = { 5 , 5 ,4 ,6 ,3 ,7 ,8, 13, 17 };
print_a(a, arr_len);
print_a(b, arr_len);
putchar('\n');
qsort(b, arr_len, sizeof(int), cmpfunc);
qsort_1(a, 0, **arr_len - 1**);
print_a(a, arr_len);
print_a(b, arr_len);
return 0;
}

When in doubt, look at the code you wrote.
We can assume for a moment that K&R knew what they were doing.
We can further assume that the authors of qsort in the standard library knew what they were doing as well.
Therefore, the first places we should look at what you authored. So what did you really author. The print function, the qsort comparator, and basically everything in main. A quick review reveals:
print_a is certainly ok, provided the base address and length are valid (and they are in this usage case), so that's out.
The qsort comparator seems correct, since (a) it works, and (b) it has nothing to do with questionable output from a totally unrelated function, qsort_1. So that's out.
That leaves only main. Within that function we have:
int main()
{
int a[] = { 5, 5, 4, 6, 3, 7, 8, 13, 17 };
int b[] = { 5, 5, 4, 6, 3, 7, 8, 13, 17 };
print_a(a, arr_len); // print first array
print_a(b, arr_len); // print second array
putchar('\n'); // space
qsort(b, arr_len, sizeof(int), cmpfunc); // sort second array with standard qsort
qsort_1(a, 0, arr_len); // sort first array with K&R qsort
print_a(a, arr_len); // print first array
print_a(b, arr_len); // print second array
return 0;
}
From this:
The array declarations are certainly ok.
The print_a calls check out ok (base address and length are valid).
The call to qsort is unrelated, and obviously ok.
That leave only one line of code in this entire program that could be the culprit:
qsort_1(a, 0, arr_len); // sort first array with K&R qsort
Checking the algorithm, the K&R function expects:
The array base address (ok)
The first index in the partition to sort, in this case 0. (ok)
The last index in the partition to sort. Um...
That's the problem. arr_len is not the last index. It is the length of the sequence. Since arrays in C are 0-index based, the last index is therefore arr_len-1, not arr_len.
Fix that:
qsort_1(a, 0, arr_len-1);
And the code will work as-expected.

Related

I have to reverse the array [1,2,3,4,5,6,7] and i am stuck

#include <stdio.h>
int reverse(int *prr, int i)
{
for (i = 6; i; i--)
{
printf("%d is reverse \n", *prr + i);
}
}
int main()
{
int arrr[] = {1, 2, 3, 4, 5, 6, 7};
int *ptr = arrr;
reverse(ptr, 6);
return 0;
}
The output I am getting is
7 is reverse
6 is reverse
5 is reverse
4 is reverse
3 is reverse
2 is reverse
but not 1!
The loop condition i is equivalent to i != 0 (and for your specific use-case i > 0).
That is, the loop will end when the i reaches 0, so that index will not be printed.
To be able to print the last element, you need to include it in the loop with a condition like i >= 0.
While the off-by-1 question has been answered already, a slightly more idiomatic C way to write it would be to pass the array count as an argument (instead of count-1), and use pointer arithmetic (instead of indexing).
void reverse(int *prr, int i)
{
for (prr += i; i--; )
{ printf("%d is reverse \n", *--prr); }
}
int main()
{
int arrr[] = {1, 2, 3, 4, 5, 6, 7};
reverse(arrr, sizeof(arrr) / sizeof(arrr[0]));
return 0;
}
You have a couple of different ways to write the function. Though as #dxiv pointed out in your comments you want *(prr + i) instead of *prr + i (which by happy mistake just happened to output the same numbers corresponding the elements 1 - 7)
When you want to access a specific element from an array, you options are *(ptr + index) which is equivalent to ptr[index] (or for that matter index[ptr]).
Whenever you need to loop a certain number of times, you can simply decrement the counter, e.g.
#include <stdio.h>
void reverse (int *prr, size_t nelem)
{
while (nelem--)
printf ("%d is reverse\n", *(prr + nelem));
}
int main()
{
int arrr[] = {1, 2, 3, 4, 5, 6, 7};
reverse (arrr, sizeof arrr/sizeof *arrr);
}
Another approach for reversal is a recursive function, e.g.
void reverse (int *prr, size_t nelem)
{
if (nelem) {
printf ("%d is reverse\n", *(prr + nelem - 1));
reverse (prr, nelem - 1);
}
}
or even
void reverse (int *prr, size_t nelem)
{
printf ("%d is reverse\n", *(prr + --nelem));
if (nelem)
reverse (prr, nelem);
}
Example Use/Output
The output of all are equivalent, e.g.:
$ ./bin/reverse_arr_fn
7 is reverse
6 is reverse
5 is reverse
4 is reverse
3 is reverse
2 is reverse
1 is reverse

Having trouble in how to modify a single specific call to function

I've been having some problems in understanding what I exactly have to do here:
1 #include <stdio.h>
2 define N 10
3
4 int f(int *, int );
5
6 int main (void) {
7 int a[] = {11, 4, 3, 41, 15, 12, 4, 2, 8, 33};
8 printf ("%d\n", f(a, N) );
9 }
10
11 int f(int *a, int n) {
12 int i, m;
13 m = a[0];
14 for (i = 1; i < n; i++)
15 if (a[i] > m) m = a[i];
16 return m;
17 }
It's asking me to modify ONLY line 8 (can't modify anything else) so that the function f will be executed only in the second part of the array (as in, from 12 to 33).
I've tried to come up with a solution for a long time but to no avail.
Help would be much appreciated.
Thanks in advance!
Take into account that an array passed to a function as an argument is implicitly converted to pointer to its first element.
In general you can pass to your function a pointer pointing to any element of the array. To do so you can use the pointer arithmetic.
The element with the value 12 is the sixth element of the array that is it can be obtained like a[5]. So you can write either like
printf ("%d\n", f( &a[5], N - 5) );
or like
printf ("%d\n", f( a + 5, N - 5) );
Or if you need to do the task for a half of the array then you can write
printf ("%d\n", f( &a[N / 2], N - N /2) );
or
printf ("%d\n", f( a + N / 2, N - N / 2) );
Replace the line 8 by
printf ("%d\n", f(a+5, N/2) );
Reason:
6th element inside the array is stored at index 5 i.e. a[5]
and a[5]=*(a+5)
So we need to pass a+5 without de-referencing it. And size is 10 so N/2 would mean 5.
Inside the function you actually start from 6th element and iterate through next 5 elements as n is 5.

incompatible pointer types passing int[5][5] to parameter of type int**

why this error(picture 1) happened when I want to input a 2d array to a function?
#include <stdio.h>
#include <stdlib.h>
void pr(int** a){
printf("%d", a[0][0]);
}
int main(){
int a[5][5]={{1,4,7,11,15},{2,5,8,12,19},{3,6,9,16,22},{10,13,14,17,24},{18,21,23,26,30}};
pr(a);
}
The core problem is that arrays and pointers are not the same (albeit they are closely related), and a 2D array is not an array of pointers.
This code shows three ways to fix up the problem. The array a0 is your array renamed and reformatted; the array a is an array of pointers, and each pointer is a pointer to an array of 5 int via a 'compound literal', a feature added to C99. I've upgraded the printing function to print all 25 elements of the array that is passed to it — and created two new printing functions with different interfaces that also print the entire array passed to them. I assume the array is square; a rectangular (non-square) matrix can be readily handled, especially by a variant on pr1() such as pr2(int n, int m, int a[n][m]) — which is almost identical to pr1() but needs a single adjustment internally to test j against m instead of n.
#include <stdio.h>
static void pr0(int a[][5]);
static void pr1(int n, int a[n][n]);
static void pr(int **a)
{
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 5; j++)
printf("%3d", a[i][j]);
putchar('\n');
}
putchar('\n');
}
int main(void)
{
int a0[5][5] =
{
{ 1, 4, 7, 11, 15 },
{ 2, 5, 8, 12, 19 },
{ 3, 6, 9, 16, 22 },
{ 10, 13, 14, 17, 24 },
{ 18, 21, 23, 26, 30 },
};
int *a[] =
{
(int[]){ 1, 4, 7, 11, 15 },
(int[]){ 2, 5, 8, 12, 19 },
(int[]){ 3, 6, 9, 16, 22 },
(int[]){ 10, 13, 14, 17, 24 },
(int[]){ 18, 21, 23, 26, 30 },
};
pr(a);
pr0(a0);
pr1(5, a0);
return 0;
}
static void pr0(int a[][5])
{
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 5; j++)
printf("%3d", a[i][j]);
putchar('\n');
}
putchar('\n');
}
static void pr1(int n, int a[n][n])
{
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
printf("%3d", a[i][j]);
putchar('\n');
}
putchar('\n');
}
The sample output is wonderfully uniform:
1 4 7 11 15
2 5 8 12 19
3 6 9 16 22
10 13 14 17 24
18 21 23 26 30
1 4 7 11 15
2 5 8 12 19
3 6 9 16 22
10 13 14 17 24
18 21 23 26 30
1 4 7 11 15
2 5 8 12 19
3 6 9 16 22
10 13 14 17 24
18 21 23 26 30
The three blocks are the same. Given a choice, I'd use the technique in pr1(), using VLAs (variable length arrays) in the interface. If you must stick with the int ** argument, you must stick with the array a, or something quite similar. There are certainly other ways to create that. For example:
int *a[] = { a0[0], a0[1], a0[2], a0[3], a0[4] };
Arrays and pointers can not be used interchangeably in all possible use cases, and you just happened to stumble into one of them. At times, an int array can be implicitly converted into a pointer, and at times it, well, shouldn't be.
In your case, implicitly (or explicitly) converting a to an (int **) would not work, simply because a points to the first element in your 2d array when considered as a pointer. Converting a to an int ** would make pr lose the information on a being an array. Consequently, handling it as a typical (int **) in pr and trying to dereference it twice would cause the first element in a (a[0][0] = 1) to be handled as an address and the value in that address would be looked up, which I believe is not the desired behavior of pr().
Ideally, you should declare pr in a way that takes a 2D array as a parameter, not an int **. A declaration of pr with the mentioned fix is given below.
void pr(int a[][5]){
printf("%d", a[0][0]);
}
Now, you mention in the comments to your question that the definition of pr can not be modified. In order not to modify pr(), you would have to change the data structure you have in main to something similar to the one given below.
int main(){
int a0[5]={1,4,7,11,15};
int a1[5]={2,5,8,12,19};
int a2[5]={3,6,9,16,22};
int a3[5]={10,13,14,17,24};
int a4[5]={18,21,23,26,30};
int *a[5] = {a0, a1, a2, a3, a4};
pr(a);
}
Note that the sample above is not the most syntactically concise way to achieve your goal. Also, check here to see this usage at work.

How to pass unbound multidimensional array?

Is there any way to pass a multidimensional array to a function without knowing the no of columns.... I mean say I want to print a multidimensional array say a[][9] and b[][3]. If I make a common function say print.
// I have to specify the no of columns right and since
// the no of columns should be same for both actual and
// formal arguments
void print(int a[][])
I have to make different functions for different multidimensional arrays. There should be some way around it.
How to pass unbound multidimensional array?
You have to include all of the array dimensions, except the innermost one (although you probably do want to give the innermost one anyway, so that your function knows when to stop printing). If the dimension is not known at compile time then you can make it a parameter to the function:
void print(size_t m, size_t n, int a[m][n])
{
for ( size_t i = 0; i < m; ++i )
for ( size_t j = 0; j < n; ++j )
printf("%d\n", a[i][j]);
}
Calling the function:
int main(void)
{
int a[][4] = { { 0, 1, 2, 3 }, {8, 7, 6, 5}, {11, 10, 12, 9} };
print(3, 4, a);
return 0;
}
Matt McNabb's answer shows how to use the C99 or C11 variable-length array facilities. There is an alternative that will work with C89 too (which might be a factor if you code on Windows with MSVC), but you still have to tell the function about both dimensions of the array, and you have to do the subscript calculations yourself:
void print(size_t m, size_t n, int *a)
{
size_t i;
size_t j;
for (i = 0; i < m; i++)
{
for (j = 0; j < n; j++)
printf(" %d", a[i * n + j]);
putchar('\n');
}
}
You might call this as:
int main(void)
{
int a[][4] = { { 0, 1, 2, 3 }, {8, 7, 6, 5}, {11, 10, 12, 9} };
print(3, 4, &a[0][0]);
return 0;
}
Sample output:
0 1 2 3
8 7 6 5
11 10 12 9
(One minor comment: I'm not certain that the automatic array could be initialized like that in C89 — there were some restrictions still on automatic variable initialization. If it doesn't work, simply move the entire array declaration outside of main() and prefix it with static so it becomes a file scope array.)

Variadic Adding Function C

I'm writing a simple variadic function that adds together a series of ints and returns the sum. I'm having a bit of trouble understanding how it works and my code doesn't seem to work though I feel I'm in the right direction with my code. (Posted below) The specifications of this function are that it takes at least one param and the last param is always a zero (as seen called in the main). I was also told, based upon my machine, that I wouldn't necessarily get the output I'm looking for which, as you could imagine, further complicates my situation. Some assistance with correcting my Sum() function would be greatly appreciated.
EDIT:
This is supposed to be done w/o the use of stdarg.h header and thus no va_arg functions.
int Sum(int a, ... ) {
int sum = 0, *addy = &a;
while (*addy) {
sum += *addy;
addy += sizeof(a);
}
return sum;
}
int main() {
printf("%d %d %d %d\n", Sum(0), Sum(3, 5, 6, 7, 0),
Sum(7, 2, 42, 3, 5, -4, 0), Sum(-1, 9, 12, 123, -213, 42, 7, 2, 0));
}
//Expected output: 0 21 55 -19
//My output: 0 32770 32770 32776
When you add a number to an int pointer (as in addy += sizeof(a)) the number you add is automatically multiplied by the size of whatever type the pointer is declared as (in this case int). To fix this, just use
addy += 1;
instead. However, I would recommend using variadic macros instead of this method, they are clearer and less error prone.
for variable arguments, you have to use va_start and va_end functions, hope useful..
http://www.gnu.org/software/libc/manual/html_node/Variadic-Example.html#Variadic-Example
Can you please check this
int Sum(int a, ... ) {
int sum = 0, *addy = &a;
while (*addy) {
sum += *addy;
addy ++;
}
return sum;
}
int main() {
printf("%d %d %d %d\n", Sum(0), Sum(3, 5, 6, 7, 0),
Sum(7, 2, 42, 3, 5, -4, 0), Sum(-1, 9, 12, 123, -213, 42, 7, 2, 0));
}
Point to remember is for pointer operations: the number you are adding to the pointer will be multiplied by the size of the type that the pointer is pointing to. So incrementing the pointer addy is enough for geting the next element.
#include <stdarg.h>
#include <stdio.h>
int
add_em_up (int count,...)
{
va_list ap;
int i, sum;
va_start (ap, count); /* Initialize the argument list. */
sum = 0;
for (i = 0; i < count; i++)
sum += va_arg (ap, int); /* Get the next argument value. */
va_end (ap); /* Clean up. */
return sum;
}
int
main (void)
{
/* This call prints 16. */
printf ("%d\n", add_em_up (3, 5, 5, 6));
/* This call prints 55. */
printf ("%d\n", add_em_up (10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
return 0;
}

Resources