在C语言中逐个比较两个数组的元素

10

为了使我们计算物理项目中的一个程序(不是我写的)更加动态,我一直在努力实现C语言中非常简单的一件事情:逐个元素比较两个不同的数组并在if条件语句中进行比较。

#include <math.h>
#include <stdio.h>
#include "header.h"
const int nParam = 10;
double a[nParam], a_tmp[nParam];
double values[10000];

double FitParam(double x){
    int xindex;
    double value;

    xindex=(int) x;

    if (a_tmp[1]==a[1] && a_tmp[2]==a[2] && a_tmp[3]==a[3] && a_tmp[4]==a[4]){ 
        value=values[xindex];
        return(value);
    }

// code continues... (very long subroutine and there is recursion for
// the subroutine so this if statement above is very important).

数组a[]在每次运行程序时具有不同数量的有效元素;例如,现在我们仅使用此子程序处理[1][4]元素。但是,在其他情况下,我们将希望有更少或更多的元素,例如,分别为最多3个元素或最多5个元素。

因此,我希望能够重写上面的if语句,使其动态化......换句话说,如果考虑N个元素,则它将执行

if (a_tmp[1]==a[1] && ... && a_tmp[N]==a[N]){}

因此,当我们关注的元素数量N改变时,这个if条件应该随之变化(N在文件头中定义为#define,我刚刚命名为header.h)。

非常感谢您对这项任务的支持。谢谢。


2
将“double”进行比较是一种不好的习惯。 - T.C.
3
我猜你是有意为之地避免使用循环,出于“性能原因”是吗?如果是的话,你应该运行一下分析器,以确保你手动扩展的解决方案确实更快。即使它是更快的,也有助于量化你所追求的收益。 - Pete Baughman
1
memcmp(&a_tmp[1], &a[1], 4 * sizeof a[1]); - M.M
6个回答

17

最好的方法是将其重写为一个返回true或false(1或0)的函数:

int compareArrays(double a[], double b[], int n) {
  int ii;
  for(ii = 1; ii <= n; ii++) {
    if (a[ii] != b[ii]) return 0;
    // better:
    // if(fabs(a[ii]-b[ii]) < 1e-10 * (fabs(a[ii]) + fabs(b[ii]))) {
    // with the appropriate tolerance
  }
  return 1;
}

请注意,将双精度浮点数进行相等比较通常不是好的实践方式 - 您最好比较它们的差异,并确保绝对值小于某个公差。

还要注意,您正在比较从1到n的元素 - C数组从0开始。

您可以使用上述内容:

if (compareArrays(a, a_tmp, N)) {

N 是根据您的问题 #define 的。

如果你想“聪明地”避免循环,可以编写以下代码-一旦达到正确的比较次数,它就会停止(“短路”)。比较双精度浮点数是否相等仍然是一个不好的主意,但我将在另一个时间留下解决方案(请参见上面的代码注释)。

if(a[1]==a_temp[1] && (2 > N || (a[2]==a_temp[2] && (3 > N || (a[3]==a_temp[3]))))) {

只要您比较了正确数量的项,这将使“其余部分”true - 因此它将停止评估术语(因为您需要)。 我并不认为这是更快或更好的代码 - 但它是“动态的”... 您显然可以使此表达式长度任意长; 我只写了前三个术语,以便您了解。我不建议使用它。

至于双精度数的比较,您可能考虑替换

if(a == b)

使用

if(closeEnough(a, b))

宏定义的定义位置

#define closeEnough(a, b) (fabs((a)-(b)) < 1e-10 * (fabs(a) + fabs(b)))? 1 : 0

这将确保您的双精度数不必“完全相等”-根据您的到达方式,它们几乎永远不会完全相等,并且相对容差为10的负十次方的1通常足以进行大多数实际比较。


1
+1 对比浮点数问题的扎实讨论 - dwerner
1
非常感谢您提供详细的答案!“compareArrays”应该有参数double a[]double b[]吗?同时,感谢您对双精度浮点数相等性的讨论。 - LightningXI
@LightningXI - 你是对的,参数应该是指针。我会更新。 - Floris

7
如果必须在编译时完成,标准中没有提供类似于重复宏的内容。就像另一个(问题)一样,对于有界的N,您可以准备N个宏来扩展您所需的比较。另一种选择是使用memcmp。
memcmp( data, data2, array_len_in_bytes );

{{链接1:参考资料}}


1
为了完整性:请注意,arraylen 是数组长度(以字节为单位),而不是元素数量,并且比较double类型的相等性并不是一个好主意;但使用memcmp是一个有趣的建议。 - Floris
我从未考虑过 memcmp。感谢您提供的解决方案。 - LightningXI

2

一种实现方法是遍历所有元素,并在检测到差异时设置一个标志

int i, N;
int is_equal = 1;

for (i=1; i<N; ++i) {
    if (a[i] != a_tmp[i]) {
        is_equal = 0;
        break;
    }
}

if (is_equal)
    printf("Arrays are equal");

1
请注意,问题中的代码似乎比较了从[1]开始的元素...很奇怪,但就是这样。 - Floris
1
好的观点,但我只是试图说明概念,而不是提供现成的定制代码。不过我看到我们想到了相同的概念 :) - Pankrates
是的。实际上,[0] 元素是为其他用途保留的,因此比较应从 [1] 开始应用。很抱歉没有澄清这一点。 - LightningXI

1
一个简单的实现是对两个数组进行线性比较,只需遍历数组长度并检查 if (a[i] != b[i]),如果是,则返回false并跳出迭代。

请参见以下示例:

#include <stdio.h>

int compareArrays(int a[], int b[], int n)
{
  for (int i=0; i<n; ++i)
  {
      if (a[i] != b[i])
      {
          return -1;
      }
  }
  return 0;
}

int main()
{
    int arr1[4] = {3, 4, 5, 7};
    int arr2[4] = {3, 4, 5, 7};

    int arr3[4] = {1, 5, 3, 7};
    int arr4[4] = {3, 4, 5, 19};

    printf("Should be True %d\n", compareArrays(arr1, arr2, 4));
    printf("Should be False %d\n", compareArrays(arr3, arr4, 4));
    return 0;
}

你应该得到:

Should be True 0
Should be False -1

运行此示例的在线代码:https://repl.it/@abranhe/compare-arrays-in-c


0

这个函数可以比较两个任意类型的数组,并返回第一个不相等元素的索引。如果两个数组完全相同,则返回值将是数组中元素的数量。

int compareArrays(void* arrayA, void* arrayB, uint numElements, uint elementSizeBytes)  {

    //returns -1 on error, numElememts if the arrays are equal or the index
    //of the first unequal elements

    uint i;
    uint8_t* byteArrayA;
    uint8_t* byteArrayB;

    if(elementSizeBytes < 1)    {
        return -1;
    }

    if(numElements < 1) {
        return -1;
    }

    byteArrayA = (uint8_t*) arrayA;
    byteArrayB = (uint8_t*) arrayB;

    for(i = 0; i < (numElements*elementSizeBytes); i++) {
        if(byteArrayA[i] != byteArrayB[i])  {
            break;
        }
    }

    return i / elementSizeBytes;
}

一个调用示例:

uint16_t test1[6] = {12, 15, 24, 86, 92, 15};

uint16_t test2[6] = {12, 15, 24, 86, 93, 15};

int retVal = compareArrays(test1, test2, 6, 2);

-1
今天我遇到了同样的问题陈述,我谷歌搜寻了一个小时,最终没有找到解决方案,以上所有方法都不是解决所述问题的正确方法。
更好的解决办法是:
将两个数组按升序或降序排序,然后比较两个数组。
#include<stdio.h>
 void sort_it(int a[], int size)
      {
       int i,j,temp=0;
       for(i=0;i<size;++i)
        {

        for(j=i+1;j<size;++j)

        {
            if(a[i]>a[j])
                {
                temp=a[i];
                a[i]=a[j];
                a[j]=temp;
                }
        }
    }
};

int compare(int size,int a[],int b[])
{ 
    int i,j,is_equal;
    for(i=0;i<size;i++)
    {
        for(j=0;j<size;j++)`enter code here`
        {
            if(a[i]!=b[j])
            {
            is_equal=0;
            }
            else
            is_equal=1;
        }

    }



return is_equal;
};

int main()
{
    int size=4,i,is_equal;
    int a[]={1,2,5,4};
    int b[]={1,7,4,2};

    sort_it(a,size);
    sort_it(b,size);
    is_equal=compare(4,a,b);
    if(is_equal)
        printf("arrays are equal\n");
    else
        printf("arrays are not equal\n");
    return (0);

}

问题陈述中没有任何暗示需要比较数组中元素的顺序。这可能是你需要的 - 但我不认为这是 OP 所要求的。 - Floris

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接