2013-07-05 43 views
5

我有以下代碼:我們是否需要比較C中數組的每個元素?

int isUsed[6] = {1,1,1,1,1,1}; 

如何比較,如果這一切的數組中的元素都等於1?或其他價值? 我知道我們可以循環數組並逐個比較它,但是我們有其他方法可以做到嗎?

+3

答案是否定的。不可能訪問每個元素。 –

+1

爲什麼你對你所知道的方式不滿意,即循環數組和逐個比較元素?你覺得這是不是最理想的?如果是這樣,爲什麼? –

+1

是的,我覺得如果我們有一個c庫方法 – user2131316

回答

12

是的,你必須做到元素。

如果您的數組僅包含純整數類型(即不是數組struct s),並且您只是想檢查相等性,則可以使用memcmp()

這當然會在內部循環,但它是預製的標準功能,因此它有助於可讀性。它可能雖然傷害表現,因爲它比較char s。另一方面(評論之後),它可能會因爲可能被優化的衆所周知的庫函數而獲得性能。

另外,爲了完整性,我對上述沒有struct s的警告的原因是結構通常包含填充字節,它將被memcmp()「看到」,並且可能導致錯誤的結果。

例如:

struct { 
    int x; 
    char y; 
    int z; 
} a = { 1, 2, 3 }, b = { 1, 2, 3 }; 

在許多系統中,上述struct將具有yz之間填充,這可能會從memcmp()由於填充字節具有未定義的值會導致一個不正確的結果。

+0

是的,它是純整數 – user2131316

+0

*它可能會損害性能*?即使在循環展開或甚至特殊的機器指令支持之後? – johnchen902

+0

@ johnchen902爲什麼會傷害表現? 'memcmp()'是很好的建議。 –

2

您必須逐個比較數組元素。

0

除了一次比較每個元素,沒有別的辦法。雖然它減慢你的速度,但沒有其他選擇。嘗試

#define NULL (void*)0 
memcmp(char* source, const char * dest, int count); 

如果字符串匹配,則返回NULL。

+3

它返回一個整數「0」。不是'NULL',一個指針。 – unwind

+0

你的答案是Unwind的答案的重複,並且你的文字中'String'是**錯誤**。 –

+0

展開:沒有看到你的味精,如果null定義爲#define NULL(void *)0,則返回true。 – Ishmeet

4

對於原始數據類型(非結構),如果你知道數組的大小和你想比較反對什麼:memcmp將做的工作:

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

static int allOnes[6] = {1,1,1,1,1,1}; 

int main(int argc, const char* argv[]) { 

    int isUsed[6] = {1,1,1,1,1,1}; 

    if(memcmp(isUsed, allOnes, sizeof allOnes) == 0) 
     printf("Array has only 1's\n"); 
    else 
     printf("At least one element is not 1\n"); 
} 

編輯:有關性能...

有些評論提到了memcmp和循環的性能,包括展開循環。

下面是一個簡單的測試程序來衡量性能。在我的機器(Mac OS X中,LLVM編譯器),這是我得到:

memcmp: 0.036031 seconds result=1 
loop: 0.097180 seconds result=1 
unrolled loop: 0.075623 seconds result=1 

在作出有關上述數字的具體意見,請注意:

  • ,我不是做一個只是表明在我的環境中,memcmp解決方案大大超過了其他方案。
  • 我展開的循環並不是最大的實現。這只是一個粗略的嘗試,有一些數字用於循環展開。

隨意修改代碼併發布其他數字。

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

static int allOnes[6] = {1,1,1,1,1,1}; 

bool compareWithMemcmp() 
{ 
     int isUsed[6] = {1,1,1,1,1,1}; 
     return memcmp(isUsed, allOnes, sizeof allOnes) == 0; 
} 

bool compareWithLoop() 
{ 
     int isUsed[6] = {1,1,1,1,1,1}; 
     for(int i = 0; i < sizeof allOnes/sizeof allOnes[0]; i++) 
      if(isUsed[i] != 1) 
       return false; 
     return true; 
} 

