Quick sort in C — pointers and memory - c

I am a computer science freshman and I still have some difficulties when it comes to pointers. I am trying to implement a quick sort program in C.I currently have 2 errors but I am not able to figure out how to fix it.
On the main function, when I am calling partition, I got an Incompatible pointer types
On the swap function: Thread 1: EXC_BAD_ACCESS (code=1, address=0x200000007)
void swap(int *i, int* j){
*i = *j;
*j = *i;
*i = *j;
}
void partition(int* array[], int size){
int pivot = size;
int i = - 1;
for(int j = 0 ; j < size - 1 ; j++){
if(array[j] < array[pivot]){
i++;
swap(array[i],array[j]);
}
}
}
int main() {
int array[] = {7,2,1,8,6,3,5,4};
int size = sizeof(array)/sizeof(array[0]);
partition(&array,size);
return 0;
}

For starters if an array has N elements then the valid range of indices is [0, N-1]
Thus there is an attempt to access memory beyond the array
int pivot = size;
int i = - 1;
for(int j = 0 ; j < size - 1 ; j++){
if(array[j] < array[pivot])
^^^^^^^
Your function swap does not make sense.
void swap(int *i, int* j){
*i = *j;
*j = *i;
*i = *j;
}
After the first expression statement
*i = *j;
the both objects pointed to by the pointers i and j will have the same value.
The function can be defined the following way.
void swap( int *p, int *q )
{
int tmp = *p;
*p = *q;
*q = tmp;
}
and called like
swap( &array[i], &array[j] );
The function partition is also invalid. Apart from the incorrect used algorithm at least its first parameter is declared also incorrectly.
Instead of
void partition( int* array[], int size );
the function should be declared like
void partition( int *array, int size );
or more correctly like
void partition( int *array, size_t size );
and the function should be called like
int array[] = {7,2,1,8,6,3,5,4};
size_t size = sizeof(array)/sizeof(array[0]);
partition( array,size );
On the other hand, the function partition should return the position that divides the array into two parts. So the final function declaration will look like
size_t partition( int array[], size_t size );
Below there is a demonstrative program that shows how a recursive function quick sort can be written using functions swap and partition.
#include <stdio.h>
void swap( int *p, int *q )
{
int tmp = *p;
*p = *q;
*q = tmp;
}
size_t partition( int a[], size_t n, int pivot )
{
size_t i = 0;
while ( i != n )
{
while ( i != n && a[i] < pivot ) i++;
while ( i != n && !( a[--n] < pivot ) );
if ( i != n ) swap( a + i, a + n );
}
return i;
}
void quick_sort( int a[], size_t n )
{
if ( n != 0 )
{
size_t pos = partition( a, n - 1, a[n - 1] );
swap( a + pos, a + n - 1 );
quick_sort( a, pos );
quick_sort( a + pos + 1, n - pos - 1 );
}
}
int main(void)
{
int a[] = { 7, 2, 1, 8, 6, 3, 5, 4 };
const size_t N = sizeof( a ) / sizeof( *a );
for ( size_t i = 0; i < N; i++ )
{
printf( "%d ", a[i] );
}
putchar( '\n' );
quick_sort( a, N );
for ( size_t i = 0; i < N; i++ )
{
printf( "%d ", a[i] );
}
putchar( '\n' );
return 0;
}
The program output is
7 2 1 8 6 3 5 4
1 2 3 4 5 6 7 8

There are a few problems in here:
The pointer notation has the weird effect that the star comes after the thing it points to, so the int* array[] in partition is an array of pointers to integers, while what you call it with in main is a pointer to an array of integers.
An array[] is actually a pointer by itself (though with some slightl technical differences, but in general something that accepts a pointer will also accept an array). You are mainly using the array in partition as an array of integers (the array[j] < array[pivot] should be a comparison of content, but with an int* array[] it is a comparison of address), so you should change it to just being an int array[]. Note that this will also help with resolving point 1, as you just need to remove the superflous referencing when you call partition.
When you index an array it counts as a dereferencing, so when you call swap(array[i],array[j]) (assuming you have made the corrections suggested above) you are passing ints and not int*s, you need to change it to swap(&array[i],&array[j]).
In swap you are setting both of their values to j's. This happens because the information of what is in i is destroyed when you write over it. There are several ways to handle this, the 2 main ones are saving the information in a temporary variable, and the second is through bit-hacking. Here are 2 examples:
void swap(int *i, int* j){
int temp = *j;
*j = *i;
*i = temp;
}
An a version using exlusive or:
void swap(int *i, int* j){
*i= *j ^ *i;
*j= *j ^ *i;
*i= *j ^ *i;
}

pointers
I wasn't sure if the question was asking about a pointer based quicksort, so here is an example, using Lomuto partition scheme. In the partition loop, it recurses on the smaller part, and loops back for the larger part, limiting stack space to O(log(n)), but worst case time complexity remains at O(n^2).
void QuickSort(int *lo, int *hi)
{
int *pi;
int *pj;
int pv;
int t;
while (lo < hi){
pv = *hi; /* pivot */
pi = lo; /* partition */
for (pj = lo; pj < hi; ++pj){
if (*pj < pv){
t = *pi; /* swap *pi, *pj */
*pi = *pj;
*pj = t;
++pi;
}
}
t = *pi; /* swap *pi, *hi */
*pi = *hi; /* to place pivot */
*hi = t;
if(pi - lo <= hi - pi){ /* recurse on smaller part */
QuickSort(lo, pi-1); /* loop on larger part */
lo = pi+1;
} else {
QuickSort(pi+1, hi);
hi = pi-1;
}
}
}

Related

swapping last element problem in sorting C array

I am trying to write a sorting algorithm using a function that finds the adress of the minimum element in the array:
#include <stdio.h>
int * findMin(int * start,int * end) ///function to return the adress of the smallest array element
{
int *min = start;
int x;
int size = (end - start);
for(x=0; x<size; x++)
{
if (*(start+x)<*min)
min = (start+x);
}
return min;
}
But here in my sort algorithm, since the last element has nothing more to compare itself with, is mistakenly left as it is
void sort(int * start, int * end) ///funtion to sort the array in ascending order
{
int x,temp;
int size = (end - start);
for (x = 0; x <size; x++)
{
if ( *(start+x) > *findMin(start,end))
{
temp = *findMin(start+x,end);
*findMin(start+x,end) = *(start+x);
*(start+x) = temp;
}
}
}
int main()
{
int arr[10]={5,11,3,12,17,25,1,9,14,2};
sort(arr,&arr[9]);
for(int i=0;i<10;i++)
printf("%d ",arr[i]);
printf("\n");
}
How can I correct this?
The expression in this declaration
int size = (end - start);
does not give the exact size of the array. At least you should write
int size = end - start + 1;
However it is not a good idea to pass the pointer to the last element of the array instead of the pointer to the memory after the last element of the array. In this case you can specify an empty range as start is equal to end.
Also if the function accepts two pointers then there is no need to introduce intermediate variables used as indices in loops.
And this code snippet
temp = *findMin(start+x,end);
*findMin(start+x,end) = *(start+x);
*(start+x) = temp;
is very inefficient.
Here is a demonstrative program that shows how the functions can be implemented.
#include <stdio.h>
int * findMin( const int * start, const int * end ) ///function to return the adress of the smallest array element
{
const int *min = start;
if ( start != end )
{
while ( ++start != end )
{
if ( *start < *min ) min = start;
}
}
return ( int * )min;
}
void selection_sort( int *start, int *end ) ///funtion to sort the array in ascending order
{
for ( ; start != end; ++start )
{
int *min = findMin( start, end );
if ( min != start )
{
int tmp = *start;
*start = *min;
*min = tmp;
}
}
}
int main(void)
{
int arr[] = { 5, 11, 3, 12, 17, 25, 1, 9, 14, 2 };
const size_t N = sizeof( arr ) / sizeof( *arr );
for ( const int *p = arr; p != arr + N; ++p )
{
printf( "%d ", *p );
}
putchar( '\n' );
selection_sort( arr, arr + N );
for ( const int *p = arr; p != arr + N; ++p )
{
printf( "%d ", *p );
}
putchar( '\n' );
return 0;
}
The program output is
5 11 3 12 17 25 1 9 14 2
1 2 3 5 9 11 12 14 17 25
But here in my sort algorithm, since the last element has nothing more to compare itself with, is mistakenly left as it is
No, that's at best a misleading characterization. Your findMin() does not specifically compare array elements to their immediate successors, so the fact that *end has no successor is irrelevant. The problem is (in part) simply that you have an off-by-one error, resulting in never comparing *end with *min. That mistake would be harder to make and easier to recognize if you relied more directly on pointer arithmetic and comparisons:
int *findMin(int *start, int *end) {
int *min = start;
// The original code is equivalent to this variant:
// for (int *x = start; x < end; x++) {
// but this is what you need for an inclusive upper bound:
// for (int *x = start; x <= end; x++) {
// or, since initially min == start, this would be even better:
for (int *x = start + 1; x <= end; x++) {
if (*x < *min) {
min = x;
}
}
return min;
}

Recursive selection sort error 11 when ordering big integers

I have to use the recursive selection sort in order to order different arrays of integers.
These arrays are respectively formed by 100, 1000, 10000, 100000, 200000, 500000 items and can be formed by ordered numbers, partially ordered numbers, inverted ordered numbers and random numbers.
After that I have to calculate the time the algorithm took to order the array.
I have to use recursion, It's a homework.
I created a function that generates the array:
typedef enum {ORINATO, INVERS, PARZ_ORDINATO, RANDOM} Ordine;
int *generaArray(int dimensione, Ordine ordine) {
int i, j, n;
int *array = (int*)malloc(dimensione * sizeof(int));
if (!array){
return NULL;
}
switch (ordine){
case ORINATO:
for (i = 0; i < dimensione; i++){
array[i] = i;
} break;
case INVERS:
n =0;
for ( i = dimensione-1; i >= 0 ; i--) {
array[i] = n;
n++;
}break;
case PARZ_ORDINATO:
for (i = 0; i < dimensione/2 ; i++) {
array[i] = i;
}
for (j = i+1; j <dimensione; j++){
n = rand();
array[j] = n;
};break;
case RANDOM:
for ( i = 0; i <= dimensione ; i++) {
array[i] = rand();
}break;
default:
break;
}
return array;
}
And it works like wonders.
Then I have created the recursive selection sort like follows:
void recursiveSelectionSort(int *array, int dim, int start){
int min=0;
if (start >= dim-1){
return;
}
min = findMin(array, start, start+1, dim);
swap(&array[min], &array[start]);
recursiveSelectionSort(array, dim, start+1);
}
int findMin(int *array, int min, int start, int dim){
if(start == dim ){
return min;
}
if (array[start]< array[min]){
min = start;
}
return findMin(array, min, start+1, dim);
}
void swap (int* x, int *y){
int temp = *x;
x = *y;
y = *temp;
}
Now, this as well should work but something clearly isn't. Let's make an example with the implementation, this is what i put in my main:
int main() {
int *array;
clock_t start, end;
double t;
array = generaArray(1000, ORINATO);
start = clock();
recursiveSelectionSort(array, 1000, 0);
end = clock();
t = ((double) (end - start)) / CLOCKS_PER_SEC;
printf("\nIl tempo impiegato per 1000 elementi è: %lf secondi", t);
return 0;
}
This works (but it's slower thank it should be). However if you try and change the dimension from 1000 to 200000 or 500000 it shows error 11.
What is it causing it? I tried everything but it doesn't seem to work.
For starters recursive functions called for large arrays can invoke a stack overflow.
So use non-recursive functions that implement the method selection sort for large arrays.
As for your implementation then for example the function swap has typos.
void swap (int* x, int *y){
int temp = *x;
x = *y;
y = *temp;
}
I think you mean
void swap (int* x, int *y){
int temp = *x;
*x = *y;
*y = temp;
}
All other functions have too many parameters.
For example the function findMin can be declared the following way
size_t findMin( const int *a, size_t n );
and can be also defined as a recursive function (if you decided to write recursive functions then this function can be also recursive)
Here is a demonstrative program that shows how the functions can be defined
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void swap( int *x, int *y )
{
int temp = *x;
*x = *y;
*y = temp;
}
size_t findMin( const int a[], size_t n )
{
if ( n < 2 )
{
return 0;
}
else
{
size_t i = findMin( a + 1, n - 1 ) + 1;
return a[i] < a[0] ? i : 0;
}
}
void recursiveSelectionSort( int a[], size_t n )
{
if ( !( n < 2 ) )
{
size_t i = findMin( a + 1, n - 1 ) + 1;
if ( a[i] < a[0] ) swap( &a[0], &a[i] );
recursiveSelectionSort( a + 1, n - 1 );
}
}
int main(void)
{
enum { N = 15 };
int a[N];
srand( ( unsigned int )time( NULL ) );
for ( size_t i = 0; i < N; i++ )
{
a[i] = rand() % N;
}
for ( size_t i = 0; i < N; i++ )
{
printf( "%d ", a[i] );
}
putchar( '\n' );
recursiveSelectionSort( a, N );
for ( size_t i = 0; i < N; i++ )
{
printf( "%d ", a[i] );
}
putchar( '\n' );
return 0;
}
The program output might look like
11 9 3 5 6 8 2 4 5 3 7 9 2 0 14
0 2 2 3 3 4 5 5 6 7 8 9 9 11 14

Using macro to get the array length inside the struct [duplicate]

This question already has answers here:
How do I determine the size of my array in C?
(24 answers)
Closed 7 years ago.
I have some C code to practice the quick sort. I want to use macro the get the length of the array. The macro works fine in the main() function. But when I use the macro inside the sort function, it does not return the length of array.
Please see the comments inside the code I left.
Also, I want to use struct to create the member function pointer called "sort" and "quick_sort". Any people who are good at c programming gives me some advise if there are some points that I can improve, not matter the syntax, the code format. I feel kind of weird about the sort and quick_sort functions format inside the struct. My purpose is use Array struct to call the functions.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NELEMS(a) (sizeof(a) / sizeof(a[0]))
typedef struct _Array Array;
struct _Array
{
void (*sort)(int* arr);
void (*quick_sort)(int* arr, int l, int r);
};
void sort(int* arr);
void sort(int* arr)
{
// Issues here.
// The len is 2 not 5.
// the macro returns the sizeof arr here is 8, not 20.
int len = NELEMS(arr);
if(len == 0){
return;
}
void quick_sort(int* arr, int l, int r);
quick_sort(arr, 0, len-1);
}
void quick_sort(int* arr, int l, int r)
{
int j;
if(l < r)
{
j = partition(arr, l, r);
quick_sort(arr, l, j - 1);
quick_sort(arr, j+1, r);
}
}
int partition( int* a, int l, int r) {
int pivot, i, j, t;
pivot = a[l];
i = l; j = r+1;
while( 1)
{
do ++i; while( a[i] <= pivot && i <= r );
do --j; while( a[j] > pivot );
if( i >= j ) break;
t = a[i]; a[i] = a[j]; a[j] = t;
}
t = a[l]; a[l] = a[j]; a[j] = t;
return j;
}
void print_array(int* array, int len){
int i;
for(i = 0; i < len; i++)
printf("%d, \n", array[i]);
}
int main(int argc, char const *argv[])
{
int nums[5] = {5, 1, 3, 2, 4};
// len is 20 / 4 = 5. It works fine.
int len = NELEMS(nums);
Array *array = malloc(sizeof(Array));
array->sort = sort;
array->quick_sort = quick_sort;
sort(nums);
print_array(nums, NELEMS(nums));
return 0;
}
The macro works in main because nums is an array, sizeof(nums) gets the size of the array.
However, when it's passed as function argument, it's automatically converted to a pointer. In sort(), sizeof(nums) only gets the size of the pointer.
You could fix it by passing the size of the array explicitly.

Move all values inside vectors in C

i'm writing a code for a project, in which i need to move values inside a vector! For example, i have a completely "null" vector:
[0][0][0][0][0]
Then i will add a value to it's first position: [10][0][0][0][0]!
Ok, now i need to add again a value to the first position, but i cant lose the value already there, i want to move it to the right, like:
[0][10][0][0][0]
To put the new one there: [5][10][0][0][0]
And then do this again, move the 5 and the 10 to the right again, to add a new one in the first, and so on!
I hope i was clear enough!
#EDIT :
Its done guys! Thanks to everyone that tried to help!
The problem was solved using #AkashPradhan function:
void changeposition(int* vetor, unsigned int size, int valor)
{
unsigned int i = size - 1;
for(; i > 0; --i)
vetor[i] = vetor[i-1] ;
vetor[0] = valor ;
}
Thanks #AkashPradhan! The function worked perfectly with my code!
You can use a Linked List and add to the front node or you could use an array and shift the elements by one position for each insertion.
In this case, I would recommend using a Linked List as the insertion routine will not involving moving every element. However if frequent random access to elements in required, use the array approach.
void insert_front(int* array, unsigned int size, int value)
{
unsigned int i = size - 1;
for(; i > 0; --i)
array[i] = array[i-1] ;
array[0] = value ;
}
Note that the routine does not check if you are inserting more elements that the size of the array.
You could implement this as a ring buffer, in which case you don't need to copy the elements all the time. An example of it would be:
typedef struct
{
size_t bufferSize;
size_t currentPos;
int *data;
} ring_buffer;
void init_buffer(ring_buffer *buffer, size_t N)
{
buffer->bufferSize = N;
buffer->currentPos = 0;
buffer->data = malloc(N*sizeof(int));
}
void free_buffer(ring_buffer *buffer)
{
free(buffer->data);
}
void push_buffer(ring_buffer *buffer, int value)
{
++buffer->currentPos;
if (buffer->currentPos >= buffer->bufferSize)
buffer->currentPos = 0;
buffer->data[buffer->currentPos] = value;
}
int get_buffer(ring_buffer *buffer, size_t pos)
{
size_t dataPos = buffer->currentPos + pos;
if (dataPos >= buffer->bufferSize)
dataPos -= buffer->bufferSize;
return buffer->data[dataPos];
}
or you could use a linked list as suggested by #AkashPradhan.
Define your own array, implement push operation, shift right data when push a new element. This implementation would delete the stale element.
typedef struct Array {
int *data;
size_t len; // current size of the array
size_t cap; // capacity of the array
}Array;
Array * new_array (size_t cap_){
Array *arr = (Array *)malloc(sizeof(Array));
arr->cap = cap_;
arr->len = 0;
arr->data = (int*)malloc(sizeof(int) * cap);
return arr;
}
void free_array(Array * arr){
if (arr->data != NULL)
free(arr->data);
free(arr);
}
void push(int x, Array *arr) {
int ptr = std::min(len, cap) - 2;
for(int i = ptr;i >= 0;i --) {
arr->data[ptr + 1] = arr->data[ptr];
}
arr->data[0] = x;
len = std::max(cap, len + 1);
}
Update : You can also use Tamás Szabó 's answer to avoid data movement.
If you need to write the corresponding function yourself then it can look the following way
size_t move( int a[], size_t n )
{
if ( n++ != 0 )
{
for ( size_t i = n; --i != 0; ) a[i] = a[i-1];
}
return n;
}
And you could use it the following way
size_t n = 0;
n = move( a, n );
a[0] = 10;
n = move( a, n );
a[0] = 5;
for ( size_t i = 0; i < n; i++ ) printf( "%d ", a[i] );
printf( "\n" );
Otherwise you have to use standard C function memmove the following way
memmove( a + 1, a, n * sizeof( int ) );
++n;
where n is the current number of actual elements in the array.

2D pointer arithmetic in C

I am attempting to swap 2 elements in a 2D array in C, with no luck.
Thanks for the answers so far, but I have edited this code to make things clearer about what I am doing.
typedef struct smystruct { /* stuff... */ } mystruct;
void nswap( mystruct ** a, mystruct ** b )
{
mystruct * tmp = *a;
*a = *b;
*b = tmp;
}
void nqsort( mystruct ** h, int m, int n )
{
double key = 0.0;
int i = 0, j = 0, k = 0;
if( m < n ) {
// choose the pivot point...
k = (m + n) / 2;
nswap( &h[ n ], &h[ k ] );
key = (*h+m)->prob;
i = m + 1;
j = n;
while ( i <= j ) {
while ( (i <= n) && (*h+i)->prob <= key )
i++;
while ( (j >= m) && (*h+j)->prob > key )
j--;
if ( i < j ) {
nswap( &h[i], &h[j] );
}
}
// swap two elements
nswap( &h[m], &h[j] );
// recursively sort the lesser list
nqsort( h, m, j-1 );
nqsort( h, j+1, n );
}
}
int main()
{
mystruct * p = NULL;
// get the number of nodes (m)...
fscanf( in, "%d", &m );
// allocate memory for the node and connectivity matrix arrays...
p = (mystruct*)malloc( sizeof( mystruct ) * m );
// read in the location and associated probabilities!...
for ( ; loop < m ; ++loop ) {
mystruct * tmpnode = p + loop;
tmpnode->str = (char*)malloc( sizeof( char ) * 1024 );
fscanf( in, "%s %lf", (char *)tmpnode->str, &tmpnode->prob );
}
nqsort( &p, 0, m );
}
Needless to say this does not work. I have searched for examples and nothing seems to work. Advise for the n00b would be appreciated.
The last element has index count-1, not count.
h[0] h[1] h[2] h[3] h[4] h[5] h[6] h[7] h[8] h[9]
----------------------------------------------------------
total 10 elements
I don't know what is fwnodes, perhaps you mean h.
Multiple stuff is wrong there.
1/ Your 2D array is badly allocated (or code is missing).
2/ A proper way to do such 2D allocation is to use Iliffe pointer (as advised in Numrical Recipes in C/C++).
mystruct** alloc_array( int h, int w )
{
int i;
mystruct** m = malloc(h*sizeof(mystruct*));
m[0] = malloc(h*w*sizeof(mystruct));
for(i=1;i<h;i++) m[i] = m[i-1]+w;
return m;
}
void release_array(mystruct** m)
{
free( m[0] );
free( m);
}
This way of allocating brings you both a contiguous block of memory (which is easier to handle, is more cache friendly, dont require to do some index computation) and a [][] access.
Your swap function then become :
void swap( mystruct* a, mystruct* b )
{
mystruct tmp = *a
*a = *b;
*b = tmp;
}
and can be called like :
swap( &some_tab[i][j], &some_other_tab[u][v] );
In a full example :
int main()
{
mystruct** my_array = alloc_array(3,4); /* 3x4 mystruct array */
/* fill the array */
/* Swap some */
swap( &my_array[2][1], &my_array[0][3] );
release_array(my_array);
}
You are passing pointer to array to your function. That means h has only one element.
swap( &p, 10 );
Should be:
swap( p, 10 );
That means you need to change your function to accept arrays of mystruct or change p to array of pointers to mystruct.
And, as KennyTM suggested the last element has index 9 not 10.

Resources