Unexpected output for this following code [duplicate] - arrays

This question already has answers here:
How to find the size of an array (from a pointer pointing to the first element array)?
(17 answers)
Closed 2 years ago.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int a1(int *a)
{
int middleItem;
int midIndex;
if (a == NULL || sizeof(a) % 2 == 0)
return 0;
midIndex = sizeof(a) / 2 ;
middleItem = a[midIndex];
for (int i=0; i<sizeof(a); i++)
{
if (i != midIndex && middleItem >= a[i])
return 0;
}
return 1;
}
int main()
{
int a[] = {9};
for (int i=0; i<sizeof(a); i++)
{
a1(a[i]);
}
return 0;
}
An array with an odd number of elements is said to be centered if all elements (except the middle one) are strictly greater than the value of the middle element. Note that only arrays with an odd number of elements have a middle element.
output:
returns 1 if it is a centered array, otherwise, it returns 0.

sizeof(a) is number of bytes in a and it is not necessarily same as the number of elements in the array a.
It is even worse in the function a1: now sizeof(a) is the size of pointer and you cannot get number of elements from that, so you have to pass it separately.
Passing a[i] as the first argument of a1 is wrong because a[i] is an integer while a pointer is required for the argument.
You will want to output what the function returned.
Try this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int a1(int *a, int size)
{
int middleItem;
int midIndex;
if (a == NULL || size % 2 == 0)
return 0;
midIndex = size / 2 ;
middleItem = a[midIndex];
for (int i=0; i<size; i++)
{
if (i != midIndex && middleItem >= a[i])
return 0;
}
return 1;
}
int main()
{
int a[] = {9};
int size = sizeof(a) / sizeof(*a);
printf("%d\n", a1(a, size));
return 0;
}

Related

Determine the three maximum and two minimum values of the array

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.

My pointer in an array doesn't work as it supposed to

