Сравнение массива C - PullRequest
       36

Сравнение массива C

5 голосов
/ 06 декабря 2011

Является ли метод defacto для сравнения массивов (в C) для использования memcmp из string.h?

Я хочу сравнить массивы целых и двойных в моих модульных тестах

IЯ не уверен, использовать ли что-то вроде:

double a[] = {1.0, 2.0, 3.0};
double b[] = {1.0, 2.0, 3.0};
size_t n = 3;
if (! memcmp(a, b, n * sizeof(double)))
    /* arrays equal */

или написать функцию типа is_array_equal(a, b, n) на заказ?

Ответы [ 5 ]

9 голосов
/ 06 декабря 2011

memcmp будет делать точное сравнение, которое редко является хорошей идеей для поплавков, и не будет следовать правилу, что NaN! = NaN. Для сортировки это нормально, но для других целей вы можете сделать приблизительное сравнение, например:

bool dbl_array_eq(double const *x, double const *y, size_t n, double eps)
{
    for (size_t i=0; i<n; i++)
        if (fabs(x[i] - y[i]) > eps)
            return false;
    return true;
}
5 голосов
/ 17 апреля 2015

Использование memcmp обычно не очень хорошая идея.Давайте начнем с более сложного и продолжим работу.


Хотя вы упомянули int и double, я сначала хочу сосредоточиться на memcmp в качестве общего решения, такого как сравнениемассивы типа:

struct {
    char c;
    // 1
    int i;
    // 2
}

Основная проблема заключается в том, что реализации могут свободно добавлять заполнение к структурам в местоположениях 1 и 2, что делает байтовое сравнение потенциально ложным, даже если важные биты идеально совпадают.


Теперь до двойников.Вы могли бы подумать, что это было лучше, так как там нет отступов.Однако есть и другие проблемы.

Первая - обработка значений NaN.IEEE754 делает все возможное, чтобы гарантировать, что NaN не равно любому другому значению, включая его самого.Например, код:

#include <stdio.h>
#include <string.h>

int main (void) {
    double d1 = 0.0 / 0.0, d2 = d1;

    if (d1 == d2)
        puts ("Okay");
    else
        puts ("Bad");

    if (memcmp (&d1, &d2, sizeof(double)) == 0)
        puts ("Okay");
    else puts
        ("Bad");

    return 0;
}

будет выводить

Bad
Okay

, иллюстрирующую разницу.

Второй - обработка плюс и минус ноль.Их следует считать равными для целей сравнения, но, поскольку битовые комбинации различны, memcmp скажет, что они различны.

Изменение объявления / инициализации d1 и d2 в приведенном вышекод для:

 double d1 = 0.0, d2 = -d1;

прояснит это.


Итак, если структуры и двойники проблематичны, конечно, целые числа в порядке.В конце концов, они всегда дополняют друг друга, да?

Нет, на самом деле это не так.ИСО обязывает одну из трех схем кодирования целых чисел со знаком, а две другие (дополнения и знак / величина) страдают от аналогичной проблемы, связанной с двойными числами, в том смысле, что существуют как плюс, так и минус ноль.

Итак, в то время каквозможно, их следует считать равными, опять же, битовые комбинации различаются.

Даже для беззнаковых целых чисел у вас есть проблема (это также проблема для знаковых значений).ISO заявляет, что эти представления могут иметь биты значения и биты заполнения, и что значения битов заполнения не определены.

Таким образом, даже для того, что может показаться самым простым случаем, memcmp может быть плохой идеей.

5 голосов
/ 06 декабря 2011

Замените memset на memcmp в вашем коде, и это работает.

В вашем случае (так как размеры обоих массивов идентичны и известны во время компиляции), вы даже можете сделать:

memcmp(a, b, sizeof(a));
3 голосов
/ 06 декабря 2011

Функция, которую вы ищете: memcmp, , а не memset. См. Ответы на этот вопрос , чтобы узнать, почему не может быть хорошей идеей memcmp массив значений типа double.

2 голосов
/ 06 декабря 2011

memcmp сравнивает два блока памяти по количеству заданного размера

memset используется для инициализации буфера со значением заданного размера. Буферы

можно сравнивать без использования memcmp следующим образом.То же самое можно изменить для разных типов данных.

int8_t array_1[] = { 1, 2, 3, 4 }
int8_t array_2[] = { 1, 2, 3, 4 }

uint8_t i;
uint8_t compare_result = 1;

for (i = 0; i < (sizeof(array_1)/sizeof(int8_t); i++)
{
 if (array_1[i] != array_2[i])
  {
   compare_result = 0;
   break;
  }
}
...