Мой цикл for добавляет 1 избыток, и я не знаю, почему

#c #loops #for-loop #epsilon

Вопрос:

В основном я пытаюсь создать программу, которая просматривает данный массив и проверяет, является ли правый элемент в 2 раза больше левого, если true вставляет среднее значение этих двух элементов в середине. После этого он распечатывает массив со вставленными элементами, а затем снова просматривает массив, подсчитывая, сколько раз появляется определенное число. Я успешно закодировал все это, используя ручку и бумагу, и записал проблему на более мелкие фрагменты, а затем закодировал ее на C, но проблема в том, что я ввожу 100 нулей (сто нулей). программа выводит, что число 0 повторяется 200 раз вместо 199. Я не знаю, почему. И извините за плохой код, моя текущая задача-научиться хорошо решать проблемы с ручкой и бумагой, после того, как я научусь этому и разовью свою логику, я постараюсь упростить код.

 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
 

Мой код

 #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", amp;n);
  } while (n <= 0 || n >= 101);

  printf("Enter elements: ");

  length = n;

  for (i = 0; i < length; i  )
    scanf("%lf", amp;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;
}
 

Комментарии:

1. Я надеюсь, что это переход к пониманию того, почему связанные списки намного лучше вставлять посередине, чем массивы.

2. @яно, я все еще изучаю C, хочу сначала ознакомиться с массивами.

3. Код проходит через конец массива. На последней итерации цикл i равен length-1 . Это означает , что выражение temp - array[i 1] считывается array[length] , но array[length] находится за пределами массива.

4. Еще не полностью изучил код, но for (i = 0; i < length-1; i ) может сработать.

5. @user3386109 это выглядит правильно для меня: godbolt.org/z/j1sPcGc6x

Ответ №1:

Вместо того, чтобы постоянно перемещать массив, гораздо проще и быстрее использовать два массива. Все, что тебе нужно, это:

 // 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;
 

Относительно prev * 1.5 :

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

Включено в надлежащую функцию:

 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;
}
 

Комментарии:

1. Как я уже писал, я все еще изучаю задачи только для начинающих, я не понимаю половины написанного вами кода, я не думаю, что я делаю что-то хорошее для себя, просто копируя и вставляя код :/

2. Здесь нет ничего, что бы вы не использовали, кроме использованного malloc вместо жесткого кодирования размера массивов. Просто игнорируйте все до int i = 0; и после цикла. См. обновление

3. Хорошо, я понял предыдущее * 1.5. Большое вам спасибо за разъяснения, ребята. Поскольку я все еще новичок в stackoverflow, я не знаю, как представить вас 1, ребята, но я думаю, что вам это все равно не нужно от меня. Большое вам спасибо @ikegami

4. Вы нажимаете на стрелку вверх рядом со столбом. Для этого может быть минимальная репутация?

5. Да, сэр, 15 повторений