2

Basically im trying to make a program that loops through the given array, and checks if the right element is 2x bigger than the left one, if true inserts average value of those two elements in the middle. After that, it prints out the array with inserted elements, and then loops through the array again, counting how many times a certain number appears. I coded all of it successfully using pen and paper and writing the problem into smaller chunks and then coding it in C but the problem is when i enter 100 zeros (one hundred zeros). the program prints out that the number 0 is repeated 200 times instead of 199. I do not know why. And sorry for the code being bad, my current task is to get good at solving problems with pen and paper, after i become decent at that and develop my logic, i will try making the code simpler.

Input sample: 
Enter the number of elements: 100
Enter the array: 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
After adding middle element: 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002.33412e-310 
The number is repeated 200 time/s

My code

#include <math.h>
#include <stdio.h>

#define EPSILON 0.0001

int main() {
  int n, i, j, k, digit, length = 0, digit_array[10] = {0};
  double array[200], temp;
  do {
    printf("Enter number of elements: ");
    scanf("%d", &n);
  } while (n <= 0 || n >= 101);

  printf("Enter elements: ");

  length = n;

  for (i = 0; i < length; i++)
    scanf("%lf", &array[i]);

  for (i = 0; i < length; i++) {
    temp = array[i] + array[i];
    if (fabs(temp - array[i + 1]) < EPSILON) {
      for (j = length; j > i + 1; j--)
        array[j] = array[j - 1];
      array[i + 1] = (array[i] + array[i + 1]) / 2.;
      i++;
      length++;
    }
  }

  printf("After adding middle element: \n");
  for (i = 0; i < length; i++)
    printf("%g ", array[i]);

  for (i = 0; i < length; i++) {
    temp = array[i];
    digit = ((int)(temp * 10)) % 10;
    digit_array[digit]++;
  }
  printf("\n");

  for (i = 0; i < 10; i++) {
    if (digit_array[i] != 0)
      printf("Number %d is repeated %d time/s.\n", i, digit_array[i]);
  }

  return 0;
}
casual
  • 39
  • 6
  • I hope this is a segue into why linked lists are so much better for inserting in the middle than arrays. – yano Oct 27 '21 at 20:38
  • @yano im still learning C, want to get familiar with arrays first. – casual Oct 27 '21 at 20:45
  • 1
    The code is going past the end of the array. In the last iteration of the loop `i` is equal to `length-1`. Which means the expression `temp - array[i+1]` is reading `array[length]`, but `array[length]` is past the end of the array. – user3386109 Oct 27 '21 at 20:48
  • When you say 2x bigger, do you mean *exactly* 2x bigger (within some epsilon), or *at least* 2x bigger? – ikegami Oct 27 '21 at 20:53
  • Note that one way to debug this problem is to reduce the number of zeros to a much smaller number, e.g. 4. Then either A) step through the code with a debugger, or B) add a whole bunch of printfs to the code to display all the variables on every iteration of the loop. – user3386109 Oct 27 '21 at 20:55
  • @ikegami exactly 2x bigger within some epsilon – casual Oct 27 '21 at 21:00
  • @user3386109 How could i fix it? Could i add a concjunction in if where i use fabs like this, if (fabs(temp - array[i + 1]) < EPSILON && i+1<=100) – casual Oct 27 '21 at 21:00
  • 1
    Haven't fully reviewed the code, but `for (i = 0; i < length-1; i++)` might work. – user3386109 Oct 27 '21 at 21:02
  • @user3386109 Fixed it by adding -1 to the for loop, now i am having "*** stack smashing detected ***: terminated" – casual Oct 27 '21 at 21:08
  • 1
    @user3386109 that looks correct to me: https://godbolt.org/z/j1sPcGc6x – yano Oct 27 '21 at 21:09
  • @user3386109 thank you so much sir <3 – casual Oct 27 '21 at 21:18

1 Answers1

2

Rather than constantly shifting the array, it's a lot easier and faster to use two arrays. All you need is this:

// Inputs:
//   n: The number of inputs.
//   a: An array of at least n doubles containing the inputs.
//   b: An array of at least n*2-1 doubles that will containing the outputs.

// Outputs:
//   m: The number of outputs.
//   b: An array of at least m doubles containing the outputs.

size_t i = 0;
size_t j = 0; 

double prev = b[j++] = a[i++];

while (i < n) {
   double next = a[i];
   if (fabs(prev*2 - next) < EPSILON) {   // If a[i-1] exactly equal a[i]*2.
      b[j++] = next / 2.0 + prev / 2.0;   // Or: b[j++] = prev * 1.5;
   }

   prev = b[j++] = a[i++];
}

size_t m = j;

Regarding prev * 1.5:

average(next, prev)
= ( next + prev ) / 2
= ( prev * 2 + prev ) / 2
= ( prev * 3 ) / 2
= prev * 1.5

Included in a proper function:

int f(double *a, size_t n, double **b_ptr, size_t *m_ptr) {
   double b = malloc( (n*2-1) * sizeof(double) );  // We need up to this much.
   if (b == NULL) {
      *b_ptr = NULL;
      return 0;
   }

   size_t i = 0;
   size_t j = 0; 

   double prev = b[j++] = a[i++];

   while (i < n) {
      double next = a[i];
      if (fabs(prev*2 - next) < EPSILON) {   // If a[i-1] exactly equal a[i]*2.
         b[j++] = next / 2.0 + prev / 2.0;   // Or: b[j++] = prev * 1.5;
      }

      prev = b[j++] = a[i++];
   }

   b = realloc(b, j * sizeof(double));  // Free the excess. (Optional)
   size_t m = j;

   *b_ptr = b;
   *m_ptr = m;
   return 1;
}
ikegami
  • 367,544
  • 15
  • 269
  • 518
  • As i wrote, i am still only learning beginner tasks, i do not understand half of the code you wrote, I dont think im doing any good to myself by just copy-pasting the code :/ – casual Oct 27 '21 at 21:09
  • There's nothing in here that you didin't use except used malloc instead of hardcoding the size of the arrays. Just ignore everything before `int i = 0;` and after the loop. See update – ikegami Oct 27 '21 at 21:15
  • Okay i understood the prev * 1.5. Thank you so much for clarification guys. As im still new to stackoverflow, i do not know how to rep +1 you guys, but i think you do not need it from me anyways. Thank you so much @ikegami – casual Oct 27 '21 at 21:18
  • You hit the up arrow next to the post. There might be a minimum reputation for that? – ikegami Oct 27 '21 at 21:20
  • Yes sir, 15 rep – casual Oct 27 '21 at 21:20