bool compareWithUnrolledLoop() 
{ 
     int isUsed[6] = {1,1,1,1,1,1}; 
     // IMPORTANT: doesn't account for odd-length array 
     for(int i = 0; i < sizeof allOnes/sizeof allOnes[0]; i += 2) 
      if((isUsed[i] != 1) || (isUsed[i+1] != 1)) 
       return false; 
     return true; 
} 

int main(int argc, const char* argv[]) { 

    bool result; 

    clock_t begin = clock(); 
    for(int i = 0; i < 10000000; i++) 
     result = compareWithMemcmp(); 
    printf("memcmp: %f seconds result=%d\n", 
      (double)(clock() - begin)/CLOCKS_PER_SEC, result); 

    begin = clock(); 
    for(int i = 0; i < 10000000; i++) 
     result = compareWithLoop(); 
    printf("loop: %f seconds result=%d\n", 
      (double)(clock() - begin)/CLOCKS_PER_SEC, result); 

    begin = clock(); 
    for(int i = 0; i < 10000000; i++) 
     result = compareWithUnrolledLoop(); 
    printf("unrolled loop: %f seconds result=%d\n", 
      (double)(clock() - begin)/CLOCKS_PER_SEC, result); 
} 
0

可以使用裝配直列,採取從這個例子:

你可以寫一個宏來重複這個代碼的6倍,約您的問題:

#include <stdio.h> 
#include <stdlib.h> 
#include <inttypes.h> 


int64_t isUsed[ 1 ] = { 1 }; 

int main (void) 
{ 

__asm__ 
(
    "\n movq %[a] , %%rax" 
    "\n cmpq $1 , %%rax" 
    : 
    : [ a ] "m" (isUsed[0]) 
); 

__asm__ goto ("jne %l0\n" 
: 
: 
: 
: NotEqual); 


printf ("\n Array Contains 1 in all elements"); 
return 1 ; 

NotEqual: 

printf ("\n Array Not contains 1 in all elements"); 

return 0 ; 
} 

這是彙編代碼(小)

movq isUsed(%rip) , %rax 
cmpq $1 , %rax 
jne .L2 

當心,你將使用整型(int32_t或的int64_t:inttypes.h)

+0

你可以,但是如果你提高了優化級別,你的代碼會比編譯器產生的代碼慢得多。玩組裝很有趣,可以擊敗編譯器 - 但除非你的名字是Agner Fog(或者同樣特殊的人),否則你不會這樣做。 –

+0

@NikBougalis,但是如果你沒有試圖擊敗編譯器,你會如何獲得像Agner Fog這樣的酷名字......? –

+0

@gradyplayer這是一個公平點 - 嘗試沒有錯。我確實說過和組裝一起玩很有趣;) –

0

你可以在你的gcc擴展:

#include <stdio.h> 
#include <inttypes.h> 

#define VECTOR_SIZE   4 
typedef int v4int __attribute__ ((vector_size(sizeof(int32_t)*VECTOR_SIZE))); 


typedef union f4vector 
{ 
v4int  v; 
__int128_t value ; 
} f4vector; 



int main() 
{ 
union f4vector a, b, c; 

a.v = (v4int) { 1, 1, 1, 2 }; // your vector 
b.v = (v4int) { 1, 1, 1, 1 }; 

c.v = a.v - b.v; 

if (c.value == 0) 
    puts ("array contains all 1"); 
else 
    puts ("array Not contais all 1"); 

return 0 ; 
} 
0

好吧,我不隨着那說,有沒有其他辦法的任何答案去...

答案取決於陣列可以如何改變。

給定一個數組,你已經預先設定了一些已知的值,沒有進一步的變化,測試是微不足道的,解決方案是O(1)。全部是1,因爲你是這麼做的。

一旦你開始改變這些值,如果它們的改變方式存在某種模式,那麼你可能能夠在該模式本身上記錄信息,並且可以在小於O的情況下對歷史進行測試( N)。

例如,當您更改數組中的一個元素時,您可能會在別處設置一個標誌,指示數組的哪些部分需要重新評估。如果所有的改動都聚集在一個小區域,那麼你可能只需要測試一小部分數組。

但是,在給出的具體例子中,一小組isUsed[],假設每個元素只有兩種可能的狀態可能是合理的。如果你使用了一個位掩碼,那麼測試整個數組可能是一個整數操作。它隱式訪問每個元素,但它比循環更有效率。