Array access via double pointer, losing its body, pure C - c

When I'm trying to sort array content, which I have referenced via double-pointer.
http://ideone.com/OapPh
line 77
SortQuick(&(*data_resource)->data,
&(*data_resource)->low,
&(*data_resource)->length - 1);
The content hasn't been sorted, via the same method I'm printing values of this array very fine with the function ArrayPrint()
This code compiles well on MS C++ compiler, about GCC don't know.
There are not any warning in the code or errors, MS compiler doesn't show it by standard configuration.

It's not sorting because &(*data_resource)->length - 1 evaluates to &(*data_resource)->low.
&(*data_resource)->length is a pointer to an int. When you subtract 1 from it, it points to the int just before and that happens to be &(*data_resource)->low because you defined the structure members in precisely this order:
typedef struct Resource
{
int low;
int length;
int *data;
} Resource;
So, your sorting code gets 2 identical indices to work with and rightly does not sort anything as there's nothing to sort in a subarray consisting of just one element.
Here's a slightly modified version that works:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Resource
{
int low;
int length;
int *data;
} Resource;
void Swap(int *first, int *second)
{
int tmp = *first;
*first = *second;
*second = tmp;
}
void SortQuick(int **data, int *low, int *high)
{
int i = *low,
j = *high,
x = (*data)[(*low + *high) / 2];
do
{
while((*data)[i] < x) i++;
while((*data)[j] > x) j--;
if(i <= j)
{
Swap(&(*data)[i], &(*data)[j]);
i++;
j--;
}
} while(i <= j);
if(i < *high) SortQuick(data, &i, high);
if(*low < j) SortQuick(data, low, &j);
}
void ArrayPrint(int **data, int *array_length)
{
for(int i = 0; i < *array_length; i++)
{
printf("[%i]: %20i\r\n", i, (*data)[i]);
}
}
void ArrayInit(int **data, int *array_length)
{
(*data) = (int*)malloc(sizeof(int) * *array_length);
for(int i = 0; i < *array_length; i++)
{
(*data)[i] = rand();
}
}
int GlobalInit(Resource **data_resource)
{
srand((unsigned int)rand());
*data_resource = (Resource*)malloc(sizeof(Resource));
(*data_resource)->low = 0;
(*data_resource)->length = 10;//rand();
ArrayInit(&(*data_resource)->data, &(*data_resource)->length);
return (*data_resource)->length;
}
void BenchmarkTest(Resource **data_resource)
{
ArrayPrint(&(*data_resource)->data, &(*data_resource)->length);
(*data_resource)->length--;
SortQuick(&(*data_resource)->data, &(*data_resource)->low, &(*data_resource)->length);
(*data_resource)->length++;
ArrayPrint(&(*data_resource)->data, &(*data_resource)->length);
}
int main(void)
{
Resource *data_resource = NULL;
GlobalInit(&data_resource);
BenchmarkTest(&data_resource);
return 0;
}
Output (ideone):
[0]: 1362961854
[1]: 8891098
[2]: 392263175
[3]: 158428306
[4]: 2074436122
[5]: 47170999
[6]: 431826012
[7]: 1599373168
[8]: 1769073836
[9]: 1043058022
[0]: 8891098
[1]: 47170999
[2]: 158428306
[3]: 392263175
[4]: 431826012
[5]: 1043058022
[6]: 1362961854
[7]: 1599373168
[8]: 1769073836
[9]: 2074436122

All of those references and dereferences of pointers are driving you mad, and in most cases they aren't necessary, try this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Resource
{
int low;
int length;
int *data;
} Resource;
void Swap(int *first, int *second)
{
int tmp = *first;
*first = *second;
*second = tmp;
}
void SortQuick(int *data, int low, int high)
{
int i = low,
j = high,
x = data[(low + high) / 2];
do
{
while(data[i] < x) i++;
while(data[j] > x) j--;
if(i <= j)
{
Swap(&(data[i]), &(data[j]));
i++;
j--;
}
} while(i <= j);
if(i < high) SortQuick(data, i, high);
if(low < j) SortQuick(data, low, j);
}
void ArrayPrint(int *data, int array_length)
{
for(int i = 0; i < array_length; i++)
{
printf("[%i]: %i\r\n", i, data[i]);
}
}
void ArrayInit(Resource *data_resource)
{
data_resource->data = (int*)malloc(sizeof(int) * data_resource->length);
for(int i = 0; i < data_resource->length; i++)
{
data_resource->data[i] = rand();
}
}
Resource* GlobalInit()
{
Resource *data_resource;
srand((unsigned int)rand());
data_resource = (Resource*)malloc(sizeof(Resource));
data_resource->low = 0;
data_resource->length = rand();
ArrayInit(data_resource);
return data_resource;
}
void BenchmarkTest(Resource *data_resource)
{
ArrayPrint(data_resource->data, data_resource->length);
SortQuick(data_resource->data, data_resource->low, data_resource->length - 1);
ArrayPrint(data_resource->data, data_resource->length);
}
int main(void)
{
Resource *data_resource = NULL;
data_resource = GlobalInit();
BenchmarkTest(data_resource);
return 0;
}

