Swapping two structs from an array of structs (bubblesort) - c

I have a struct which holds 3 integers each resembling the size of one side of a triangle:
struct triangle{
int a; int b; int c;
};
typedef struct triangle tri;
I firstly need to read the number of triangles to come (n). Then I read 3 sides of n triangles and sort them by the area of triangles in order from smallest to largest.
Now my idea was to compare the areas with each other and if the former area is larger than the later, I swap the corresponding structures. In the end, the values of structs (sides) will be printed out as an output from smallest to largest.
I am stuck with swapping the structures. So far I have done this:
void swap(tri *a, tri *b)
{
tri t;
t = *a;
*a = *b;
*b = t;
}
void sort_by_area(tri *tr, int n)
{
int sorted, storage[n];
for(int i = 0; i <= n-1; i++)
{
storage[i] = give_area(&tr[i]);
}
do
{
sorted = 1;
for(int i = 0; i < n-1; i++)
{
if(storage[i] > storage[i+1])
{
/*swap(tr[i].a, tr[i+1].a);
swap(tr[i]->b, tr[i+1]->b);
swap(tr[i]->c, tr[i+1]->c);*/
/*the commented section was my another attempt in which I would change the swap inputs to swap(int a, int b) or swap(int *a, int *b)*/
swap(&tr[i], &tr[i+1]);
sorted = 0;
}
}
}while(!sorted);
}
I'm sure I'm definitely completely wrong with putting the structs in.
If one needs more, here is my main function:
int main()
{
int n;
scanf("%d\n", &n);
tri *tr = malloc(n*(sizeof(tri)));
for(int i = 0; i < n; i++){
scanf("%d %d %d", &tr[i].a, &tr[i].b, &tr[i].c);
}
sort_by_area(tr, n);
for(int i = 0; i < n; i++){
printf("\n%d %d %d", tr[i].a, tr[i].b, tr[i].c);
}
free(tr);
return 0;
}
From my investigation the code works properly, I think the main issue lies either within the swap function, or the nested (for/if) loop in which the swap function is run.

The swap method is fine. There is a logical error in your approach though.
You compare the storage (the areas), and if the comparison is true, you swap the triangles, but not the areas. As a result, the i-th triangle does not correspond anymore to the i-th storage necessarily.
You need to swap the areas too, when their respective triangles are swapped, like this:
(I used double to store the areas, but you could still use int for it, by losing in precision)
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
struct triangle{
int a; int b; int c;
};
typedef struct triangle tri;
void swap(tri *a, tri *b)
{
tri t;
t = *a;
*a = *b;
*b = t;
}
void swap_double(double *a, double *b)
{
double tmp = *a;
*a = *b;
*b = tmp;
}
// Heron's formula
double give_area(struct triangle *tr)
{
double t = (tr->a + tr->b + tr->c)/2.0; /* Compute half of the perimeter */
return sqrt(t * (t - tr->a) * (t - tr->b) * (t - tr->c)); /* Return area */
}
void sort_by_area(tri *tr, int n)
{
int sorted;
double storage[n];
for(int i = 0; i <= n-1; i++)
{
storage[i] = give_area(&tr[i]);
}
do
{
sorted = 1;
for(int i = 0; i < n-1; i++)
{
if(storage[i] > storage[i+1])
{
swap(&tr[i], &tr[i+1]);
// Swap the areas too!!!
swap_double(&storage[i], &storage[i + 1]);
sorted = 0;
}
}
}while(!sorted);
}
int main(void)
{
int n;
scanf("%d\n", &n);
tri *tr = malloc(n*(sizeof(tri)));
for(int i = 0; i < n; i++){
scanf("%d %d %d", &tr[i].a, &tr[i].b, &tr[i].c);
}
sort_by_area(tr, n);
for(int i = 0; i < n; i++){
printf("\n%d %d %d", tr[i].a, tr[i].b, tr[i].c);
}
free(tr);
return 0;
}
Compile like this:
gcc main.c -Wall -Wextra -lm
./a.out
Input:
2
7 8 9
4 5 6
Output:
4 5 6
7 8 9
Debug-Tip: As #alk mentioned, when you are uncertain about the correctness of a specific method, write a laconic program to test that method (a minimal complete verified example (MCVE), as we tend to say here in Stack Overflow).

