2017-02-11 20 views
-1

我有以下程序:Bsearch和垃圾中的值的比較函數

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <stdint.h> 
#include <errno.h> 

#define DICT_BUFSIZE 64 

int compar(const void * a, const void * b) 
{ 
    const char* c1 = (const char*)a; 
    const char* c2 = (const char*)b; 

    printf("c1: %s | c2: %s\n", c1, c2); 

    return strcmp(c1, c2); 
} 

int main (void) 
{ 
    FILE*  fdict; 
    uint32_t i; 
    char** dict = NULL; 
    size_t size = 0; 
    size_t size_alloced = 0; 
    char  buf[DICT_BUFSIZE]; 

    fdict = fopen("/usr/share/dict/words", "r"); 
    if (!fdict) { 
     printf("Could not open \"%s\": %s\n", "usr/share/dict/words", strerror(errno)); 
     exit(1); 
    } 

    for (i = 0; fgets(buf, DICT_BUFSIZE, fdict); ++i) { 
     size_t len; 

     if (i == size_alloced) { 
      dict = realloc(dict, (i +50000) * sizeof(*dict)); 
      size_alloced += 50000; 
     } 
     len = strlen(buf); 
     dict[i] = malloc(len); 

     memcpy(dict[i], buf, len -1); 
     dict[i][len -1] = '\0'; 
    } 
    size = i; 

    //for (i = 0; i < size; i++) 
     //printf("%s\n", dict[i]); 

    if(bsearch("company", dict, size, sizeof(*dict), compar)) 
     printf("Found!\n"); 

    for (i = 0; i < size; ++i) 
     free(dict[i]); 
    free(dict); 

    fclose(fdict); 

    return 0; 
} 

在(要搜索的鍵)中的「C1」可變的「COMPAR」功能被正確地顯示,但有垃圾輸出在v2變量中。

下面是一個示例輸出:

c1: company | c2: ��� 
c1: company | c2: �$z 
c1: company | c2: ��I 
c1: company | c2: ��7 
c1: company | c2: P�. 
c1: company | c2: �b3 
c1: company | c2: �1 
c1: company | c2: P�/ 
c1: company | c2: ��0 
c1: company | c2: PC0 
c1: company | c2: @g0 
c1: company | c2: y0 
c1: company | c2: 0�0 
c1: company | c2: ��0 
c1: company | c2: `�0 
c1: company | c2: ��0 
c1: company | c2: 
c1: company | c2: P�0 

我無法理解這種行爲。

+0

我不認爲的sizeof(*字典)有你認爲它的價值。 – Irisshpunk

+0

我立即想到這是一個罪魁禍首,但我沒有看到它有什麼問題? – Nick

回答

1

如果您正在搜索int的數組,您將會將const void *參數轉換爲您的比較函數int *,您會不會?

您正在搜索的char *數組,所以你需要轉換const void *參數char ** - 你需要傳遞一個char **論據被發現的價值。

需要對你的代碼的變化是最小的,但是至關重要的:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <stdint.h> 
#include <errno.h> 

#define DICT_BUFSIZE 64 

static int compar(const void *a, const void *b) 
{ 
    const char *c1 = *(const char **)a; 
    const char *c2 = *(const char **)b; 

    printf("c1: %s | c2: %s\n", c1, c2); 

    return strcmp(c1, c2); 
} 

int main (void) 
{ 
    FILE*  fdict; 
    uint32_t i; 
    char** dict = NULL; 
    size_t size = 0; 
    size_t size_alloced = 0; 
    char  buf[DICT_BUFSIZE]; 
    const char *file = "/usr/share/dict/words"; 

    fdict = fopen(file, "r"); 
    if (!fdict) { 
     printf("Could not open \"%s\": %s\n", file, strerror(errno)); 
     exit(1); 
    } 

    for (i = 0; fgets(buf, DICT_BUFSIZE, fdict); ++i) { 
     size_t len; 

     if (i == size_alloced) { 
      dict = realloc(dict, (i +50000) * sizeof(*dict)); 
      size_alloced += 50000; 
     } 
     len = strlen(buf); 
     dict[i] = malloc(len); 

     memcpy(dict[i], buf, len -1); 
     dict[i][len -1] = '\0'; 
    } 
    size = i; 

    //for (i = 0; i < size; i++) 
     //printf("%s\n", dict[i]); 

    const char *search = "company"; 
    if(bsearch(&search, dict, size, sizeof(*dict), compar)) 
     printf("Found!\n"); 

    for (i = 0; i < size; ++i) 
     free(dict[i]); 
    free(dict); 

    fclose(fdict); 

    return 0; 
} 

比較函數現在需要兩個char **值,並捕獲字符串的每個點來。

該調用的第一個參數需要爲變量char *的地址;因此增加了變量const char *search = "company";

一些清理包括使比較函數靜態(主要是爲了滿足我的迂腐默認編譯選項 - 雖然最好在函數被定義之前聲明),並且使用變量const char *file = "/usr/share/dict/words";來避免(接近)重複到fopen()和錯誤信息。

樣本輸出(和MacOS塞拉利昂10.12.3在Mac上運行):

c1: company | c2: modifier 
c1: company | c2: eagle 
c1: company | c2: Canarian 
c1: company | c2: counteridea 
c1: company | c2: citropten 
c1: company | c2: compulsoriness 
c1: company | c2: coelenteric 
c1: company | c2: Colossian 
c1: company | c2: commonable 
c1: company | c2: compilation 
c1: company | c2: compagination 
c1: company | c2: compatriot 
c1: company | c2: comparition 
c1: company | c2: comparable 
c1: company | c2: companionate 
c1: company | c2: companionway 
c1: company | c2: comparability 
c1: company | c2: company 
Found! 
+0

非常感謝,這很有趣!更正:bsearch中的「鍵」不會作爲指針傳遞,因爲它在我的示例中已成功打印。除此之外,我還對以下網站中的第二個示例如何在沒有我的程序問題的情況下運行感到困惑:http://www.cplusplus.com/reference/cstdlib/bsearch/ – Nick

+0

如果您要使用與'qsort()'相同的比較函數 - 這將允許您對數據進行排序 - 您肯定需要兩個參數都是相同的類型。在'bsearch()'中的鍵總是作爲第一個參數傳遞的,所以你可以使用'static int compar(const void * a,const void * b) {const char * c1 =(const char *)a; const char * c2 = *(const char **)b;'不對稱轉換,但是創建一個用於排序的函數和另一個用於搜索的函數似乎很愚蠢。所以,是的,如果你只是用'bsearch()'來使用比較器,你可以按照你的建議來做。我不會這樣做。 –

+0

http://www.cplusplus.com/reference/cstdlib/bsearch/鏈接中的第二個例子是搜索char strvalues [] [20] = {「some」,「example」,「strings」,「here」 };',而不是'char * strvalues [] = {「some」,「example」,「strings」,「here」};' - 差異真的很重要。後者相當於你擁有的東西。 –