This part doesn't make sense:
&(*data_resource)->length - 1);
You are taking the address of the length field and substracting 1. Removing the - 1 seems to make it work.
Besides, you are overusing pointers. E.g. ArrayPrint could simply be
void ArrayPrint(int *data, int array_length)
{
for(int i = 0; i < array_length; i++)
{
printf("[%i]: %i\r\n", i, data[i]);
}
}

Related

having trouble with this c quick sort while using an array struct

The program doesn't crash, the build is successful, and it runs through the rest of main properly. The only problem is that the sort doesn't actually sort the array.
I left out the creation of the array and the rest of main simply because I've already tested them with another sort, and they work properly. However I'm supposed to use a higher level sort so I have to change things.
//struct for the array
typedef double darray_value_t;
typedef struct darray_t_tag {
darray_value_t *data;
size_t size;
size_t capacity;
} darray_t;
//top of main
quickSort(&dataset, 0, dataset.size - 1);
//rest of main
//functions used to for the quick sort
void quickSort(darray_t *dataset, int lowValue, int highValue) {
if (lowValue < highValue) {
int part = partition(dataset, lowValue, highValue);
quickSort(dataset, lowValue, part - 1);
quickSort(dataset, part + 1, highValue);
}
}
darray_value_t partition(darray_t *dataset, int lowValue, int highValue) {
int pivot = dataset->data[highValue];
int i = (lowValue - 1);
for (int j = lowValue; j < highValue; j++) {
if (dataset->data[j] <= pivot) {
i++;
swapValues(&dataset->data[i], &dataset->data[j]);
}
}
swapValues(&dataset->data[i + 1], &dataset->data[highValue]);
return (i + 1);
}
void swapValues(darray_value_t *a, darray_value_t *b) {
darray_value_t temp = *a;
*a = *b;
*b = temp;
}
There are multiple problems in your code:
the return value of partition should be int, not darray_value_t,
conversely, the type of pivot should be darray_value_t, not int.
Here is a modified version:
#include <stdio.h>
//struct for the array
typedef double darray_value_t;
typedef struct darray_t_tag {
darray_value_t *data;
size_t size;
size_t capacity;
} darray_t;
void swapValues(darray_value_t *a, darray_value_t *b) {
darray_value_t temp = *a;
*a = *b;
*b = temp;
}
int partition(darray_t *dataset, int lowValue, int highValue) {
darray_value_t pivot = dataset->data[highValue];
int i = lowValue;
for (int j = lowValue; j < highValue; j++) {
if (dataset->data[j] <= pivot) {
swapValues(&dataset->data[i++], &dataset->data[j]);
}
}
swapValues(&dataset->data[i], &dataset->data[highValue]);
return i;
}
//functions used to for the quick sort
void quickSort(darray_t *dataset, int lowValue, int highValue) {
if (lowValue < highValue) {
int part = partition(dataset, lowValue, highValue);
quickSort(dataset, lowValue, part - 1);
quickSort(dataset, part + 1, highValue);
}
}
int main() {
darray_value_t arr[] = { 2.0, 1.5, 4.5, -1 };
darray_t dataset = { arr, 4, 4 };
quickSort(&dataset, 0, dataset.size - 1);
for (size_t i = 0; i < dataset.size; i++) {
printf(" %g", dataset.data[i]);
}
printf("\n");
return 0;
}

How do you make a FIFO array in C

