为什么我不能在 C 中仅使用 1 个相等运算符来检查多个条件?

Why can't I check multiple conditions using only 1 equality operator in C?

在我下面的代码中,a 是一个字符数组,我的 if 语句正在检查特定字符是否为 ADOQRP

if条件中检查条件的常规方法如下代码所示。

/代码段/

scanf("%s",a);
len=strlen(a);
for(i=0;i<len;i++)
{
        if(a[i]=='A'||a[i]=='D'||a[i]=='O'||a[i]=='Q'||a[i]=='R'||a[i]=='P')
             //Do something
}           

我的疑问:

1) 假设我这样写 if 语句:

if(a[i]=='A'||'D'||'O'||'Q'||'R'||'P')

为什么它的行为方式与我在上面代码片段中的 if 语句的行为方式不同?这个声明是如何工作的?

2) 如果我想检查多个条件(比方说成百上千个条件)怎么办,我怎样才能只使用一个相等运算符进行检查,而不必像这样使用多个相等运算符:

if(a[i]=='A'||a[i]=='D'||a[i]=='O'||a[i]=='Q'||a[i]=='R'||a[i]=='P')

可以吗?如果是,如何?如果不是,为什么?

a[i]=='A'

== 运算符作用于 LHS 和 RHS 上的操作数,所以如果你有

(a[i] == 'A' || 'B' ||......)

然后 == 将处理 a[i] == 'A',如果结果为 TRUE,则其余操作数不会被评估为 (1 || 0 == 1)

答案是您不能使用单个 == 运算符来检查多个条件。

有两件事要检查,

  1. Operator Precedence,这表明 ==||

  2. 具有更高的优先级
  3. || 运算符本身,它要求[第 6.5.14 章,C99]

the || operator guarantees left-to-right evaluation; there is a sequence point after the evaluation of the first operand. If the first operand compares unequal to 0, the second operand is not evaluated.

答案 1)

所以,对于

这样的表达式
if(a[i]=='A'||'D'||'O'||'Q'||'R'||'P')

评价会这样,

  1. if a[i]=='A'为TRUE,则ifreturnsTRUE/成功,其他操作数不求值。

  1. if a[i]=='A' 为 FALSE,然后检查下一个操作数 D [ASCII 值],其计算结果始终为 TRUE。

无论哪种方式,只有 一个 a[i] 值进行比较。 || 的其他操作数只是 values。没有比较。

答案2)

因此您无法使用单个 == 来检查多个值的(不)相等性。但是,您可以改用 switch 语句。

如果 a[i] 的值与 case 中的 任何 匹配,将执行所需的代码块。

switch (a[i])
  case 'A':
  case 'D':
  case 'O':
  case 'Q':
  case 'R':
  case 'P':
            //some code
            break;

在 c 中,每个非空值的计算结果都为真。

当你这样写的时候:

if(a[i]=='A'||'D'||'O'||'Q'||'R'||'P')

你可以这样想:

if(a[i]=='A' || true || true , ...)

所以你的陈述永远是正确的!

有更多的可能性可以做这样的检查,这取决于哪一个是最好的:

switch(a[i]) {
  case 'A':
  case 'D':
  case 'O':
  case 'Q':
  case 'R':
  case 'P':
    // your if code here
    break;
  default:
    // your else code here
    break;
}

char check[6] = {'A','D','O','Q','R','P'};
for(int j = 0; j < 6; j++)
  if(check[j]==a[i]) {
    // your code
    break;
  }

或者如果您可以对值进行分组:

if(a[i] > 'A' && a[i] < 'D' || a[i] > 'P' && a[i] < 'T')  // warning! other values, just for demo!

还有更多。

您可以像这样将您感兴趣的角色添加到数组中:

#include <stdio.h>

int main(){
    char a[10] = { 0 };
    printf("enter string sequence:");
    scanf("%s", a);
    int len = sizeof(a)/sizeof(a[0]);
    char review[] = { 'A','D','O','Q','R','P' };
    int rLen = sizeof(review) / sizeof(review[0]);
    int found = 0;
    for (int i = 0; i<len; i++)
    {
        for (int j = 0; j < rLen; j++){
            if (a[i] == review[j]){
                printf("found atlast !!!");
                found = 1;
                break;
            }
        }
        if (found == 1)
            break;
    }
    if (found == 0)
        printf("Could not be found");
}

通过使用这样的数组:char review[] = { 'A','D','O','Q','R','P' };,跟踪检查的内容变得非常容易。

并且由于您的代码需要更改要检查的字符,因此您只需在一个地方进行更改。

2) 您可以使用查找 table 通过单次比较来确定字符是否在给定的集合中。这实际上是一些编译器如何实现 isupper isalpha 和相关的 functions/macros 定义的 <ctype.h>.

代价是您要么需要手动编写 256 个条目的 table,要么需要代码在运行时填写 table。这还假设您不关心 unicode 字符,因为这会使 table 大很多。

以下代码在启动时初始化 table,并定义一个宏,允许您检查字符是否在集合 {'A', 'D', 'O', 'Q', 'R', 'P'} 中,甚至无需使用一个相等运算符。

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

#define isSpecial(x) (specialArray[x])

char specialArray[256];
int specialList[] = { 'A', 'D', 'O', 'Q', 'R', 'P', EOF };

int main( void )
{
    memset( specialArray, 0, sizeof(specialArray) );
    for ( int i = 0; specialList[i] != EOF; i++ )
        specialArray[specialList[i]] = 1;

    if ( isSpecial( 'A' ) )
        printf( "A is special\n" );
    else
        printf( "A is normal\n" );

    if ( isSpecial( 'B' ) )
        printf( "B is special\n" );
    else
        printf( "B is normal\n" );
}