The problem with the code is that the auxiliary array storage stays unchanged when structure elements are swapped.
In fact there is no need to have this auxiliary array. Without it you could just write
if( give_area(&tr[i] ) > give_area( &tr[i+1] ) )
Otherwise you have to add one more swap function like
void swap_storage(int *a, int *b)
{
int t = *a;
*a = *b;
*b = t;
}
and use it together with the already defined function swap
swap(&tr[i], &tr[i+1]);
swap_storage( &storage[i[, ^storage[i+1[ );

Related

Core keeps dumping when trying to reverse array using a function to swap values of 2 pointers

#include<stdio.h>
int main() {
/* read integer array */
int n, i;
scanf("%d", &n);
int *a = (int *)malloc(n * sizeof(int));
for (i = 0; i < n; i++) {
scanf("%d", &a[i]);
}
/* reverse the array */
for (i = 0; i < n / 2; i++) {
exchange(a[i], a[n - i - 1]);
}
/* print the array */
for (i = 0; i < n; i++) {
printf("%d ", a[i]);
}
/* free the memory */
free(a);
return;
}
/* write a function that takes two pointers of two intergers and then exchanges the values
in those locations */
void exchange(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
This is the code, the function exchange tries to exchange the values of the integers which these two pointers are pointing to.
Keeps dumping the core.
In this call of the function exchange
exchange(a[i], a[n - i - 1]);
the both arguments have the type int while the function expects arguments of the type int *.
You need to call the function like
exchange( a + i, a + n - i - 1);
You need to send address values for exchange functions since arguments of it are declared as pointers. Therefore, you need to change this line
exchange(a[i], a[n - i - 1]);
to this line because as I mentioned it expects addresses.
exchange(&a[i], &a[n - i - 1]);
A nicer way would be passing the whole array and indexes to swap.
Like this: TRY IT ONLINE
#include<stdio.h>
#include <stdlib.h>
void exchange(int **arr, int n1, int n2);
int main() {
/* read integer array */
int n, i;
scanf("%d", &n);
int *a = (int *)malloc(n * sizeof(int));
for (i = 0; i < n; i++) {
scanf("%d", &a[i]);
}
/* reverse the array */
for (i = 0; i < n / 2; i++) {
exchange(&a, i, n - i - 1);
}
/* print the array */
for (i = 0; i < n; i++) {
printf("%d ", a[i]);
}
/* free the memory */
free(a);
return 0;
}
/* write a function that takes two pointers of two intergers and then exchanges the values
in those locations */
void exchange(int **arr, int n1, int n2) {
int temp = (*arr)[n1];
(*arr)[n1] = (*arr)[n2];
(*arr)[n2] = temp;
}

Can somone please explain this to me

For n=3 and a={1,2,3},b={4,5,6} its supposed to calculate 1*4+2*5+3*6.
I don't understand why does it work because p is a pointer and p=produs(a,b,n) means that the address of p becomes the value returned by produs.
#include <stdio.h>
#include <conio.h>
void citire(int *x,int *n)
{
for(int i=1; i<=*n; i++)
scanf("%d",&x[i]);
}
int produs(int *a,int*b,int n)
{
int produs=0;
for(int i=1;i<=n;i++)
produs=a[i]*b[i]+produs;
return produs;
}
int main()
{
int n;
int*p;
scanf("%d",&n);
int *a=(int*)malloc(n*sizeof(int));
int *b=(int*)malloc(n*sizeof(int));
citire(a,&n);
citire(b,&n);
p=produs(a,b,n);
printf("%d",p);
return 0;
}
When you do:
size_t size = 10;
int* x = calloc(size, sizeof(int));
You get an array x with 10 items in it, indexed 0..9, not 1..10. Here calloc is used to make it abundantly clear what's being requested instead of doing multiplication that can be mysterious or obtuse.
As such, to iterate:
for (int i = 0; i < size; ++i) {
x[i] ...
}
You have a number of off-by-one errors in your code due to assuming arrays are 1..N and not 0..(N-1).
Putting it all together and cleaning up your code yields:
#include <stdio.h>
#include <stdlib.h>
void citire(int *x, size_t s)
{
for(int i=0; i < s; i++)
scanf("%d", &x[i]);
}
int produs(int *a, int* b, size_t s)
{
int produs = 0;
for(int i = 0; i < s; i++)
produs = a[i] * b[i] + produs;
return produs;
}
int main()
{
int n;
scanf("%d",&n);
int* a = calloc(n, sizeof(int));
int* b = calloc(n, sizeof(int));
citire(a, n);
citire(b, n);
// produs() returns int, not int*
int p = produs(a,b,n);
printf("%d", p);
return 0;
}
You're using pointers in places where pointers don't belong. In C passing a pointer to a single value means "this is mutable", but you don't change those values, so no pointer is necessary nor advised.
Try and use size_t as the "size of thing" type. That's what's used throughout C and it's an unsigned value as negative indexes or array lengths don't make any sense.

Using a swap function to swap the address in pointers of a 2D-array

For an assignment I need to make a sorting algorithm for n amount of vector arrays. The assignment specifically tells me to not swap the value of what the pointers are pointing to, but the address that is stored in those pointers. The result will then be printed using those pointers.
My problem is that I can't seem to accomplish the swapping of the addresses that the pointers contain. I have searched SO for related questions but they almost all change the values of where the pointers are referring to.
So far I have this:
Swap function
void swap(double **p, double **q, int i, int j){
double* tmp;
tmp = &p;
*p= &q;
*q = tmp;
printf("\tSwapped [%d][%d] and [%d][%d]\n", i,j, (i-1), j);}
And my main function
int main (void){
int dim, num, *tmp;
int i, j, a;
double **w;
scanf("%d %d", &dim, &num); /* read the dimension and amount of array*/
w = calloc(num, sizeof(double *)); /* allocate array of num pointers */
for (i = 0; i<num; i++)
{
/*allocate space for a dim-dimensional vector */
w[i] = calloc(dim, sizeof(double));
/* read the vector */
for (j = 0; j < dim; j++)
{
scanf("%le", &w[i][j]);
}
}
a = 0;
while (a <= num)
{
/*sort num times*/
i = (num -1);
while(i != 0)
{
if ((argument1) > (argument2) )
{ /*swap each columns of the rows individually*/
printf("\tSwapping..\n");
for(j = 0; j<dim; j++)
{
swap(&w[i][j], &w[i-1][j], i, j);
}
}
i--;
}
a++;
}
for(i=0; i<num; i++)
{
for(j=0; j<dim; j++)
{
printf("%e ",w[i][j]);
}
printf("\n");
}
return 0;
}
When i test this program, it does enter the swap function correctly but the printed result is the same as the input (so not swapped). Can anyone help me why this isn't working?
The swap function can look like
void swap( double **p, double **q )
{
double *tmp = *p;
*p = *q;
*q = tmp;
}
As for the code that is used to sort arrays then it is invalid and does not make sense. At least the variables argument1 and argument2 are not declared.

C Program, function sorting through pointers

This program is supposed to take an array, and sort it from lowest to highest value. My program won't sort any values though. I believe the error is in the selectionSort. The values i and j are present in the function, I printed them out inside the function but they are not passed into the swap function. I tried making i and j pointers but it didn't work. I just have no clue on what to do next. Any help would be appreciated.
#include <stdio.h>
#define N 5
void selectionSort(int *a, int n);
int *findLargest(int *a, int n);
void swap(int *p, int *q);
int main(void)
{
int i;
int a[N];
printf("Enter %d numbers: ", N);
for (i = 0; i < N; i++) {
scanf("%d", &a[i]);
}
selectionSort(a, N);
printf("In sorted order:");
for (i = 0; i < N; i++) {
printf(" %d", a[i]);
}
printf("\n");
return 0;
}
void selectionSort(int *a, int n)
{
int *p = a;
int i;
int j;
if (n == 1) {
return;
}
i = *(p+n-1);
j = *findLargest(a, n);
swap(&i, &j);
selectionSort(a, n - 1);
}
int *findLargest(int *a, int n)
{
int *p;
int *p_max = a;
for(p = a + 1; p < a + n - 1; p++) {
if ( *p > *p_max)
p_max = p;
}
return p_max;
}
void swap(int *p, int *q)
{
int temp = *(p-1);
*(p-1) = *q;
*q = temp;
}
The problem is in your call of swap: you swap the content of two local variables
int i;
int j;
... // Some other code, then
swap(&i, &j);
This has no effect on the original array. You should be passing p+n-1 and findLargest(a, n) directly, or store their results in pointers, not in ints:
swap(p+n-1, findLargest(a, n));
In addition, your swap is broken: rather than swapping the content of two pointers, it assumes that p points one element past the target location. This is a bad assumption to make in a general-purpose function, such as swap, and it also leads to undefined behavior in your program.
void swap(int *p, int *q) {
int temp = *p;
*p = *q;
*q = temp;
}

Optimizing a 'sorting code' in C

I am working on a code I want to optimize. The code is all about sorting a double array by ascending order of its second .
The first input is an integer N, and the second is a 2D array of size N*2 (call it c), then we sort the array by ascending order of c[.][1], and when there are equal elements, say if c[i][1]==c[j][1], for two integers i and j, we sort those elements by ascending of the elements of the first columns, so c[i][1] is below c[j][1] if c[i][1]<c[j][1]. Let's take an example :
input
3
2 3
1 3
4 2
output
4 2
1 3
2 3
The fact is that the code needs to run in less than 0.5s and mine is really too slow. Here it is
#include <stdio.h>
#include <stdlib.h>
//determining the index of the max elments in an array
int max(int i, int N, int **c)
{
int j=0;
int M=0;
for(j=0;j<i;j++)
{if(c[j][1]>c[M][1]){M=j;}else{}}
return M;
}
int main ()
{
//integers used for the loops
int i;
int j;
//the size of the 2D array is N*2
int N;
scanf("%d",&N);
int **c;
int mx;
int maxi;
//this array is the output, thath is the 2D array sorted
int e[N][2];
//2D array we want to sort
c = malloc(N*sizeof(int*));
for (i=0;i<N;i++)
{
c[i] = malloc(2*sizeof(int));
for (j=0;j<2;j++)
{
scanf("%d",&c[i][j]);
}
}
//at the first step, we have initialized the value of the max
maxi=max(N,N,c);
for(i=0;i<N;i++)
{
//we sort the c[.][1], and we take the max (called 'mx') of the array. At each step of the loop, we throw away the max from the array c[.][1] (we mean the max found at the precedent step of the loop)
mx=max(N-i,N,c);
//Here, we look at the multiple occurence of the max, if there are, we sort the c[.][0] for which c[.][1]=c[mx][1] by ascending order
if(maxi==mx){int k;
for(k=0;k <N;k++){if(c[k][1]==c[mx][1]){if(c[k][0]>c[mx][0]){mx=k;}}else{}}
}else{}
//we keep the value of the max in order to verify that the same value of the max has another occurence in following steps
maxi=mx;
//e is the double array for the output
e[i][0]=c[mx][0];
e[i][1]=c[mx][1];
int j;
//here we throw away the max from the array
for(j=mx;j< N-i-1;j++){c[j][1]=c[j+1][1];c[j][0]=c[j+1][0];}
}
for(i=0;i<N;i++)
{printf("%d %d",e[N-1-i][0],e[N-1-i][1]);
printf("\n");}
}
Could anyone help ?
Your code has way too high computational complexity. Also, int e[N][2] only works under GCC extension since N is a variable determined at run time instead of compile time.
An easy (in terms of coding) way to improve it is utilizing qsort() in C standard library.
struct IntPair
{
int n[2];
};
int compareIntPair(const void* lhs, const void* rhs)
{
const struct IntPair *l = (const struct IntPair*)lhs;
const struct IntPair *r = (const struct IntPair*)rhs;
if(l->n[1] < r->n[1])
return -1;
if(l->n[1] > r->n[1])
return 1;
if(l->n[0] < r->n[0])
return -1;
if(l->n[0] > r->n[0])
return 1;
return 0;
}
int main(void)
{
//integers used for the loops
int i;
//the size of the 2D array is N*2
int N;
struct IntPair* c;
scanf("%d",&N);
c = (struct IntPair*)calloc(N, sizeof(struct IntPair));
for(i = 0; i < N; ++i)
{
scanf("%d%d", &c[i].n[0], &c[i].n[1]);
}
qsort(c, N, sizeof(struct IntPair), compareIntPair);
for(i = 0; i < N; ++i)
printf("%d %d\n", c[i].n[0], c[i].n[1]);
free(c);
return 0;
}
Edit: to answer the question in comment "could each element of the N-dynamic allocation points to 1D array of size 2?"
int compareElem(const void* lhs, const void* rhs)
{
const int *l = *(const int**)lhs;
const int *r = *(const int**)rhs;
if(l[1] < r[1])
return -1;
if(l[1] > r[1])
return 1;
if(l[0] < r[0])
return -1;
if(l[0] > r[0])
return 1;
return 0;
}
int main(void)
{
//integers used for the loops
int i;
//the size of the 2D array is N*2
int N;
int ** c;
scanf("%d",&N);
c = (int**)calloc(N, sizeof(int*));
for(i = 0; i < N; ++i)
{
c[i] = (int*)calloc(2, sizeof(int));
scanf("%d%d", &c[i][0], &c[i][1]);
}
qsort(c, N, sizeof(int*), compareElem);
for(i = 0; i < N; ++i)
{
printf("%d %d\n", c[i][0], c[i][1]);
free(c[i]);
}
free(c);
return 0;
}

Resources