I need an array with a limited size where I can push ints in.
Once the array is full the last one in the array needs to go out so there is a new spot in front so I can keep adding data. How can you do this in C?
this should be a reasonable implementation
#include <stdio.h>
#include <stdlib.h>
struct int_queue{
int *arr;
size_t size;
int len;
int first_elem;
};
void init_int_queue(struct int_queue *queue, size_t nelems)
{
queue->arr = malloc(nelems*sizeof(int));
queue->first_elem = 0;
queue->len = 0;
queue->size = nelems;
}
void destroy_int_queue(struct int_queue *queue)
{
free(queue->arr);
}
void push_int(struct int_queue *queue, int new_val)
{
queue->arr[(queue->first_elem + (queue->len)++) % queue->size] = new_val;
if (queue->len > queue->size){
queue->len--;
queue->first_elem++;
queue->first_elem %= queue->size;
}
}
int get_int(struct int_queue *queue, int index)
{
// note does not handle the case for index out of bounds
// wraps around for overflow
return queue->arr[(queue->first_elem + index) % queue->size];
}
void print_int_queue(struct int_queue *queue)
{
printf("[");
for(int i = 0; i < queue->len; ++i){
printf("%d", queue->arr[(queue->first_elem + i) % queue->size]);
if(i < queue->len - 1)
printf(", ");
}
printf("]\n");
}
int main(int argc, char *argv[])
{
struct int_queue queue;
init_int_queue(&queue, 100);
for(int i = 0; i < 150; ++i){
push_int(&queue, i);
}
print_int_queue(&queue);
destroy_int_queue(&queue);
return 0;
}
Not extensively tested but it's simply wrapping around the array everytime a new element is added, keeping track of the first element shifting if the length exceeds the size.

Sorting one array and copying the order over to another