I wanted to create a function, that would accept an 1:array_of_int, and 2:size_of_array, then return sum of the 3 biggest int. Code follows:
#include <stdio.h>
#include <stdlib.h>
int max_3(int arr[], int asize)
{
int max_arr[3];
int max =0;
int sum = 0;
int* pi;
for(int j=0; j<3; j++)
{
for(int i =0; i<asize;i++)
{
if(arr[i] > max)
{
max = arr[i];
pi = (arr + i); // to know the address of the max int of 'i' cycle
}
}
max_arr[j] = max;
*pi = 0; // make the max int = 0 so that the next 'i' cycle doesnt have the previous max in it
//(so it can look for another max value - the second one)
}
for(int i=0; i<3; i++)
sum += max_arr[i];
return sum;
}
int main (int argc, char** argv) {
int arr[6] = {1,5,9,12,16,14};
printf("%i\n",max_3(arr, 6));
return (EXIT_SUCCESS);
}
The pointer pi doesn't make the value of the current max value 0, and the next cycle in for (int i..) make the biggest one again as from the previous. So instead of returning max val1 + val2 + val3, it returned 3 * val1 (the biggest one) -- in my particular example - it printed out 48 instead of 42 (12 + 16 + 14) - as it should. But how when I make the value of address (which my pointer point to) as 0? I do not understand that properly.
Your if statement:
if (arr[i] > max)
isn't going to be entered after the first time you find max (i.e. when j > 0).
You need to zero it after:
max_arr[j] = max;
max = 0;
The following proposed code:
performs the desired functionality
is very straight forward in its' algorithm
incorporates a bubble sort for selecting the top three entries in the array
eliminates the 'magic' number 6
modifies the second parameter to type size_t as that is the type returned by sizeof()
the expression: sizeof(arr)/sizeof(arr[0]) lets compiler calculate number of entries in array
the statement: int arr[] = {1,5,9,12,16,14}; lets compiler allocate room for array
avoids modifying the original array, when sorting
and now, the proposed code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h> // memcpy()
void swap(int *xp, int *yp)
{
int temp = *xp;
*xp = *yp;
*yp = temp;
}
// A function to implement bubble sort
void bubbleSort(int arr[], size_t n)
{
size_t i;
size_t j;
for (i = 0; i < n-1; i++)
{
// Last i elements are already in place
for (j = 0; j < n-i-1; j++)
{
if (arr[j] > arr[j+1])
{
swap(&arr[j], &arr[j+1]);
}
}
}
}
int max_3(int arr[], size_t asize)
{
int localArray[ asize ];
memcpy( localArray, arr, asize*sizeof( int ) );
// sort array
bubbleSort( localArray, asize );
// calculate sum of max 3 entries
int sum = localArray[asize-1] + localArray[asize-2] + localArray[asize-3];
return sum;
}
int main ( void )
{
int arr[] = {1,5,9,12,16,14};
printf( "%i\n", max_3( arr, sizeof(arr)/sizeof(arr[0])) );
return (EXIT_SUCCESS);
}
a run of the proposed code results in:
42
After the very first iteration of the outer loop (the loop for(int j=0; j<3; j++)) the value of max and pi will never change.
In that first iteration of the outer loop, you will find that the fifth element in the array will be largest, max will be equal to 16 and pi will point to that element. You set max_arr[0] to 16 and set *pi to zero. Then the outer loop starts over with max still being equal to 16. And now there will be no value in the array that will be equal or larger than that. So you set max_arr[1] to 16 as well, and set *pi (where pi is still pointing to the fifth element) to zero again. And the same thing the next iteration.
The natural solution would be to define max and pi inside the outer loop:
for(int j=0; j<3; j++)
{
// The variables will be redefined and reinitialized each iteration of the loop
int max = 0;
int *pi;
for(int i =0; i<asize;i++)
{
if(arr[i] > max)
{
max = arr[i];
pi = (arr + i); // to know the address of the max int of 'i' cycle
}
}
max_arr[j] = max;
*pi = 0; // make the max int = 0 so that the next 'i' cycle doesnt have the previous max in it
//(so it can look for another max value - the second one)
}
There are a few other problems with the code, like for example the possibility that pi will never be initialized. I leave it as an exercise to the reader to figure when that will happen and how to solve it.

C program - How to check array elements [duplicate]

