Reputation: 43
So I have this code that randomly generates an integer array based on user input, and puts the elements in ascending and descending order. However, currently, the code only prints the descending order twice. So I would like to know how to make a copy of the array ascd and use the copy in the piece of code that organizes the descending order. I am just a beginner, so I apologize if this is a silly question, and appreciate all the guidance I can get. Here is my code:
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
int main (){
int x;
printf("Enter the size of your array\n");//User is entering number of elements
scanf("%d", &x);
int ascd[x]; //Array
int c;
int d;
int e;
int kk = 0;
int temp;
int tempother;
int turtle;
for(c = 0; c<x; c++){//Randomly generating elements
srand(time(0));
ascd[kk] = (rand() %100) + 1;
}
for(c = 0; c<x; c++){ //Ascending order
for(d = 0; d<(x-c-1); d++){
if(ascd[d] > ascd[d+1]){
temp = ascd[d];
ascd[d] = ascd[d+1];
ascd[d+1] = temp;
}
}
}
for(turtle = 0; turtle<x; turtle++){//Descending order
for(e = 0; e<(x-turtle-1); e++){
if(ascd[e] < ascd[e+1]){
tempother = ascd[e];
ascd[e] = ascd[e+1];
ascd[e+1] = tempother;
}
}
}
printf("The ascending order is\n\n");
for(c = 0; c<x; c++){
printf("%d\n", ascd[c]);
}
printf("\n\nThe descending order is\n\n");
for(turtle = 0; turtle<x; turtle++){
printf("%d\n", ascd[turtle]);
}
}
Upvotes: 0
Views: 105
Reputation: 84642
There are a number of additional issues you need to consider. First always, always, validate user input. If nothing else, with the scanf
family of functions, make sure the expected number of conversions were successfully performed. e.g.
int x = 0;
printf ("\n enter the number of elements for your array: ");
if (scanf ("%d", &x) != 1) { /* always validate user input */
fprintf (stderr, "error: invalid input, integer required.\n");
return 1;
}
int ascd[x], desc[x];
Next, you only need to seed the random number generator once. Move srand (time (NULL));
out of the loop.
While not a requirement, it is good practice to initialize your VLA's to all zero (or some number, since you cannot provide an initializer) to eliminate the chance of an inadvertent read from an uninitialized value when iterating over the array (you can consider your filling in this case an initialization, making the memset
optional here, but you won't immediately loop and fill in all cases. Something as simple as the following is sufficient if you are not immediately filling the array, e.g.
memset (ascd, 0, x * sizeof *ascd); /* good idea to zero your VLA */
After filling your array, a simple memcpy
will duplicate the array if you wish to preserve both ascending and descending sorts, e.g.
for (int i = 0; i < x; i++) /* x random values 1 - 100 */
ascd[i] = (rand () % 100) + 1;
memcpy (desc, ascd, x * sizeof *ascd); /* copy ascd to desc */
The remainder is just a bit of cleanup. Resist the urge to create a (variable next) for every value in your code. That quickly becomes unreadable. While I prefer the C89 declarations, the C99/C11 declarations inside the for
block are convenient, e.g.:
for (int i = 0; i < x; i++) /* ascending order */
for (int j = 0; j < (x - i - 1); j++)
if (ascd[j] > ascd[j + 1]) {
int temp = ascd[j];
ascd[j] = ascd[j + 1];
ascd[j + 1] = temp;
}
Putting all the pieces together, and noting that main()
is type int
and therefore will return
a value, you could tidy things up as follows. Your style is completely up to you, but the goal should be readability. e.g.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
int main (void) {
int x = 0;
printf ("\n enter the number of elements for your array: ");
if (scanf ("%d", &x) != 1) { /* always validate user input */
fprintf (stderr, "error: invalid input, integer required.\n");
return 1;
}
int ascd[x], desc[x];
srand (time (NULL)); /* you only need do this once */
memset (ascd, 0, x * sizeof *ascd); /* good idea to zero your VLA */
for (int i = 0; i < x; i++) /* x random values 1 - 100 */
ascd[i] = (rand () % 100) + 1;
memcpy (desc, ascd, x * sizeof *ascd); /* copy ascd to desc */
for (int i = 0; i < x; i++) /* ascending order */
for (int j = 0; j < (x - i - 1); j++)
if (ascd[j] > ascd[j + 1]) {
int temp = ascd[j];
ascd[j] = ascd[j + 1];
ascd[j + 1] = temp;
}
for (int i = 0; i < x; i++) /* descending order */
for (int j = 0; j < (x - i - 1); j++)
if (desc[j] < desc[j + 1]) {
int temp = desc[j];
desc[j] = desc[j + 1];
desc[j + 1] = temp;
}
printf ("\n the ascending order is\n\n");
for (int i = 0; i < x; i++) {
if (i && !(i % 10)) putchar ('\n');
printf (" %3d", ascd[i]);
}
printf ("\n\n the descending order is\n\n");
for (int i = 0; i < x; i++) {
if (i && !(i % 10)) putchar ('\n');
printf (" %3d", desc[i]);
}
putchar ('\n');
return 0;
}
Example Use/Output
$ ./bin/sort_copy
enter the number of elements for your array: 100
the ascending order is
1 1 4 4 5 5 7 8 8 9
10 13 16 16 17 20 22 22 22 23
24 24 25 27 29 29 33 35 35 35
37 38 40 41 41 41 41 42 44 45
46 48 48 48 49 50 53 54 56 57
58 59 61 61 63 64 65 65 66 66
67 68 68 70 71 73 74 74 74 75
76 80 80 80 80 82 84 84 85 85
85 85 86 88 88 89 89 90 91 91
91 92 92 93 93 93 96 99 100 100
the descending order is
100 100 99 96 93 93 93 92 92 91
91 91 90 89 89 88 88 86 85 85
85 85 84 84 82 80 80 80 80 76
75 74 74 74 73 71 70 68 68 67
66 66 65 65 64 63 61 61 59 58
57 56 54 53 50 49 48 48 48 46
45 44 42 41 41 41 41 40 38 37
35 35 35 33 29 29 27 25 24 24
23 22 22 22 20 17 16 16 13 10
9 8 8 7 5 5 4 4 1 1
Look things over and let me know if you have any questions.
Sorting with qsort
Continuing for the comment, qsort
is an optimized sorting routine that is part of the C standard library (in stdlib.h
) and is the go-to sort function regardless of the type of data you have to sort. The only requirement that generally catches new C programmers is the need to write a comparison function to pass to qsort
so that qsort
knows how you want the collection of objects sorted. qsort
will compare two elements by passing a pointer to the values to the compare function you write. The declaration for the comparison is the same regardless of what you are sorting, e.g.
int compare (const void *a, const void *b);
You know you are sorting integer values, so all you need to do to sort ascending is to write a function that returns a positive value if a > b
, returns zero if they are equal, and finally returns a negative value if b > a
. The simple way, is to write
int compare (const void *a, const void *b) {
int x = *(int *)a;
int y = *(int *)b;
return x - y;
}
That satisfies the sort requirement for ascending order, and to sort in descending order return y - x;
-- but there is a problem. If x
and y
happen to be large positive and large negative values, there is a potential that x - y
will exceed the maximum (or minimum) value for an integer (e.g. overflow, because the result will not fit in an integer value).
The solution is simple. You can perform the same comparison, but using the results of an inequality, e.g. returning (a > b) - (a < b)
for the ascending comparison, and (a < b) - (a > b)
for the descending comparison. (this scheme will work for all numeric types, you just need to adjust the cast). Step though the inequality. In the ascending case, if a > b
the return is 1
(e.g. return 1 - 0;
). If they are equal, the inequality returns 0
(0 - 0
), and finally if a < b
, the value returned is -1
( 0 - 1
).
While you are free to continue to explicitly declare the x
and y
variables, you will generally see it written with the cast in the comparison, eliminating the need for the x
and y
variables altogether, e.g.
/* integer comparison ascending (prevents overflow) */
int cmpascd (const void *a, const void *b)
{
/* (a > b) - (a < b) */
return (*(int *)a > *(int *)b) - (*(int *)a < *(int *)b);
}
Putting those pieces together, the same program can be written using qsort
instead of the inefficient nested loops (and moving the print array routine to a function of its own) as follows,
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define ROW 10
int cmpascd (const void *a, const void *b);
int cmpdesc (const void *a, const void *b);
void prnarr (int *a, int n, int row);
int main (void) {
int x = 0;
printf ("\n enter the number of elements for your array: ");
if (scanf ("%d", &x) != 1) { /* always validate user input */
fprintf (stderr, "error: invalid input, integer required.\n");
return 1;
}
int ascd[x], desc[x];
srand (time (NULL)); /* you only need do this once */
memset (ascd, 0, x * sizeof *ascd); /* good idea to zero your VLA */
for (int i = 0; i < x; i++) /* x random values 1 - 100 */
ascd[i] = (rand () % 100) + 1;
memcpy (desc, ascd, x * sizeof *ascd); /* copy ascd to desc */
qsort (ascd, x, sizeof *ascd, cmpascd); /* qsort ascending */
qsort (desc, x, sizeof *desc, cmpdesc); /* qsort descending */
printf ("\n the ascending order is\n\n");
prnarr (ascd, x, ROW);
printf ("\n\n the descending order is\n\n");
prnarr (desc, x, ROW);
putchar ('\n');
return 0;
}
/* integer comparison ascending (prevents overflow) */
int cmpascd (const void *a, const void *b)
{
/* (a > b) - (a < b) */
return (*(int *)a > *(int *)b) - (*(int *)a < *(int *)b);
}
/* integer comparison descending */
int cmpdesc (const void *a, const void *b)
{
/* (a < b) - (a > b) */
return (*(int *)a < *(int *)b) - (*(int *)a > *(int *)b);
}
void prnarr (int *a, int n, int row)
{
for (int i = 0; i < n; i++) {
printf (" %3d", a[i]);
if (i && !((i + 1) % row))
putchar ('\n');
}
}
As with the first answer, give it a try and let me know if you have any questions. (And remember to always compile with a minimum -Wall -Wextra
to enable most compiler warnings -- and fix any warnings generated before you consider your code reliable -- you won't run into any circumstance where warnings can be understood and safely ignored anytime soon) Add -pedantic
to see virtually all warnings that can be generated. (if you look up pedantic in Websters, you will see why that name is apt.) Just FYI, the gcc
compiler string I used to compile the code was:
$ gcc -Wall -Wextra -pedantic -std=c11 -Ofast -o bin/sort_copy sort_copy.c
Upvotes: 3
Reputation: 1340
Create an another array to store descending items. You can reverse the ascending array to create the descending array. Try this code. #include #include #include #include int main (){
int x;
printf("Enter the size of your array\n");//User is entering number of elements
scanf("%d", &x);
int ascd[x]; //Array
int desc[x];
int c;
int d;
int e;
int kk = 0;
int temp;
int tempother;
int turtle;
int z=0;
for(c = 0; c<x; c++){//Randomly generating elements
srand(time(0));
ascd[kk] = (rand() %100) + 1;
}
for(c = 0; c<x; c++){ //Ascending order
for(d = 0; d<(x-c-1); d++){
if(ascd[d] > ascd[d+1]){
temp = ascd[d];
ascd[d] = ascd[d+1];
ascd[d+1] = temp;
}
}
}
for(turtle = x-1; turtle>=0; turtle--){//Descending order
desc[z]=ascd[turtle];
z++;
}
printf("The ascending order is\n\n");
for(c = 0; c<x; c++){
printf("%d\n", ascd[c]);
}
printf("\n\nThe descending order is\n\n");
for(turtle = 0; turtle<x; turtle++){
printf("%d\n", desc[turtle]);
}
}
Upvotes: 0
Reputation: 322
You print the final array twice, you can have your ascending array output by printing the values of the array right after you have done the ascending operation.
Upvotes: 0