I have two arrays side by side, one lists the different teams and the other lists the scores. I am able to sort the order of scores in descending order. Can this order then be used to move the corresponding team to the correct position of the leader board? eg. move the two teams with 100 points (USA and Germany) to the top of the board
#include <stdio.h>
int main()
{
char teams[18][20]={"England","Ireland","Wales","Scotland","France","Italy","Germany","Uraguay","Belgium","USA","Mexico","Australia","Belize","Denmark","Sweden","Japan","South Africa","Algeria"};
int points[18]={43,5,77,23,89,0,100,46,94,100,45,55,32,65,11,37,26,78};
int i;
int j;
int a;
for (i = 0; i < 18; ++i)
{
printf("%i ",i+1);
printf("%s",teams[i]);
printf("\t%d\n", points[i]);
}
printf("\n");
for (i = 0; i < 18; ++i)
{
for (j = i + 1; j < 18; ++j)
{
if (points[i] < points[j])
{
a = points[i];
points[i] = points[j];
points[j] = a;
}
}
}
for (i = 0; i < 18; ++i)
{
printf("%i ",i+1);
printf("%s",teams[i]);
printf("\t%d\n", points[i]);
}
return 0;
}
As mentioned in a comment, the typical solution is to model your data as an array of structures, rather than separate arrays. This makes sense, since the data is associated with each other.
You'd have something like:
struct score {
const char *name;
int points;
} scores[] = {
{ "England", 43 },
{ "Ireland", 5 },
/* and so on */
};
Then you can use qsort() (or your own sorting code, if that's of interest) to sort entire structure instances, and the all the data will remain together since entire structures are being moved around.
Also arrange your teams array when sorting;
a = points[i];
b = teams[i];
points[i] = points[j];
teams[i] = teams[j];
points[j] = a;
teams[j] = b;
The obvious way (as pointed out by others) is embedding your arrays into a struct, but if you are forced to use parallel arrays you can build your own function and sort both arrays at once:
#include <stdio.h>
static int comp(const void *a, const void *b)
{
return *(int *)a - *(int *)b;
}
static void swap(int v1[], char *v2[], int a, int b)
{
int temp1;
char *temp2;
temp1 = v1[a];
v1[a] = v1[b];
v1[b] = temp1;
temp2 = v2[a];
v2[a] = v2[b];
v2[b] = temp2;
}
static void sort(int v1[], char *v2[], int left, int right, int (*comp)(const void *, const void *))
{
int i, last;
if (left >= right) return;
swap(v1, v2, left, (left + right) / 2);
last = left;
for (i = left + 1; i <= right; i++) {
if (comp(&v1[i], &v1[left]) < 0)
swap(v1, v2, ++last, i);
}
swap(v1, v2, left, last);
sort(v1, v2, left, last - 1, comp);
sort(v1, v2, last + 1, right, comp);
}
int main(void)
{
char *teams[] = {"England","Ireland","Wales","Scotland","France","Italy","Germany","Uraguay","Belgium","USA","Mexico","Australia","Belize","Denmark","Sweden","Japan","South Africa","Algeria"};
int points[] = {43,5,77,23,89,0,100,46,94,100,45,55,32,65,11,37,26,78};
size_t i, n = sizeof(points) / sizeof(*points);
sort(points, teams, 0, n - 1, comp);
for (i = 0; i < n; i++) {
printf("%s->%d\n", teams[i], points[i]);
}
return 0;
}
Output:
Italy->0
Ireland->5
Sweden->11
Scotland->23
South Africa->26
Belize->32
Japan->37
England->43
Mexico->45
Uraguay->46
Australia->55
Denmark->65
Wales->77
Algeria->78
France->89
Belgium->94
Germany->100
USA->100

Returning merged arrays from function in C

I have the following code:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef struct _item {
int v, w;
} item;
void printItems(item *t, int n) {
int i;
for(i= 0; i < n; i++)
printf("%4i",t[i].v);
printf("\n");
}
item * newItemSet(int n) {
int i;
item *t = (item*)malloc(sizeof(item));
for (i = 0; i < n; i++){
(t+i)->v = rand()%100;
(t+i)->w = rand()%100;
}
return t;
}
item * mer(item*a, int n, item*b, int m) {
int size = m+n;
item*q = (item*)malloc(sizeof(item)*size);
int i, c;
c = 0;
printf("a----\n");
printItems(a,n);
printf("b----\n");
printItems(b,m);
for(i = 0; i<n; i++) {
q[c] = a[i];
c++;
}
for(i = 0; i<m; i++) {
q[c] = b[i];
c++;
}
printItems(q,size);
return q;
}
int main(void) {
srand(time(NULL));
item * a = newItemSet(6);
item *b = newItemSet(6);
item *c = mer(a,6,b,6);
printItems(c,12);
return 0;
}
At every execution, the first part of c is correct, up to the last two elements of b. What did I miss?
The allocation for newItemSet does not appear correct. It should be:
item *t = malloc(sizeof(item) * n);
item *t = (item*)malloc(sizeof(item));
Should be:
item *t = malloc(n * sizeof(item));
You are allocating space for n items, not one item. Also, there is no need to cast the return value of malloc and it can hide errors.

segfault in merge sort implementation

I'm working on a C implementation as an exercise (I'm a student). I have the logic fine (I've used the implementation itself before), but I get a segfault when actually running it. I've looked for a long time, and I can't understand what's causing it. Here is my complete code:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ARRAY_CAPACITY 50
void do_sort(int* list);
void merge_sort(int* list_of, int* buffer_of, int start, int end);
void do_sort(int* list)
{
int capacity = ((ARRAY_CAPACITY) / 2);
int buffer[capacity];
merge_sort(list, buffer, 0, ARRAY_CAPACITY);
}
void merge_sort(int* list_of, int* buffer_of, int start, int end)
{
printf("%s", "hi!");
int i, t;
if((end - start) < 2) return;
int mid = (start + end) / 2;
merge_sort(list_of, buffer_of, start, mid);
merge_sort(list_of, buffer_of, mid, end);
int left = 0;
int right = mid;
for(i = 0; i < ARRAY_CAPACITY; i++)
{
buffer_of[i] = list_of[i];
}
for(t = start; t < end; t++)
{
if((left < (mid - start)) && (right == end || buffer_of[left] < list_of[right]))
{
list_of[t] = buffer_of[left];
left++;
}
else
{
list_of[t] = list_of[right];
right++;
}
}
}
int main()
{
srand(time(NULL));
int number_array[ARRAY_CAPACITY];
int i;
for(i = 0; i < ARRAY_CAPACITY; i++)
{
number_array[i] = (rand() % 100);
}
printf("%d\n", number_array[3]);
int j, m;
printf("%s\n", "Pre-Sorted Array: ");
for(j = 0; j < ARRAY_CAPACITY; j++)
{
printf("%d ", number_array[j]);
}
do_sort(number_array);
for(m = 0; m < ARRAY_CAPACITY; m++)
{
printf("%d ", number_array[m]);
}
printf("\n");
}
The output is as follows:
50 (this is a random number, but it always prints successfully)
Pre-Sorted Array:
Segmentation fault
So the segfault triggers when I try to loop to print the pre sorted array, but I've just proven that the array values were properly set, so I can't fathom this error. Help?
You have the following code:
void merge_sort(int* list_of, int* buffer_of, int start, int end)
{
...
for(i = 0; i < ARRAY_CAPACITY; i++)
{
buffer_of[i] = list_of[i];
}
...
That code will get called, at one point, with the following arguments:
list_of is an array of 50 integers.
buffer_of is an array of 25 integers.
start is 0.
end is 50.
You will copy 50 elements of list_of into buffer_of, but buffer_of has only room for 25 elements.

Resources