This question already has answers here:
C sizeof a passed array [duplicate]
(7 answers)
Closed 6 years ago.
I have a function repsEqual that takes an array and integer and returns 1 if the array contains only digits of the number in the same order that appear in the same number. Otherwise it returns 0.
int repsEqual(int a[], int len, int n)
If a is {3,2,0,5,3} and n is 32053 return 1 because the array contains only the digits of the number in same order as they are in the number.
If a is {0,3,2,0,5,3} and n is 32053 return 1; we can ignore leading zeros.
I tried like this
int repsEqual(int a[], int len, int n)
{
int len = sizeof(a)/sizeof(a[0]);
//storing elements in array
for(int i=0;i<len;i++)
{
scanf("%d", &a[i]); //eg storing:3 2 0 5 3
}
//asking user integer number and storing in next array
scanf("%d",&a2[num]);//eg 32053
}
Now I need to check if a2 elements are in same order as a1, but do not know how to get started.
This is what you want
int repsEqual(int a[], int len, int n)
{
for (int i = 0; i < len; i++)
{
if (a[len - i - 1] == n % 10)
n /= 10;
else
return 0;
}
//For cases where your number-length is longer than your array length
if (n != 0) return 0;
return 1;
}
First you have your array, say like a[5] = { 5, 2, 3, 1, 4}
Basically what i do is looping the array from end to start, thats a[len - i - 1]
Then i check it with the last character of n thats n%10
So example with n = 52314, the first if statement check if (52314 % 10) which is 4 equal with a[4] which is also 4
if the 2 character match then the loop continue first by remove the last character of n: 52314 / 10 = 5231.
And the next loop will check for 5231 % 10 and a[3]
else the loop break mid-way and return 0 indicate that a mis-match is found
finally after all the character in array is checked and no mismatch is found, it will return 1, as the pattern match
Note: a function should only does what its name says
In your case, check if an array and an integer have the same pattern
User input should be put outside somewhere else, after you have the inputs (the array, the len, and n) you then pass-in to repsEqual for checking
Try matching the number (n) backwards against the array 'a'. To do this you'll want to modulus the smallest digit from 'n', by getting the remainder from dividing by 10. Then remove the smallest digit from 'n' by dividing by 10.
int repsEqual(int a[], int len, int n)
{
int i;
int temp;
if (0 == len || NULL == a)
return 0; // no array, or elements, doesn't match a real number (n).
temp = n;
for (i = len - 1; i >= 0; --i)
{
if (a[i] != (temp % 10))
return 0; // remainder mismatch against array element.
temp = temp / 10; // removes the smallest digit.
}
return 1;
}
By modulus 10 on your n you get the remainder of dividing by 10. IE 452 % 10 = 2. Then by dividing be ten we remove the smallest digit IE 452 / 10 = 45.
This seems to be some homework, haha. Anyway I gave u a quick/ugly sample to start with.
#include <stdio.h>
int repsEqual(int a[],int len , int n)
{
char str[100];
sprintf(str, "%d", n);
int i;
int nonzeroIndex;
for(i=0; i<len; i++){
if (a[i] != 0)
break;
}
nonzeroIndex = i;
printf("nonzeroIndex is %d\n", nonzeroIndex);
for(i= nonzeroIndex; i <len; i++){
if (a[i] != str[i - nonzeroIndex] - 48) {
printf("diff at %d\n", i);
return 0;
}
}
return 1;
}
int main()
{
int a[5];
a[0] = 0;
a[1] = 2;
a[2] = 0;
a[3] = 5;
a[4] = 3;
int output = repsEqual(a, 5, 2053);
printf("result: %d\n", output);
}

keeping track of the original indices of an array after sorting in C

