I have been working on this problem for a while now: basically I need to put the for loop in a function so I can call for it, but I don't how to to make a function return a 2D array, I want to solve this by creating a 1D array, but the problem is that my task is to compute the sum of numbers under the diagonal of a matrix, so I need it to be 2D first, then it can only become 1D. Does anyone have a solution?
Maybe my thought process is just wrong and somebody could just recommend how to put the for loops in functions? If it was without the if clause inside then I might have an idea, but now I really don't.
#include <math.h>
#include <stdio.h>
#include <stdlib.h> // libraries added from example
#include <time.h>
//(*) For a square matrix calculate the sum of elements under the main diagonal excluding it.
#define A -10
#define B 10
int main() {
void enter(int *x, int *y);
int get_random(int lbound, int ubound); // telling the programs that functions are declared
int r;
int c;
int row, col, sum = 0;
enter(&r, &c); // calling the function
srand48(time(NULL)); //Call srand48 with current time reported by `time` casted to a long integer.
// srand48 is used to reinitialize the most recent 48-bit value in this storage
int array[r][c]; // we decided its gonna be r rows and c columns
int line[r * c]; // turning 2d into 1d array
for (row = 0; row < r; ++row) // we cycle numeration of rows of matrix
{
for (col = 0; col < c; col++) // we cycle numeration of columns of matrix
{
array[row][col] = get_random(B, A);// filling array with random numbers, taken from example
printf("%d ", array[row][col]);
if (row > col) { //since we want the sum numbers below the diagonal row>col must be true
sum = sum + array[row][col];// if row>col then we add the number to our sum;
};
}
printf("\n"); // this is to break line after row 1,2 col 3, so it looks nicer
}
for (row = 0; row < r; ++row) // we cycle numeration of rows of matrix
{
for (col = 0; col < c; col++) // we cycle numeration of columns of matrix
{
line[row * r + col] = array[row][col];
}
}
printf("the array in 1D: ");
for (row = 0; row < r * c; row++) {
printf("%d ", line[row]);
}
printf("\n");
printf("sum of array below the diagonal: %d\n", sum);
return 0;
}
void enter(int *x, int *y) { // we have to use pointers if we want more then one return from a function
printf("How man rows in array? "); // just like the last lab we decide how big the matrix will be
scanf("%d", x); // we use x instead of &x because we need the address of the number not the value
printf("How man columns in array? ");
scanf("%d", y); // we use y instead of &y because we need the address of the number not the value
}
int get_random(int lbound, int ubound) {
return mrand48() % (ubound - lbound + 1) + lbound; // function for generating random numbers
}
Conditions have to be met:
the user decides size of square matrix
the matrix has to be filled with random numbers
the array is called by the function has to be 1D using i*N+j, 2D array can't be passed
Let's consider your assignment
Conditions have to be met:
the user decides size of square matrix
the matrix has to be filled with random numbers
the array is called by the function has to be 1D using i*N+j, 2D
array can't be passed
Firstly the matrix must be square.
So this your function
void enter(int *x, int *y) { // we have to use pointers if we want more then one return from a function
printf("How man rows in array? "); // just like the last lab we decide how big the matrix will be
scanf("%d", x); // we use x instead of &x because we need the address of the number not the value
printf("How man columns in array? ");
scanf("%d", y); // we use y instead of &y because we need the address of the number not the value
}
does not make sense. The user can enter different values for the numbers of rows and columns of the matrix. You need to enter only one positive value.
Secondly as we are speaking about a matrix then it means that you have to define a two-dimensional array.
Also you need to write a function that will calculate the sum of elements under the main diagonal of a matrix. The function is declared such a way that it can accept only a one-dimensional array. This means that you need to pass your matrix to the function casting it to a pointer of the type int *. There is no need to create an auxiliary one-dimensional array,
Here is a demonstration program that shows how the function can be declared and defined and how the matrix can be passed to the function.
#include <stdio.h>
long long int sum_under_dioganal( const int a[], size_t n )
{
long long int sum = 0;
for (size_t i = 1; i < n; i++)
{
for (size_t j = 0; j < i; j++)
{
sum += a[i * n + j];
}
}
return sum;
}
int main( void )
{
enum { N = 5 };
int a[N][N] =
{
{ 0, 0, 0, 0, 0 },
{ 1, 0, 0, 0, 0 },
{ 2, 3, 0, 0, 0 },
{ 4, 5, 6, 0, 0 },
{ 7, 8, 9, 10, 0 }
};
printf( "sum of elements under the main diagonal = %lld\n",
sum_under_dioganal( ( int * )a, N ) );
}
The program output is
sum of elements under the main diagonal = 55
Another approach to define the function and call it is the following
#include <stdio.h>
long long int sum_under_dioganal( const int a[], size_t n )
{
long long int sum = 0;
size_t m = 0;
while (m * m < n) ++m;
if (m * m == n)
{
for (size_t i = 1; i < m; i++)
{
for (size_t j = 0; j < i; j++)
{
sum += a[i * m + j];
}
}
}
return sum;
}
int main( void )
{
enum { N = 5 };
int a[N][N] =
{
{ 0, 0, 0, 0, 0 },
{ 1, 0, 0, 0, 0 },
{ 2, 3, 0, 0, 0 },
{ 4, 5, 6, 0, 0 },
{ 7, 8, 9, 10, 0 }
};
printf( "sum of elements under the main diagonal = %lld\n",
sum_under_dioganal( ( int * )a, N * N ) );
}
The program output is the same as shown above.
sum of elements under the main diagonal = 55
2d arrays don't really exist. The compiler just allows you to write a[i][j] so that you can believe in them. Here's some simple code to demonstrate a few methods:
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
void *
make_array(size_t size)
{
int *a = malloc(sizeof *a * size * size);
int *t = a;
if( a == NULL ){
perror("malloc");
exit(1);
}
for( int row = 0; row < size; row += 1 ){
for( int col = 0; col < size; col += 1 ){
*t++ = rand() % 32 - 16;
}
}
return a;
}
int
trace(void *v, size_t s)
{
int *a = v;
int sum = 0;
for( size_t i = 0; i < s; i += 1 ){
sum += *a;
a += s + 1;
}
return sum;
}
int
main(int argc, char **argv)
{
srand(time(NULL));
size_t s = argc > 1 ? strtol(argv[1], NULL, 0) : 5;
void *v = make_array(s);
/* a, b, c, and d will demonstrate different access techniques */
int *a = v; /* a is the conventional "1-d array" (1)*/
int (*b)[s] = v; /* b is a "two-d" array */
int *c = v; /* c iterates through each element */
int *d = v; /* d treats each row as a 1-d array */
for( int i = 0; i < s; i += 1 ){
for( int j = 0; j < s; j += 1 ){
printf("%3d ", b[i][j]);
assert( a[i * s + j] == b[i][j] );
assert( *c == b[i][j] );
assert( d[j] == b[i][j] );
c += 1;
}
d += s;
putchar('\n');
}
printf("trace: %d\n", trace(v, s));
}
/* (1) These comments are not strictly accurate. `a` is *not* an
* array, and `b` is *not* a 2-d array. `a` is a pointer, and `b` is
* an array of pointers. Arrays are not pointers, and pointers are
* not arrays.
*/
Related
Task:
Given a natural number N (set arbitrarily as a preprocessor constant) and one-dimensional array A0, A1, …, AN-1 of integers (generate positive and negative elements randomly, using the <stdlib.h> library function rand()). Perform the following actions: Determine the three maximum and two minimum values of this array.
Code with search for two minimum values:
#include <stdio.h>
#include <stdlib.h>
#define N 9
int main() {
int M[N], i, a[N], fbig, sbig, tbig, min, smin;
for (i = 0; i < N; i++) {
M[i] = rand() % 20 - 10;
printf("%i\t", M[i]);
}
printf("\n");
for (i = 0; i < N; i++) {
if (a[i] < min) {
smin = min;
min = a[i];
} else
if (a[i] < smin && a[i] != min)
smin = a[1];
}
printf("\nMinimum=%d \nSecond Minimum=%d", min, smin);
return 0;
}
I tried to compare array elements with each other but here is my result:
-7 -4 7 5 3 5 -4 2 -1
Minimum=0
Second Minimum=0
I would be very grateful if you could help me fix my code or maybe I'm doing everything wrong and you know how to do it right. Thank you for your time
I will revise my answer if op address what to do about duplicate values. My answer assume you want possible duplicate values in the minimum and maximum arrays, while other answers assume you want unique values.
The easiest solution would be to sort the input array. The minimum is the first 2 values and the maximum would be the last 3:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MAX_N 3
#define MIN_N 2
#define N 9
void generate(size_t n, int a[n]) {
for(size_t i = 0; i < n; i++)
a[i] = rand() % 20 - 10;
}
void print(size_t n, int a[n]) {
for(size_t i = 0; i < n - 1; i++)
printf("%d, ", a[i]);
if(n) printf("%d\n", a[n-1]);
}
int cmp_asc(const void *a, const void *b) {
if(*(int *) a < *(int *) b) return -1;
if(*(int *) a > *(int *) b) return 1;
return 0;
}
int main() {
int t = time(0);
srand(t);
printf("%d\n", t); // essential for debugging
int a[N];
generate(N, a);
print(N, a);
qsort(a, N, sizeof *a, cmp_asc);
print(MIN_N, a);
print(MAX_N, a + (N - MAX_N));
}
If you cannot use sort then consider the following purpose built algorithm. It's much easier to use arrays (min and max) rather than individual values, and as a bonus this allows you to easily change how many minimum (MIN_N) and maximum (MAX_N) values you want. First we need to initialize the min and max arrays, and I use the initial values of the input array for that. I used a single loop for that. To maintain the invariant that the min array has the MIN_N smallest numbers we have seen so far (a[0] through a[i-1]) we have to replace() largest (extrema) of them if the new value a[i] is smaller. For example, if the array is min = { 1, 10 } and the value we are looking at is a[i] = 5 then we have to replace the 10 not the 1.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MAX_N 3
#define MIN_N 2
#define N 9
void generate(size_t n, int a[n]) {
for(size_t i = 0; i < n; i++)
a[i] = rand() % 20 - 10;
}
void print(size_t n, int a[n]) {
for(size_t i = 0; i < n - 1; i++)
printf("%d, ", a[i]);
if(n) printf("%d\n", a[n-1]);
}
int cmp_asc(const void *a, const void *b) {
if(*(int *) a < *(int *) b) return -1;
if(*(int *) a > *(int *) b) return 1;
return 0;
}
int cmp_desc(const void *a, const void *b) {
return cmp_asc(b, a);
}
void replace(size_t n, int a[n], int v, int (*cmp)(const void *, const void *)) {
int *extrema = &a[0];
for(size_t i = 1; i < n; i++) {
if(cmp(extrema, &a[i]) < 0) {
extrema = &a[i];
}
}
if(cmp(extrema, &v) > 0)
*extrema = v;
}
void min_max(size_t n, int a[n], size_t min_n, int min[n], size_t max_n, int max[n]) {
for(size_t i = 1; i < n; i++) {
if(i < min_n)
min[i] = a[i];
else
replace(min_n, min, a[i], cmp_asc);
if(i < max_n)
max[i] = a[i];
else
replace(max_n, max, a[i], cmp_desc);
}
}
int main() {
int t = time(0);
srand(t);
printf("%d\n", t); // essential for debugging
int a[N];
generate(N, a);
print(N, a);
int min[MIN_N];
int max[MAX_N];
min_max(N, a, MIN_N, min, MAX_N, max);
print(MIN_N, min);
print(MAX_N, max);
}
and here is example output. The first value is a the seed in case you have to reproduce a run later. Followed by input, min and max values:
1674335494
-7, 0, -2, 7, -3, 4, 5, -8, -9
-9, -8
7, 5, 4
If MIN_N or MAX_N gets large, say, ~1,000+, then you want sort the min and max arrays and use binary search to figure out where to inserta[i]. Or use a priority queue like a heap instead of arrays.
There are multiple problems in your code:
min and smin are uninitialized, hence the comparisons in the loop have undefined behavior and the code does work at all. You could initialize min as a[0] but initializing smin is not so simple.
there is a typo in smin = a[1]; you probably meant smin = a[i];
Note that the assignment is somewhat ambiguous: are the maximum and minimum values supposed to be distinct values, as the wording implies, or should you determine the minimum and maximum elements of the sorted array?
For the latter, sorting the array, either fully or partially, is a simple solution.
For the former, sorting is also a solution but further testing will be needed to remove duplicates from the sorted set.
Here is a modified version to print the smallest and largest values:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define N 9
#define N_MIN 2
#define N_MAX 3
void swap(int *a, int *b) {
int tmp = *a;
*a = *b;
*b = tmp;
}
int main() {
int a[N], i, j, e, dup;
int smallest[N_MIN], nsmall = 0;
int largest[N_MAX], nlarge = 0;
srand(time(NULL));
for (i = 0; i < N; i++) {
a[i] = rand() % 20 - 10;
printf("%i\t", a[i]);
}
printf("\n");
for (i = 0; i < N; i++) {
e = a[i];
dup = 0;
for (j = 0; j < nsmall; j++) {
if (e == smallest[j]) {
dup = 1;
break;
}
if (e < smallest[j]) {
swap(&e, &smallest[j]);
}
}
if (!dup && nsmall < N_MIN) {
smallest[nsmall++] = e;
}
e = a[i];
dup = 0;
for (j = 0; j < nlarge; j++) {
if (e == largest[j]) {
dup = 1;
break;
}
if (e > largest[j]) {
swap(&e, &largest[j]);
}
}
if (!dup && nlarge < N_MAX) {
largest[nlarge++] = e;
}
}
printf("smallest values: ");
for (i = 0; i < nsmall; i++) {
printf(" %d", smallest[i]);
}
printf("\n");
printf("largest values: ");
for (i = nlarge; i --> 0;) {
printf(" %d", largest[i]);
}
printf("\n");
return 0;
}
As already noted, the most direct way to do this would be to simply sort the array. (In fact, if all you need is an output of five integers then your array only need be five elements long.) But I will presume that that is not the point of this homework.
Your goal isn’t super efficiency or a pretty algorithm. It is simply to solve the tasks. Do them one at a time.
First question: How would you find the largest value?
Answer: Loop through the array, keeping track of the largest element found so far.
int largest = array[0]; // why start with this value?
for (int n = 0; n < size; n++)
if (array[n] > largest)
largest = array[n];
Second question: How would you find the smallest value?
Answer: Almost the same way, with only a simple change: Instead of testing if (array[n] > largest) we want to test if (array[n] < smallest), right?
int smallest = largest; // why start with this value?
for (int n = 0; n < size; n++)
if (...) // new condition goes here
smallest = array[n];
Third question: How would you find the second smallest value?
Answer: It should not surprise you that you just need to change the if condition in that loop again. An element would be the second smallest if:
it is the smallest value greater than the smallest.
Think about how you would change your condition:
int second_smallest = largest; // why start with this value?
for (int n = 0; n < size; n++)
if (... && ...) // what is the new test condition?
second_smallest = array[n];
Remember, this time you are testing two things, so your test condition needs that && in it.
Fourth question: can you write another loop to find the second-largest? How about the third-largest?
At this point you should be able to see the variation on a theme and be able to write a loop that will get you any Nth largest or smallest value, as long as you already have the (N-1)th to work against.
Further considerations:
Is it possible that the third-largest is the same as the second-smallest?
Or the smallest?
Is it possible for there to not be a third-largest?
Does it matter?
Put all these loops together in your main() and print out the results each time and you are all done!
...
int main(void)
{
int array[SIZE];
// fill array with random numbers here //
int largest = array[0];
for (...)
if (...)
...
int smallest = largest;
for (...)
if (...)
...
int second_smallest = largest;
for (...)
if (...)
...
int second_largest = smallest;
for (...)
if (...)
...
int third_largest = smallest;
for (...)
if (...)
...
printf( "The original array = " );
// print original array here, then: //
printf( "largest = %d\n", largest );
printf( "2nd largest = %d\n", second_largest );
printf( "3nd largest = %d\n", third_largest );
printf( "2nd smallest = %d\n", second_smallest );
printf( "smallest = %d\n", smallest );
return 0;
}
Example outputs:
{ 1 2 3 4 }
smallest = 1
2nd smallest = 2
3rd largest = 2
2nd largest = 3
largest = 4
{ 5 5 5 5 5 }
smallest = 5
2nd smallest = 5
3rd smallest = 5
largest = 5
{ 1 2 }
smallest = 1
2nd smallest = 2
3rd smallest = 2
largest = 2
Bonus: be careful with variable names. There has been no need to use short abbreviations since before the early nineties. Prefer clarity over brevity.
I want to create a 2d array using random dimensions.
Here's my random number maker method:
int GetRandomNumber(int low, int high)
{
srand((unsigned)time(NULL));
int res = rand() % ((high + 1) - low) + low;
return res;
}
and here's the main code for now:
void main()
{
int dime = GetRandomNumber(3, 5), a = GetRandomNumber(3, 5), b = GetRandomNumber(3, 5);
int matA[a][dime];
int matB[dime][b];
system("PAUSE");
}
The problem is I get an expression must have a constant value and cannot allocate an array of constant size 0 errors.
My question is how to make a 2d array using random numbers as dimensions.
As of C99, you can define an array's size at runtime using variable length arrays:
int x = some_value();
int y = some_other_value();
int arr[x][y];
Since their size isn't determined until runtime, there are some restrictions on their use - they can't have static storage duration (i.e., they can't declared at file scope or with the static keyword), and you can't use an initializer in the declaration. You also want to be careful if x or y are large.
If you don't have a C99 or later compiler available, then this won't work. You'll have to use dynamic memory allocation instead, and you'll have to allocate it as a "jagged" array:
int x = some_value();
int y = some_other_value();
int **arr = malloc( sizeof *arr * x );
if ( arr )
{
for ( size_t i = 0; i < x; i++ )
{
arr[i] = malloc( sizeof *arr[i] * y );
}
}
When you're done, you'd deallocate as
for (size_t i = 0; i < x; i++ )
free( arr[i] );
free( arr );
This will work like any other 2D array when it comes to accessing elements:
arr[i][j] = some_value();
but be aware that the rows will not be contiguous - there will be gaps from the end of one row to the beginning of the next row. If that matters, then the last option is to declare a 1D array and manually compute the index:
int *arr = malloc( sizeof *arr * x * y );
...
arr[i * x + j] some_value();
When you're done, you'd free it as
free( arr );
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int getRandom(int digits, int start) {
return rand() % digits + start;
}
int main() {
/* Seed rand() with current time; only want to do
* this once */
srand(time(0));
/* Set row and col sizes equal to random numbers on
* the interval [1, 4]; 4 is the number of
* digits we want and 1 is where we start */
int row = getRandom(4, 1);
int col = getRandom(4, 1);
/* Declare a 2d array of row and col size */
int arr[row][col];
/* Traverse through the 2d array */
for(int i = 0; i < row; ++i) {
for(int j = 0; j < col; ++j) {
/* Set arr[i][j] to a random number in the
* interval [-10, 10]; there are 21 digits
* from -10 to 10 */
arr[i][j] = getRandom(21, -10);
/* Print the contents of the array */
printf("arr[%d][%d] = %d\n", i, j, arr[i][j]);
}
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include<time.h>
void main()
{
srand(time(0));
int dime = GetRandomNumber(3, 5), a = GetRandomNumber(3, 5), b = GetRandomNumber(3, 5),c = GetRandomNumber(3, 5);
int matA[a][dime];
int matB[dime][b];
printf("%d %d %d %d",dime,a,b,c);
//system("PAUSE");
}
int GetRandomNumber(int low, int high)
{
int res = rand() % ((high + 1) - low) + low;
return res;
}
I'm looking for a function in ANSI C that would randomize an array just like PHP's shuffle() does. Is there such a function or do I have to write it on my own? And if I have to write it on my own, what's the best/most performant way to do it?
My ideas so far:
Iterate through the array for, say, 100 times and exchange a random index with another random index
Create a new array and fill it with random indices from the first one checking each time if the index is already taken (performance = 0 complexity = serious)
Pasted from Asmodiel's link to Ben Pfaff's Writings, for persistence:
#include <stdlib.h>
/* Arrange the N elements of ARRAY in random order.
Only effective if N is much smaller than RAND_MAX;
if this may not be the case, use a better random
number generator. */
void shuffle(int *array, size_t n)
{
if (n > 1)
{
size_t i;
for (i = 0; i < n - 1; i++)
{
size_t j = i + rand() / (RAND_MAX / (n - i) + 1);
int t = array[j];
array[j] = array[i];
array[i] = t;
}
}
}
EDIT: And here's a generic version that works for any type (int, struct, ...) through memcpy. With an example program to run, it requires VLAs, not every compiler supports this so you might want to change that to malloc (which will perform badly) or a static buffer large enough to accommodate any type you throw at it:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
/* compile and run with
* cc shuffle.c -o shuffle && ./shuffle */
#define NELEMS(x) (sizeof(x) / sizeof(x[0]))
/* arrange the N elements of ARRAY in random order.
* Only effective if N is much smaller than RAND_MAX;
* if this may not be the case, use a better random
* number generator. */
static void shuffle(void *array, size_t n, size_t size) {
char tmp[size];
char *arr = array;
size_t stride = size * sizeof(char);
if (n > 1) {
size_t i;
for (i = 0; i < n - 1; ++i) {
size_t rnd = (size_t) rand();
size_t j = i + rnd / (RAND_MAX / (n - i) + 1);
memcpy(tmp, arr + j * stride, size);
memcpy(arr + j * stride, arr + i * stride, size);
memcpy(arr + i * stride, tmp, size);
}
}
}
#define print_type(count, stmt) \
do { \
printf("["); \
for (size_t i = 0; i < (count); ++i) { \
stmt; \
} \
printf("]\n"); \
} while (0)
struct cmplex {
int foo;
double bar;
};
int main() {
srand(time(NULL));
int intarr[] = { 1, -5, 7, 3, 20, 2 };
print_type(NELEMS(intarr), printf("%d,", intarr[i]));
shuffle(intarr, NELEMS(intarr), sizeof(intarr[0]));
print_type(NELEMS(intarr), printf("%d,", intarr[i]));
struct cmplex cmparr[] = {
{ 1, 3.14 },
{ 5, 7.12 },
{ 9, 8.94 },
{ 20, 1.84 }
};
print_type(NELEMS(intarr), printf("{%d %f},", cmparr[i].foo, cmparr[i].bar));
shuffle(cmparr, NELEMS(cmparr), sizeof(cmparr[0]));
print_type(NELEMS(intarr), printf("{%d %f},", cmparr[i].foo, cmparr[i].bar));
return 0;
}
The following code ensures that the array will be shuffled based on a random seed taken from the usec time. Also this implements the Fisher–Yates shuffle properly. I've tested the output of this function and it looks good (even expectation of any array element being the first element after shuffle. Also even expectation for being the last).
void shuffle(int *array, size_t n) {
struct timeval tv;
gettimeofday(&tv, NULL);
int usec = tv.tv_usec;
srand48(usec);
if (n > 1) {
size_t i;
for (i = n - 1; i > 0; i--) {
size_t j = (unsigned int) (drand48()*(i+1));
int t = array[j];
array[j] = array[i];
array[i] = t;
}
}
}
I’ll just echo Neil Butterworth’s answer, and point out some trouble with your first idea:
You suggested,
Iterate through the array for, say, 100 times and exchange a random index with another random index
Make this rigorous. I'll assume the existence of randn(int n), a wrapper around some RNG, producing numbers evenly distributed in [0, n-1], and swap(int a[], size_t i, size_t j),
void swap(int a[], size_t i, size_t j) {
int temp = a[i]; a[i] = a[j]; a[j] = temp;
}
which swaps a[i] and a[j].
Now let’s implement your suggestion:
void silly_shuffle(size_t n, int a[n]) {
for (size_t i = 0; i < n; i++)
swap(a, randn(n), randn(n)); // swap two random elements
}
Notice that this is not any better than this simpler (but still wrong) version:
void bad_shuffle(size_t n, int a[n]) {
for (size_t i = 0; i < n; i++)
swap(a, i, randn(n));
}
Well, what’s wrong? Consider how many permutations these functions give you: With n (or 2×_n_ for silly_shuffle) random selections in [0, n-1], the code will “fairly” select one of _n_² (or 2×_n_²) ways to shuffle the deck. The trouble is that there are n! = _n_×(n-1)×⋯×2×1 possible arrangements of the array, and neither _n_² nor 2×_n_² is a multiple of n!, proving that some permutations are more likely than others.
The Fisher-Yates shuffle is actually equivalent to your second suggestion, only with some optimizations that change (performance = 0, complexity = serious) to (performance = very good, complexity = pretty simple). (Actually, I’m not sure that a faster or simpler correct version exists.)
void fisher_yates_shuffle(size_t n, int a[n]) {
for (size_t i = 0; i < n; i++)
swap(a, i, i+randn(n-1-i)); // swap element with random later element
}
ETA: See also this post on Coding Horror.
There isn't a function in the C standard to randomize an array.
Look at Knuth - he has algorithms for the job.
Or look at Bentley - Programming Pearls or More Programming Pearls.
Or look in almost any algorithms book.
Ensuring a fair shuffle (where every permutation of the original order is equally likely) is simple, but not trivial.
Here a solution that uses memcpy instead of assignment, so you can use it for array over arbitrary data. You need twice the memory of original array and the cost is linear O(n):
void main ()
{
int elesize = sizeof (int);
int i;
int r;
int src [20];
int tgt [20];
for (i = 0; i < 20; src [i] = i++);
srand ( (unsigned int) time (0) );
for (i = 20; i > 0; i --)
{
r = rand () % i;
memcpy (&tgt [20 - i], &src [r], elesize);
memcpy (&src [r], &src [i - 1], elesize);
}
for (i = 0; i < 20; printf ("%d ", tgt [i++] ) );
}
The function you are looking for is already present in the standard C library. Its name is qsort. Random sorting can be implemented as:
int rand_comparison(const void *a, const void *b)
{
(void)a; (void)b;
return rand() % 2 ? +1 : -1;
}
void shuffle(void *base, size_t nmemb, size_t size)
{
qsort(base, nmemb, size, rand_comparison);
}
The example:
int arr[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
srand(0); /* each permutation has its number here */
shuffle(arr, 10, sizeof(int));
...and the output is:
3, 4, 1, 0, 2, 7, 6, 9, 8, 5
Assuming you may want to just access an array randomly instead of actually shuffling it, you can use the degenerative case of a linear congruential pseudo-random number generator
X_n+1 = (a Xn+c) mod N
where a is coprime to N
generates a random cycle over all values 0:N
Naturally you could store this sequence in an empty array.
uint32_t gcd ( uint32_t a, uint32_t b )
{
if ( a==0 ) return b;
return gcd ( b%a, a );
}
uint32_t get_coprime(uint32_t r){
uint32_t min_val = r>>1;
for(int i =0;i<r*40;i++){
uint64_t sel = min_val + ( rand()%(r-min_val ));
if(gcd(sel,r)==1)
return sel;
}
return 0;
}
uint32_t next_val(uint32_t coprime, uint32_t cur, uint32_t N)
{
return (cur+coprime)%N;
}
// Example output Array A in random order
void shuffle(float * A, uint32_t N){
uint32_t coprime = get_coprime(N);
cur = rand()%N;
for(uint32_t i = 0;i<N;i++){
printf("%f\n",A[cur]);
cur = next_val(coprime, cur, N);
}
Just run the following code first and modify it for your needs:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define arr_size 10
// shuffle array
void shuffle(int *array, size_t n) {
if (n > 1) {
for (size_t i = 0; i < n - 1; i++) {
size_t j = i + rand() / (RAND_MAX / (n - i) + 1);
int t = array[j];
array[j] = array[i];
array[i] = t;
}
}
}
// display array elements
void display_array(int *array, size_t n){
for (int i = 0; i < n; i++)
printf("%d ", array[i]);
}
int main() {
srand(time(NULL)); // this line is necessary
int numbers[arr_size] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
printf("Given array: ");
display_array(numbers, arr_size);
shuffle(numbers, arr_size);
printf("\nShuffled array: ");
display_array(numbers, arr_size);
return 0;
}
You would have something like:
You get different shuffled arrays every time you run the code:
The same answer like Nomadiq but the Random is kept simple.
The Random will be the same if you call the function one after another:
#include <stdlib.h>
#include <time.h>
void shuffle(int aArray[], int cnt){
int temp, randomNumber;
time_t t;
srand((unsigned)time(&t));
for (int i=cnt-1; i>0; i--) {
temp = aArray[i];
randomNumber = (rand() % (i+1));
aArray[i] = aArray[randomNumber];
aArray[randomNumber] = temp;
}
}
I saw the answers and I've discovered an easy way to do it
#include <stdio.h>
#include <conio.h>
#include <time.h>
int main(void){
int base[8] = {1,2,3,4,5,6,7,8}, shuffled[8] = {0,0,0,0,0,0,0,0};
int index, sorted, discart=0;
srand(time(NULL));
for(index = 0; index<8; index++){
discart = 0;
while(discart==0){
sorted = rand() % 8;
if (shuffled[sorted] == 0){
//This here is just for control of what is happening
printf("-------------\n");
printf("index: %i\n sorted: %i \n", index,sorted);
printf("-------------\n");
shuffled[sorted] = base[index];
discart= 1;
}
}
}
//This "for" is just to exibe the sequence of items inside your array
for(index=0;index<8; index++){
printf("\n----\n");
printf("%i", shuffled[index]);
}
return 0;
}
Notice that this method doesn't allow duplicated items.
And at the end you can use either numbers and letters, just replacing them into the string.
This function will shuffle array based on random seed:
void shuffle(int *arr, int size)
{
srand(time(NULL));
for (int i = size - 1; i > 0; i--)
{
int j = rand() % (i + 1);
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
In the code example, I have a function that takes as parameters a pointer to an int ordered_array and a pointer to int shuffled_array and a number representing the length of both arrays. It picks in each loop a random number from the ordered_array and inserts it into the shuffled array.
void shuffle_array(int *ordered_array, int *shuffled_array, int len){
int index;
for(int i = 0; i < len; i++){
index = (rand() % (len - i));
shuffled_array[i] = ordered_array[index];
ordered_array[index] = ordered_array[len-i];
}
}
I didn't see it among answers so I propose this solution if it can help anybody:
static inline void shuffle(size_t n, int arr[])
{
size_t rng;
size_t i;
int tmp[n];
int tmp2[n];
memcpy(tmp, arr, sizeof(int) * n);
bzero(tmp2, sizeof(int) * n);
srand(time(NULL));
i = 0;
while (i < n)
{
rng = rand() % (n - i);
while (tmp2[rng] == 1)
++rng;
tmp2[rng] = 1;
arr[i] = tmp[rng];
++i;
}
}
I'm looking for a function in ANSI C that would randomize an array just like PHP's shuffle() does. Is there such a function or do I have to write it on my own? And if I have to write it on my own, what's the best/most performant way to do it?
My ideas so far:
Iterate through the array for, say, 100 times and exchange a random index with another random index
Create a new array and fill it with random indices from the first one checking each time if the index is already taken (performance = 0 complexity = serious)
Pasted from Asmodiel's link to Ben Pfaff's Writings, for persistence:
#include <stdlib.h>
/* Arrange the N elements of ARRAY in random order.
Only effective if N is much smaller than RAND_MAX;
if this may not be the case, use a better random
number generator. */
void shuffle(int *array, size_t n)
{
if (n > 1)
{
size_t i;
for (i = 0; i < n - 1; i++)
{
size_t j = i + rand() / (RAND_MAX / (n - i) + 1);
int t = array[j];
array[j] = array[i];
array[i] = t;
}
}
}
EDIT: And here's a generic version that works for any type (int, struct, ...) through memcpy. With an example program to run, it requires VLAs, not every compiler supports this so you might want to change that to malloc (which will perform badly) or a static buffer large enough to accommodate any type you throw at it:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
/* compile and run with
* cc shuffle.c -o shuffle && ./shuffle */
#define NELEMS(x) (sizeof(x) / sizeof(x[0]))
/* arrange the N elements of ARRAY in random order.
* Only effective if N is much smaller than RAND_MAX;
* if this may not be the case, use a better random
* number generator. */
static void shuffle(void *array, size_t n, size_t size) {
char tmp[size];
char *arr = array;
size_t stride = size * sizeof(char);
if (n > 1) {
size_t i;
for (i = 0; i < n - 1; ++i) {
size_t rnd = (size_t) rand();
size_t j = i + rnd / (RAND_MAX / (n - i) + 1);
memcpy(tmp, arr + j * stride, size);
memcpy(arr + j * stride, arr + i * stride, size);
memcpy(arr + i * stride, tmp, size);
}
}
}
#define print_type(count, stmt) \
do { \
printf("["); \
for (size_t i = 0; i < (count); ++i) { \
stmt; \
} \
printf("]\n"); \
} while (0)
struct cmplex {
int foo;
double bar;
};
int main() {
srand(time(NULL));
int intarr[] = { 1, -5, 7, 3, 20, 2 };
print_type(NELEMS(intarr), printf("%d,", intarr[i]));
shuffle(intarr, NELEMS(intarr), sizeof(intarr[0]));
print_type(NELEMS(intarr), printf("%d,", intarr[i]));
struct cmplex cmparr[] = {
{ 1, 3.14 },
{ 5, 7.12 },
{ 9, 8.94 },
{ 20, 1.84 }
};
print_type(NELEMS(intarr), printf("{%d %f},", cmparr[i].foo, cmparr[i].bar));
shuffle(cmparr, NELEMS(cmparr), sizeof(cmparr[0]));
print_type(NELEMS(intarr), printf("{%d %f},", cmparr[i].foo, cmparr[i].bar));
return 0;
}
The following code ensures that the array will be shuffled based on a random seed taken from the usec time. Also this implements the Fisher–Yates shuffle properly. I've tested the output of this function and it looks good (even expectation of any array element being the first element after shuffle. Also even expectation for being the last).
void shuffle(int *array, size_t n) {
struct timeval tv;
gettimeofday(&tv, NULL);
int usec = tv.tv_usec;
srand48(usec);
if (n > 1) {
size_t i;
for (i = n - 1; i > 0; i--) {
size_t j = (unsigned int) (drand48()*(i+1));
int t = array[j];
array[j] = array[i];
array[i] = t;
}
}
}
I’ll just echo Neil Butterworth’s answer, and point out some trouble with your first idea:
You suggested,
Iterate through the array for, say, 100 times and exchange a random index with another random index
Make this rigorous. I'll assume the existence of randn(int n), a wrapper around some RNG, producing numbers evenly distributed in [0, n-1], and swap(int a[], size_t i, size_t j),
void swap(int a[], size_t i, size_t j) {
int temp = a[i]; a[i] = a[j]; a[j] = temp;
}
which swaps a[i] and a[j].
Now let’s implement your suggestion:
void silly_shuffle(size_t n, int a[n]) {
for (size_t i = 0; i < n; i++)
swap(a, randn(n), randn(n)); // swap two random elements
}
Notice that this is not any better than this simpler (but still wrong) version:
void bad_shuffle(size_t n, int a[n]) {
for (size_t i = 0; i < n; i++)
swap(a, i, randn(n));
}
Well, what’s wrong? Consider how many permutations these functions give you: With n (or 2×_n_ for silly_shuffle) random selections in [0, n-1], the code will “fairly” select one of _n_² (or 2×_n_²) ways to shuffle the deck. The trouble is that there are n! = _n_×(n-1)×⋯×2×1 possible arrangements of the array, and neither _n_² nor 2×_n_² is a multiple of n!, proving that some permutations are more likely than others.
The Fisher-Yates shuffle is actually equivalent to your second suggestion, only with some optimizations that change (performance = 0, complexity = serious) to (performance = very good, complexity = pretty simple). (Actually, I’m not sure that a faster or simpler correct version exists.)
void fisher_yates_shuffle(size_t n, int a[n]) {
for (size_t i = 0; i < n; i++)
swap(a, i, i+randn(n-1-i)); // swap element with random later element
}
ETA: See also this post on Coding Horror.
There isn't a function in the C standard to randomize an array.
Look at Knuth - he has algorithms for the job.
Or look at Bentley - Programming Pearls or More Programming Pearls.
Or look in almost any algorithms book.
Ensuring a fair shuffle (where every permutation of the original order is equally likely) is simple, but not trivial.
Here a solution that uses memcpy instead of assignment, so you can use it for array over arbitrary data. You need twice the memory of original array and the cost is linear O(n):
void main ()
{
int elesize = sizeof (int);
int i;
int r;
int src [20];
int tgt [20];
for (i = 0; i < 20; src [i] = i++);
srand ( (unsigned int) time (0) );
for (i = 20; i > 0; i --)
{
r = rand () % i;
memcpy (&tgt [20 - i], &src [r], elesize);
memcpy (&src [r], &src [i - 1], elesize);
}
for (i = 0; i < 20; printf ("%d ", tgt [i++] ) );
}
The function you are looking for is already present in the standard C library. Its name is qsort. Random sorting can be implemented as:
int rand_comparison(const void *a, const void *b)
{
(void)a; (void)b;
return rand() % 2 ? +1 : -1;
}
void shuffle(void *base, size_t nmemb, size_t size)
{
qsort(base, nmemb, size, rand_comparison);
}
The example:
int arr[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
srand(0); /* each permutation has its number here */
shuffle(arr, 10, sizeof(int));
...and the output is:
3, 4, 1, 0, 2, 7, 6, 9, 8, 5
Assuming you may want to just access an array randomly instead of actually shuffling it, you can use the degenerative case of a linear congruential pseudo-random number generator
X_n+1 = (a Xn+c) mod N
where a is coprime to N
generates a random cycle over all values 0:N
Naturally you could store this sequence in an empty array.
uint32_t gcd ( uint32_t a, uint32_t b )
{
if ( a==0 ) return b;
return gcd ( b%a, a );
}
uint32_t get_coprime(uint32_t r){
uint32_t min_val = r>>1;
for(int i =0;i<r*40;i++){
uint64_t sel = min_val + ( rand()%(r-min_val ));
if(gcd(sel,r)==1)
return sel;
}
return 0;
}
uint32_t next_val(uint32_t coprime, uint32_t cur, uint32_t N)
{
return (cur+coprime)%N;
}
// Example output Array A in random order
void shuffle(float * A, uint32_t N){
uint32_t coprime = get_coprime(N);
cur = rand()%N;
for(uint32_t i = 0;i<N;i++){
printf("%f\n",A[cur]);
cur = next_val(coprime, cur, N);
}
Just run the following code first and modify it for your needs:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define arr_size 10
// shuffle array
void shuffle(int *array, size_t n) {
if (n > 1) {
for (size_t i = 0; i < n - 1; i++) {
size_t j = i + rand() / (RAND_MAX / (n - i) + 1);
int t = array[j];
array[j] = array[i];
array[i] = t;
}
}
}
// display array elements
void display_array(int *array, size_t n){
for (int i = 0; i < n; i++)
printf("%d ", array[i]);
}
int main() {
srand(time(NULL)); // this line is necessary
int numbers[arr_size] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
printf("Given array: ");
display_array(numbers, arr_size);
shuffle(numbers, arr_size);
printf("\nShuffled array: ");
display_array(numbers, arr_size);
return 0;
}
You would have something like:
You get different shuffled arrays every time you run the code:
The same answer like Nomadiq but the Random is kept simple.
The Random will be the same if you call the function one after another:
#include <stdlib.h>
#include <time.h>
void shuffle(int aArray[], int cnt){
int temp, randomNumber;
time_t t;
srand((unsigned)time(&t));
for (int i=cnt-1; i>0; i--) {
temp = aArray[i];
randomNumber = (rand() % (i+1));
aArray[i] = aArray[randomNumber];
aArray[randomNumber] = temp;
}
}
I saw the answers and I've discovered an easy way to do it
#include <stdio.h>
#include <conio.h>
#include <time.h>
int main(void){
int base[8] = {1,2,3,4,5,6,7,8}, shuffled[8] = {0,0,0,0,0,0,0,0};
int index, sorted, discart=0;
srand(time(NULL));
for(index = 0; index<8; index++){
discart = 0;
while(discart==0){
sorted = rand() % 8;
if (shuffled[sorted] == 0){
//This here is just for control of what is happening
printf("-------------\n");
printf("index: %i\n sorted: %i \n", index,sorted);
printf("-------------\n");
shuffled[sorted] = base[index];
discart= 1;
}
}
}
//This "for" is just to exibe the sequence of items inside your array
for(index=0;index<8; index++){
printf("\n----\n");
printf("%i", shuffled[index]);
}
return 0;
}
Notice that this method doesn't allow duplicated items.
And at the end you can use either numbers and letters, just replacing them into the string.
This function will shuffle array based on random seed:
void shuffle(int *arr, int size)
{
srand(time(NULL));
for (int i = size - 1; i > 0; i--)
{
int j = rand() % (i + 1);
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
In the code example, I have a function that takes as parameters a pointer to an int ordered_array and a pointer to int shuffled_array and a number representing the length of both arrays. It picks in each loop a random number from the ordered_array and inserts it into the shuffled array.
void shuffle_array(int *ordered_array, int *shuffled_array, int len){
int index;
for(int i = 0; i < len; i++){
index = (rand() % (len - i));
shuffled_array[i] = ordered_array[index];
ordered_array[index] = ordered_array[len-i];
}
}
I didn't see it among answers so I propose this solution if it can help anybody:
static inline void shuffle(size_t n, int arr[])
{
size_t rng;
size_t i;
int tmp[n];
int tmp2[n];
memcpy(tmp, arr, sizeof(int) * n);
bzero(tmp2, sizeof(int) * n);
srand(time(NULL));
i = 0;
while (i < n)
{
rng = rand() % (n - i);
while (tmp2[rng] == 1)
++rng;
tmp2[rng] = 1;
arr[i] = tmp[rng];
++i;
}
}
My app is supposed to take a double array, find the average of elements of even columns, find the max value, compare average to max / 2 and rotate the matrix 90 degrees if average > max / 2.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <math.h>
int M = 4, N = 4;
int ** rotateArr(int arr[4][4]) {
int D[4][4];
int i, n;
for(i=0; i <= 4; i++ ){
for(n =0; n <= 4; n++){
D[i][n] = arr[n][M - i + 1];
}
}
return D;
}
int getAvg(int arr[4][4]) {
int sum = 0, num = 0;
int i, n;
for(i=0; i <= 4; i += 2){
for(n=0; n <= 4; n++){
sum += arr[i][n];
num += 1;
}
}
return sum/num;
}
int ** getMax(int arr[4][4]) {
int maxa = arr[0][0];
int i, n;
for(i=0; i <= 4; i++){
for(n=0; n <= 4; n++){
if (maxa < arr[i][n]){
maxa = arr[i][n];
}
}
}
return maxa;
}
int main()
{
int S[4][4] = { { 1, 4, 10, 3 }, { 0, 6, 3, 8 }, { 7, 10 ,8, 5 }, { 9, 5, 11, 2} };
int maxa = 0;
float avg = 0;
avg = getAvg(S);
maxa = getMax(S);
int i , n;
if (avg > maxa/2){
S[4][4] = rotateArr(S);
for(i=0; i <= 4; i+=2){
for(n=0 ; n <= 4; n++){
printf("%d", S[i][n]);
}
printf("\n");
}
}
getch();
return 0;
}
The app doesn't output anything and just ends on key press with
Process terminated with status 0 (0 minutes, 2 seconds)
There are a lot of problems with your code. For example:
All your loops are of the form for(i=0; i <= 4; i++ ) The condition should be changed to i < 4 because the valid array indices are 0 to 3.
The rotateArr function returns a pointer to a local variable. You can't do this. One solution is to receive the output array as a parameter and write into it:
void rotateArr(int arr[4][4], int output[4][4]) {
....
output[i][j] = ...;
}
int** is not the same as int[4][4].
S[4][4] = ... tries to assign to an invalid element. It looks like you're trying to assign to S itself, which can't be done (you need to assign each element, or memcpy from another array):
int anArray[4][4];
int anotherArray[4][4];
memcpy(anArray, anotherArray, sizeof(anArray));
In the expression arr[n][M - i + 1], the second index can be out of range. Consider what happens when i==0.
I suggest you pay attention to compiler warnings, as they would catch some of these issues (on GCC compiler use the -Wall option). Also, learn to use a debugger.
Analyse your program and you will find that;
You are returning D (of type int (*)[4] from rotateArr whose return type is int **. And similar issue with getMax.
For n =4 array arr[i][n] will go out of bound!
sum/num is in fact not calculating the average value (numerator and denominator both are int and you will always get an int value (may be 0 too).
and many more..........