C array comparison
Asked Answered
M

5

6

Is the defacto method for comparing arrays (in C) to use memcmp from string.h?

I want to compare arrays of ints and doubles in my unit tests

I am unsure whether to use something like:

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

or to write a bespoke is_array_equal(a, b, n) type function?

Melodics answered 6/12, 2011 at 12:32 Comment(4)
I think you mean memcmp. memset would overwrite the first array.Universalist
IIRC memset will change (set) values in the array so that's not usefull for only comparing arrays.Scansion
yes, memcmp that is what i meant - is this considered good practice?Melodics
@Hiett: depends on what you want. memcmp compares byte-for-byte, which may not be what you want (esp. with floating-point values).Embark
E
10

memcmp would do an exact comparison, which is seldom a good idea for floats, and would not follow the rule that NaN != NaN. For sorting, that's fine, but for other purposes, you might to do an approximate comparison such as:

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;
}
Embark answered 6/12, 2011 at 12:34 Comment(6)
i see - i've written a similar function but was concerned that it was 'overkill' and I should maybe trying to use more generic library functions, not reinventing the wheel and all that. I think I will stick with your recommendationMelodics
whats the bool datatype? is that not a C++ thing?Melodics
@Hiett: since C99, bool is part of C. It's in <stdbool.h> and comes with macros true and false. If you're on MSVC, you may not have stdbool.h since that compiler only supports C89.Embark
in <stdbool.h> am I right in thinking true and false are #defines of 1 and 0, e.g. they can be used interchangeably? Thinking about how to best integrate into my existing codeMelodics
@Hiett: yes, you can assume those values for true and false.Embark
You should change it in if(!((fabs(x[i] - y[i]) <= eps)), so you can handle a NaN. In your code, a NaN value will never return a falseTit
T
6

Using memcmp is not generally a good idea. Let's start with the more complex and work down from there.


Though you mentioned int and double, I first want to concentrate on memcmp as a general solution, such as to compare arrays of type:

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

The main problem there is that implementations are free to add padding to structures at locations 1 and 2, making a bytewise comparison potentially false even though the important bits match perfectly.


Now down to doubles. You might think this was better as there's no padding there. However there are other problems.

The first is the treatment of NaN values. IEEE754 goes out of its way to ensure that NaN is not equal to any other value, including itself. For example, the code:

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

will output

Bad
Okay

illustrating the difference.

The second is the treatment of plus and minus zero. These should be considered equal for the purposes of comparison but, as the bit patterns are different, memcmp will say they are different.

Changing the declaration/initialisation of d1 and d2 in the above code to:

 double d1 = 0.0, d2 = -d1;

will make this clear.


So, if structures and doubles are problematic, surely integers are okay. After all, they're always two's complement, yes?

No, actually they're not. ISO mandates one of three encoding schemes for signed integers and the other two (ones' complements and sign/magnitude) suffer from a similar problem as doubles, that fact that both plus and minus zero exist.

So, while they should possibly be considered equal, again the bit patterns are different.

Even for unsigned integers, you have a problem (it's also a problem for signed values as well). ISO states that these representations can have value bits and padding bits, and that the values of the padding bits are unspecified.

So, even for what may seem the simplest case, memcmp can be a bad idea.

Tapetum answered 17/4, 2015 at 5:1 Comment(0)
G
5

Replace memset with memcmp in your code, and it works.

In your case (as the size both arrays arrays are identical and known during compilation) you can even do:

memcmp(a, b, sizeof(a));
Grandson answered 6/12, 2011 at 12:34 Comment(0)
A
4

The function you're looking for is memcmp, not memset. See the answers to this question for why it might not be a good idea to memcmp an array of doubles though.

Azucenaazure answered 6/12, 2011 at 12:35 Comment(0)
P
2

memcmp compares two blocks of memory for number of size given

memset is used to initialise buffer with a value for size given

buffers can be compared without using memcmp in following way. same can be changed for different datatypes.

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;
  }
}
Putrescine answered 6/12, 2011 at 13:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.