I have an array let's say A[5], the 5 elements are 5,4,1,2,3. Now I sort these arrays in ascending order. so the resulting array will now be 1,2,3,4,5. I use qsort() function of stdlib.h to sort this. The question is how can I get the indices of the original array with respect to my new array. originally my indices were 0,1,2,3,4 for corresponding values of 5,4,1,2,3 and now the indices have changed to 2,3,4,1,0. How can I get these indices efficiently in C? Thank you in advance(please write the code if possible)
There is also a method as follows under limited conditions.
#include <stdio.h>
int main(void){
int data[] ={ 5,4,1,2,3 }; //Without duplication, The number of limited range.
int size = sizeof(data)/sizeof(*data);
int keys[size];
int i;
printf("data :\n");
for(i=0;i<size;i++){
printf("%d ",data[i]);
}
for(i=0;i<size;i++){
keys[data[i]-1]=i;
}
printf("\n\ndata\tindex\n");
for(i=0;i<size;i++){
printf("%d\t%d\n", data[keys[i]], keys[i]);
}
return 0;
}
/* result sample
data :
5 4 1 2 3
data index
1 2
2 3
3 4
4 1
5 0
*/
How to sort an array of index #Kerrek is as proposed.
#include <stdio.h>
#include <stdlib.h>
int *array;
int cmp(const void *a, const void *b){
int ia = *(int *)a;
int ib = *(int *)b;
return array[ia] < array[ib] ? -1 : array[ia] > array[ib];
}
int main(void){
int data[] ={ 5,4,1,2,3 };
int size = sizeof(data)/sizeof(*data);
int index[size];//use malloc to large size array
int i;
for(i=0;i<size;i++){
index[i] = i;
}
array = data;
qsort(index, size, sizeof(*index), cmp);
printf("\n\ndata\tindex\n");
for(i=0;i<size;i++){
printf("%d\t%d\n", data[index[i]], index[i]);
}
return 0;
}
Take a 2D array. Store the numbers is first column and then corressponding indexes in second column. You can write your comparator function as:
int compare ( const void *pa, const void *pb )
{
const int *a = pa;
const int *b = pb;
if(a[0] == b[0])
return a[1] - b[1];
else
return a[0] - b[0];
}
Call to qsort should be:
qsort(array, n, sizeof array[0], compare); // n is representing rows
See the Live Demo
Based on Kerrek SB's brilliant idea I made an implementation that works for any array type by providing its element size and a comparator function for that type.
_Thread_local uint8_t *array_to_order;
_Thread_local size_t elem_size_to_order;
_Thread_local int (*cmp_for_ordering)(const void *, const void *);
int cmp_array_entry(const size_t *a, const size_t *b)
{
return cmp_for_ordering(&array_to_order[*a * elem_size_to_order], &array_to_order[*b * elem_size_to_order]);
}
size_t *make_order_index_array(void *array, size_t *order, size_t elem_count, size_t elem_size, int (*cmp)(const void *, const void *))
{
// If order is provided by the caller it should have suitable contents, such as when updating an order
// Initialise the order array if not already provided
if (order == NULL)
{
order = calloc(elem_count, sizeof(size_t));
// Initialise the order array to the unsorted indices
for (size_t i=0; i < elem_count; i++)
order[i] = i;
}
// Globals used by the comparison function to order the array
array_to_order = array;
elem_size_to_order = elem_size;
cmp_for_ordering = cmp;
// Order the order array
qsort(order, elem_count, sizeof(size_t), cmp_array_entry);
return order;
}
_Thread_local is something that we should be able to take for granted for writing such code when we're forced to use globals but should worry about thread safety. Mine is defined with the following macros:
#if defined(_MSC_VER) && !defined(_Thread_local)
#define _Thread_local __declspec(thread)
#endif
#if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201102L)) && !defined(_Thread_local)
#if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__)
#define _Thread_local __thread
#endif
#elif defined(__GNUC__) && defined(__GNUC_MINOR__) && (((__GNUC__ << 8) | __GNUC_MINOR__) < ((4 << 8) | 9))
#define _Thread_local __thread
#endif
#include <limits.h>
#include <stdio.h>
#define SIZE 5
int* sortArrayNKeepIndices(int arr[], int arrSize){
static int indexArr[SIZE];
int arr2[arrSize];
for (int i = 0; i < arrSize; i++) {
indexArr[i] = 0;
arr2[i] = arr[i];
}
int min = 0, temp = 0;
for (int i = 0; i < arrSize ; i++)
{
min = i; // record the position of the smallest
for (int j = i + 1; j < arrSize; j++)
{
// update min when finding a smaller element
if (arr[j] < arr[min])
min = j;
}
// put the smallest element at position i
temp = arr[i];
arr[i] = arr[min];
arr[min] = temp;
} // array sorting ends here
int ctr = 0;
while ( ctr < arrSize) {
min = 0; // restart from first element
for (int j = 0; j < arrSize; j++)
{
if (arr2[j] == INT_MAX) continue; // ignore already marked as minimum indices
// update min when finding a smaller element
if (arr2[j] < arr2[min])
min = j;
}
indexArr[ctr] = min; // updating indexArr with the index of the next minimum
arr2[min] = INT_MAX; // marking minimum element to be ignored next time
ctr++;
} //keeping track of previous indices of the array elements ends here
return indexArr;
} // function sortArrayKeepIndices ends here
int main () {
int arr[SIZE] = {16, 15, 12, 10, 13};
int* ptr = sortArrayNKeepIndices(arr, SIZE);
for (int dex = 0; dex < SIZE; dex++){
printf("%d (%d, %d)\t", arr[dex], * (ptr + dex), dex);}
}
// output will be 10 (3, 0) 12 (2, 1) 13 (4, 2) 15 (1, 3) 16 (0, 4)
// element (old index, new index)

