I have a 2 dimensional array that I am trying to sort in ascending order. For example, say the array looks like this:
4, 5
2, 6
7, 2
8, 4
I would like it to look like this:
2, 6
4, 5
7, 2
8, 4
The code that I have so far:
int temp = 0;
for(int m = 0; m<=nonZeroLength-1; m++){
for(int n = m+1; n<=nonZeroLength-1; n++){
if(nonZeroScoreSorcting[m] > nonZeroScoreSorcting[m+1]){
temp = nonZeroScoreSorcting[m];
strcpy(nonZeroScoreSorcting[m], nonZeroScoreSorcting[n]);
strcpy(nonZeroScoreSorcting[n], temp);
}
}
}
Assume that nonZeroLength has a value of 4 for this example. I am using strcpy() because I read that that is the only way to change elements of an array in C. When I run the program I get the following error:
passing argument 1 of ‘strcpy’ from incompatible pointer type [-Wincompatible-pointer-types]
I have also tried the regular assign method:
if(nonZeroScoreSorcting[m] > nonZeroScoreSorcting[m+1]){
temp = nonZeroScoreSorcting[m];
nonZeroScoreSorcting[m] = nonZeroScoreSorcting[n];
nonZeroScoreSorcting[n] = temp;
}
If you do in fact have a 2D array of int as you indicate, the key to sorting the array by row is understanding that during the sort, you will need to swap rows, not simply values. This is how you preserve the row-wise relationship during the sort.
You cannot do that treating each row of int as a string and attempting a row-wise copy using strcpy. This will result in Undefined Behavior when strcpy accesses values in the src argument outside the array bounds looking for a nul-terminating character that isn't present.
(though technically, providing a properly sized array for each src and dest and sizing 'n' in strncpy to copy 2 * sizeof(int) bytes can copy rows by virtue of limiting the read to n chars where no nul-terminating character is present -- but DON'T do it -- that's what memcpy (or memmove) is for).
Though the recommended way to sort in C is using the qsort function provided in stdlib.h, you can provide whatever sort algorithm you want. It will likely not be anywhere close to the efficiency of qsort, and certainly will be nowhere near as thoroughly tested. A simple row-sort using the slow old insertion sort could be done as follows:
#include <stdio.h>
#include <string.h>
int main (void) {
int a[][2] = {{ 4, 5 },
{ 2, 6 },
{ 7, 2 },
{ 8, 4 }},
n = sizeof a / sizeof *a,
col = sizeof *a / sizeof **a;
for (int i = 0; i < n; i++) /* insertion sort of a by row */
for (int j = i; j > 0 && *a[j] < *a[j-1]; j--) {
int tmp[col]; /* temporary VLA */
memcpy (tmp, a[j], sizeof *a);
memcpy (a[j], a[j-1], sizeof *a);
memcpy (a[j-1], tmp, sizeof *a);
}
for (int (*p)[2] = a; p < a + n; p++) /* output results */
printf ("%d, %d\n", (*p)[0], (*p)[1]);
return 0;
}
Example Use/Output
$ ./bin/inssort2d
2, 6
4, 5
7, 2
8, 4
With qsort most new C programmers are stumped by having to write a compare function to pass to qsort to let it do its job. It is really not that difficult at all. You know qsort will pass pointers to two of whatever you are sorting as arguments to your compare function.
In this case you will be sorting rows of integers (1D arrays of integers) based on the first element of each row. So qsort will compare two int * (pointers to int). You only care about the first element in each array (which you can obtain simply by dereferencing the pointer). A compare here can be a simple:
int cmp (const void *a, const void *b)
{
/* (a > b) - (a < b) */
return (*(int *)a > *(int *)b) - (*(int *)a < *(int *)b);
}
(note: by using the result of the two inequalities you protect against over/underflow that could occur if you simply returned the result of a subtraction alone).
The complete qsort implementation would be:
#include <stdio.h>
#include <stdlib.h>
int cmp (const void *a, const void *b)
{
/* (a > b) - (a < b) */
return (*(int *)a > *(int *)b) - (*(int *)a < *(int *)b);
}
int main (void) {
int a[][2] = {{ 4, 5 },
{ 2, 6 },
{ 7, 2 },
{ 8, 4 }},
n = sizeof a / sizeof *a;
qsort (a, n, sizeof *a, cmp); /* qsort array of pointers */
for (int (*p)[2] = a; p < a + n; p++) /* output results */
printf ("%d, %d\n", (*p)[0], (*p)[1]);
return 0;
}
(output is the same)
Look over both methods and know that qsort is the preferred method, but for learning, there is nothing wrong with doing it by hand to gain experience. Let me know if you have further questions.
Related
Hello guys i have a situation here am trying to sort out numbers in C language but i seem to struggle to put a sort function can you please help me with this following souce code that prints out number and supose to sort them but i cant...please help:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int num1 = 8, num2 = 6, num3 = 2, num4 = 4, num5 = 1;
printf("%d %d %d %d %d", num1, num2, num3, num4, num5);
// qsort(); THIS IS WHAT I STRUGGLE WITH AT THE MOMENT
return 0;
} // THIS CODE PRINTS OUT NUMBERS BUT ARE NOT SORTED...SO I NEED TO SORT THEM PLEASE
// YOUR HELP WILL BE MUCH APPRECIATED
// I NEED TO KNOW HOW TO USE THE SORT(qsort) FUNCTION
qsort() does one thing and it does it exceptionally well, it sorts arrays, and does so very efficiently. As noted in the comments, before you can use qsort() you will need to collect your values in an array rather than separate variables. Once you have an array, using qsort() is trivial, your only responsibility using qsort is to write the compare() function.
New users of qsort() usually have their eyes roll back in their heads when they see the declaration for the function:
int compare (const void *a, const void *b) { ... }
It's actually quite simple. a and b are simply pointers to elements of the array to compare. Since qsort() can handle any type array, the parameter type are void pointers. If you have an array of int, a and b are just pointers int (e.g. int*). You simply need to write your compare function to cast a and b to int* and dereference to compare the int values with each other.
The return of compare() is either less than zero (a sorts before b), zero (a and b are equal) or greater than zero (b sorts before a). So a niave compare() can be as simple as:
int compare (const void *a, const void *b)
{
int x = *(int *)a,
y = *(int *)b;
return x - y;
}
However, there is always a potential for x - y to overflow with a large negative x and large y or large x and large negative y. So you generally try and use the differnce between two comparisons to eliminate the potential for overflow, e.g.
int compare (const void *a, const void *b)
{
int x = *(int *)a,
y = *(int *)b;
return (x > y) - (x < y);
}
Now if you take any value of a and b the return will either be -1, 0 or 1 providing the sort information for qsort() without chance of overflow.
A short example using your values could be written as:
#include <stdio.h>
#include <stdlib.h>
int compare (const void *a, const void *b)
{
int x = *(int *)a,
y = *(int *)b;
return (x > y) - (x < y);
}
void prn_arr (int *arr, size_t nmemb)
{
for (size_t i = 0; i < nmemb; i++)
printf (i ? ", %d" : "%d", arr[i]);
putchar ('\n');
}
int main()
{
int num[] = {8, 6, 2, 4, 1};
size_t nmemb = sizeof num / sizeof *num;
puts ("array before sort:\n");
prn_arr (num, nmemb);
qsort (num, nmemb, sizeof *num, compare);
puts ("\narray after sort:\n");
prn_arr (num, nmemb);
}
Example Use/Output
$ ./bin/qsortnum
array before sort:
8, 6, 2, 4, 1
array after sort:
1, 2, 4, 6, 8
Look things over and let me know if you have further questions.
Lets say I have two arrays, A[5] and B[3]. I want to create another array C[8] that will contain all the elements from A and B. First it will store A elements and then B. I am a beginner in C. So anyone can help?
You can use memcpy. Below I have assumed these are arrays of ints, but you could replace sizeof(int) with the type you are actually doing.
memcpy(C, A, 5 * sizeof(int));
memcpy(C + 5, B, 3 * sizeof(int));
The first line says copy 5 ints from the start of A to the start of C. The second line says copy 3 ints from the start of B to C starting at index 5.
Edit: As pointed out in the comments, I overcomplicated this. You can use the following and not have to worry about types:
memcpy(C, A, 5 * sizeof(C[0]));
memcpy(C + 5, B, 3 * sizeof(C[0]));
You can achieve this with two for loops. First copy the content from A to C:
for(int i = 0; i < 5; i++)
C[i] = A[i];
And then, copy the content of B to C, from the position where you inserted the last element of A:
for(int i = 5; i < 8; i++)
C[i] = B[i-5];
Note that the loop now starts with 5 and ends in 8, this is because we want to start copying the values of B into C after the positions already filled with the values of A. The position of B where we are reading is i - 5, which gives the positions 0, 1, 2... for B. We are doing this here because the loop starts in 5.
You can also do this with just one for loop in the following way:
for(int i = 0; i < 5; i++){
C[i] = A[i];
if(i < 3)
C[i+5] = B[i];
}
universal function
void *copy(void * restrict dest, const void * restrict src, const void * restrict src1, const size_t len1, const size_t len2, const size_t elemsize)
{
unsigned char *restrict ucdest = dest;
if(dest && src && src1)
{
memcpy(ucdest, src, elemsize * len1);
memcpy(ucdest + elemsize * len1, src1, elemsize * len2);
}
return dest;
}
I was writing a program to concatenate two arrays in C. I am allocating memory for a third array and using memcpy to copy the bytes from the two arrays to the third. The test output is:
1 2 3 4 5 0 0 0 0 0
Is there anything wrong with this approach?
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int *array_concat(const void *a, int an,
const void *b, int bn)
{
int *p = malloc(sizeof(int) * (an + bn));
memcpy(p, a, an*sizeof(int));
memcpy(p + an*sizeof(int), b, bn*sizeof(int));
return p;
}
// testing
const int a[] = { 1, 2, 3, 4, 5 };
const int b[] = { 6, 7, 8, 9, 0 };
int main(void)
{
unsigned int i;
int *c = array_concat(a, 5, b, 5);
for(i = 0; i < 10; i++)
printf("%d\n", c[i]);
free(c);
return 0;
}
memcpy(p + an*sizeof(int),...
this second memcpy, you are trying to add 5 * sizeof(int) to an int pointer, p. However, when you add to a pointer, it already knows that it has to deal with sizeof(type), so you don't have to tell it.
memcpy(p + an,...
Remove the multiplication *sizeof(int) from the 1st argument of memcpy. Keep it in the argument of malloc and the 3rd argument of memcpy.
This is because p + an points to an int which is an ints to the right from p -- that is, the int which is an*sizeof(int) bytes to the right from p.
p is a pointer to int. When you add an integer to a pointer to an int, the compiler multiplies the integer by the size of an integer. The net result is to multiply by the size of an integer twice: what you're getting is "p + an*sizeof(int)" is p + (number of elements in a) * (number of bytes in an int) * (number of bytes in an int).
memcpy(p + an*sizeof(int), b, bn*sizeof(int));
should be:
memcpy(p + an, b, bn*sizeof(int));
You should remove sizeof(int) from second memcpy where you use pointer arithmetic (+).
Compiler doing this by itself depending on type of pointer.
you should see the definition of the memcpy, which copy's n "bytes" from the src to the dst area. so,you just need to times sizeof(int) only for the 3rd argument. and for "c", it's a pointer of int type, so, it does know that "+an" means move p forward to the an+1 int position.
Merging can be done by sorting the elements of the elements which are going to be merged code for merging two arrays
#include<stdio.h>
void sort(int arr[],int size){ // sorting function
int i,j,temp;
for(i=0;i<size;i++){
for(j=i;j<size;j++){
if(arr[i]>arr[j]){
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
}
int main(){
int a[10],b[10],c[10];
int n,i,k=0,j=0;
printf("Enter the size of the array:");
scanf("%d",&n);
for(i=0;i<n;i++){
printf("Enter the element of array A at index %d:",i); //input array A
scanf("%d",&a[i]);
}
sort(a,n);
for(i=0;i<n;i++){
printf("Enter the element of array B at index %d:",i); //Input array B
scanf("%d",&b[i]);
}
sort(b,n);
for(i=0;i<(n+n);i++){ // merging the two arrays
if(a[k]<b[j]){
c[i] = a[k];
k++;
}
else{
c[i] = b[j];
j++;
}
}
printf("Merged Array :\n");
for(i=0;i<(n+n);i++){
printf("c -> %d ",c[i]);
}
return 0;
}
Reference C program to Merge Two Arrays after Sorting
Being able to define an array e.g.
int a[] = {1,2,3};
is very convenient, however, the array a is an r-value so I can't subsequently change the values in a, e.g.
a[] = {4,5,6};
The context for wanting to do this is writing a bunch of unit tests where I am feeding in arrays to functions and testing the outputs. I'm running tests on the same function with different inputs and would like to avoid having to have unique names for my input arrays, e.g. I'm having to do this:
int test1_a[] = {1,2,3};
/* calls to functions */
int test2_a[] = {4,5,6};
/* calls to functions */
Also, if I want to pass a pointer to an array into a function I have to 1st cast it like this:
int a[] = {1,2,3};
int *b = a;
my_func(&b);
passing a pointer to an r-value like this doesn't work:
my_func(&a);
My question is whether there is any other way to easily initialise an array of values without suffering from these limitations? (particularly with a view to making it easy to write many similar unit tests without each test having a unique set of array names)
If you already have the values you want to pass to the functions, why not use a multi-dimensional array?
int a[][] = {
{ 1, 2, 3 },
{ 4, 5, 6 }
}
for (int i = 0; i < 2; i++)
{
/* Call functions with 'a[i]' as argument */
}
Also, if the functions you call expect an array, and you have a e.g. int a[] = {...}; int *b = a;, then don't call them with &b. Using &b passes the address of the pointer, not what it points to.
If i have understood your question properly.I guess the following should solve your problem.
memcpy(a, (int[]){3, 2, 1}, sizeof a);
Only if your c compiler supports compound literals(c99 onwards).
To specify the standard, gcc can be invoked as "gcc -std=c99 -Wall -pedantic".
Here's one option:
#include <stdio.h>
#include <stdarg.h>
void ReinitArray(int* p, size_t cnt, ...)
{
va_list ap;
va_start(ap, cnt);
while (cnt--)
{
*p++ = va_arg(ap, int);
}
va_end(ap);
}
int array[5] = { 1, 2, 3, 4, 5 };
int main(void)
{
size_t i;
printf("array[5]=");
for (i = 0; i < 5; i++) printf("%d ", array[i]);
printf("\n");
ReinitArray(array, 5, 11, 22, 33, 44, 55);
printf("array[5]=");
for (i = 0; i < 5; i++) printf("%d ", array[i]);
printf("\n");
return 0;
}
Output:
array[5]=1 2 3 4 5
array[5]=11 22 33 44 55
And you can simply write my_func(a); where a is an array name. This will be equivalent to passing &a[0], the address of the very first array element. You can't pass entire arrays directly as function parameters in C.
I have been stuck on this for a while and nothing seems to work.
I have a data structure:
DATA
{
int size;
int id;
}
And I have an array of DATA structures:
myArray = (DATA *) malloc(10 * sizeof(DATA));
Then I assign some test values:
myArray[0].size = 5;
myArray[1].size = 9;
myArray[2].size = 1;
myArray[3].size = 3;
So my starting array should look like:
5,9,1,3,0,0,0,0,0,0
Then, I call qsort(myArray,10,sizeof(DATA),comp)
Where comp is:
int comp(const DATA * a, const DATA * b)
{
return a.size - b.size;
}
And trust me, I tried many things with the compare function, NOTHING seems to work. I just never get any sorting that makes any sense.
So my starting array should look like 5, 9, 1, 3, 0, 0, 0, 0, 0, 0.
No, it really won't, at least it's not guaranteed to.
If you want zeros in there, either use calloc() to zero everything out, or put them in yourself. What malloc() will give you is a block of the size required that has indeterminant content. In other words, it may well have whatever rubbish was in memory beforehand.
And, on top of that, a and b are pointers in your comp function, you should be using -> rather than . and it's good form to use the correct prototype with casting.
And a final note: please don't cast the return from malloc in C - you can get into problems if you accidentally forget to include the relevant header file and your integers aren't compatible with your pointers.
The malloc function returns a void * which will quite happily convert implicitly into any other pointer.
Here's a complete program with those fixes:
#include <stdio.h>
#include <stdlib.h>
typedef struct {int size; int id;} DATA;
int comp (const void *a, const void *b) {
return ((DATA *)a)->size - ((DATA *)b)->size;
}
int main (void) {
int i;
DATA *myArray = malloc(10 * sizeof(DATA));
myArray[0].size = 5;
myArray[1].size = 9;
myArray[2].size = 1;
myArray[3].size = 3;
for (i = 4; i < 10; i++)
myArray[i].size = 0;
qsort (myArray, 10, sizeof(DATA), comp);
for (i = 0; i < 10; i++)
printf ("%d ", myArray[i].size);
putchar ('\n');
return 0;
}
The output:
0 0 0 0 0 0 1 3 5 9