C Mergesort Segfault

Situation
I was trying to implement a more interesting mergesort that creates a random length array with random values and then randomizes them, but after debugging and compiling it segfaults. I don't know why it segfaults, but I'm sure it's related to memory allocation.
Question
Why does this code cause a segfault?
Code
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
// Declare some stuff up front
int array_size(int *array);
int print_array(int *array);
//Some decade old main function coming at you
int main() {
//Concerned with the integrity of my rand
srand( (unsigned)time( NULL ));
//A global, random length array between 1 and 100?
int *array;
array = malloc(sizeof(*array) * ((rand() % 100) + 1));
init_array(*array);
getchar();
return 0;
}
int init_array(int *array) {
//Base case
array[0] = 1;
//random values for i in array
int i;
for(i = 1; i <= array_size(array); i++) {
array[i] = rand() % array_size(array) + 1;
}
//randomize the random values in the random length array
for (i = 0; i < (array_size(array) - 1); i++)
{
unsigned int swapA = (rand() % array_size(array)) + 1;
int a = array[swapA];
array[swapA] = array[i];
array[i] = a;
}
//output random array, then mergeSort the array
print_array(array);
sort_array(array);
return 0;
}
//Get my array.Length
int array_size(int *array) {
return sizeof(array)/sizeof(array[0]);
}
//Output array
int print_array(int *array) {
int i;
for(i = 0; i < (array_size(array) + 1); i++) {
printf("%d\n", array[i]);
}
return 0;
}
//merge the array after sorting
void merge_array(int *array, int low, int split, int high) {
int sorted[high-low+1];
int a = 0;
int b = low;
int c = split + 1;
//iterate from beginning to middle and from middle to end in parallel
while(b <= split && c <= high)
{
if(array[b] < array[c])
{
sorted[a++] = array[b++];
}
else
{
sorted[a++] = array[c++];
}
}
while(b <= split) sorted[a++] = array[b++];
while(c <= high) sorted[a++] = array[c++];
int i;
for(i = 0; i < a; i++) {
array[i+low] = sorted[i];
}
print_array(array); //Print sorted array
}
//Sort the array
int sort_array(int *array, int low, int high) {
int split = ( low + high ) / 2;
if( low < high ) {
sort_array(array, low, split);
sort_array(array, split + 1, high);
merge_array(array, low, split, high);
}
}
return sizeof(array)/sizeof(array[0]);
The above statement evaluates to 1 (assuming sizeof(int *) = sizeof(int), as pointed out by H2CO3).
Try something like this,
int main() {
//Concerned with the integrity of my rand
srand( (unsigned)time( NULL ));
//A global, random length array between 1 and 100?
int *array;
int number_of_elements = (rand() % 100) + 1;
array = malloc(sizeof(*array) * num_of_elements);
init_array(*array, num_of_elements);
getchar();
return 0;
}
Pass the number of elements as arguments to init_array instead of calculating it every time.
This seems to be the problem:
//Get my array.Length
int array_size(int *array) {
return sizeof(array)/sizeof(array[0]);
}
You essentially return sizeof(int*)/sizeof(int), which is not what you want. This whole thing appears because arrays decay into pointers when passed to functions.
You should read the Arrays and Pointers section in the comp.lang.c FAQ for edification.
What happens when you run your program with /WALL? What warnings are being spat out? Why?
What happens when you step through your program with a debugger attached? What is the value of each variable at each line? Why?
There are several problems with your code:
You don't check the result of malloc to see if it returned NULL.
You are passing the dereference of array to init_array, i.e. you are sending the first int of the array to init_array which then promptly dereferences it. Since malloc returns garbage data, you're dereferencing a random number inside of init_array.
array_size is not magic. If you do not track the size of your arrays in C, you cannot retrospectively find out how big you wanted them to be. You need to remember the size of the array and pass it to init_array.

Resources