簡體   English   中英

C - 使用strcmp進行分段錯誤?

[英]C - Segmentation Fault with strcmp?

我似乎在strcmp函數的某處出現了分段錯誤。 我還是C的新手,我不明白為什么它會給我錯誤。

int linear_probe(htable h, char *item, int k){
  int p;
  int step = 1;
  do {
    p = (k + step++) % h->capacity;
  }while(h->keys[p] != NULL && strcmp(h->keys[p], item) != 0);
  return p;
}

GDB:

Program received signal SIGSEGV, Segmentation fault.
0x0000003a8e331856 in __strcmp_ssse3 () from /lib64/libc.so.6

(gdb) frame 1
#1  0x0000000000400ea6 in linear_probe (h=0x603010, item=0x7fffffffde00 "ksjojf", k=-1122175319) at htable.c:52

編輯: 插入代碼和htable結構

int htable_insert(htable h, char *item){
  unsigned int k = htable_word_to_int(item);
  int p = k % h->capacity;

  if(NULL == h->keys[p]){
    h->keys[p] = (char *)malloc(strlen(item)+1);
    strcpy(h->keys[p], item);
    h->freqs[p] = 1;
    h->num_keys++;
    return 1;
  }

  if(strcmp(h->keys[p], item) == 0){
    return ++h->freqs[p];
  }

  if(h->num_keys == h->capacity){
    return 0;
  }

  if(h->method == LINEAR_P) p = linear_probe(h, item, k);
  else p = double_hash(h, item, k);

  if(NULL == h->keys[p]){
    h->keys[p] = (char *)malloc(strlen(item)+1);
    strcpy(h->keys[p], item);
    h->freqs[p] = 1;
    h->num_keys++;
    return 1;
  }else if(strcmp(h->keys[p], item) == 0){
    return ++h->freqs[p]; 
  }
  return 0;
}

  struct htablerec{
      int num_keys;
      int capacity;
      int *stats;
      char **keys;
      int *freqs;
      hashing_t method;
    };

謝謝

編輯: valgrind - 我輸入隨機值添加到表

sdkgj
fgijdfh
dfkgjgg
jdf
kdjfg
==25643== Conditional jump or move depends on uninitialised value(s)
==25643==    at 0x40107E: htable_insert (htable.c:87)
==25643==    by 0x400AB7: main (main.c:75)
==25643== 
fdkjb
kjdfg
kdfg
nfdg
lkdfg
oijfd
kjsf
vmf
kjdf
kjsfg
fjgd
fgkjfg
==25643== Invalid read of size 8
==25643==    at 0x400E0E: linear_probe (htable.c:51)
==25643==    by 0x401095: htable_insert (htable.c:87)
==25643==    by 0x400AB7: main (main.c:75)
==25643==  Address 0x4c342a0 is not stack'd, malloc'd or (recently) free'd
==25643== 
==25643== Invalid read of size 8
==25643==    at 0x400E2B: linear_probe (htable.c:51)
==25643==    by 0x401095: htable_insert (htable.c:87)
==25643==    by 0x400AB7: main (main.c:75)
==25643==  Address 0x4c342a0 is not stack'd, malloc'd or (recently) free'd
==25643== 
==25643== Invalid read of size 1
==25643==    at 0x4A06C51: strcmp (mc_replace_strmem.c:426)
==25643==    by 0x400E3C: linear_probe (htable.c:51)
==25643==    by 0x401095: htable_insert (htable.c:87)
==25643==    by 0x400AB7: main (main.c:75)
==25643==  Address 0x210 is not stack'd, malloc'd or (recently) free'd
==25643== 
==25643== 
==25643== Process terminating with default action of signal 11 (SIGSEGV)
==25643==  Access not within mapped region at address 0x210
==25643==    at 0x4A06C51: strcmp (mc_replace_strmem.c:426)
==25643==    by 0x400E3C: linear_probe (htable.c:51)
==25643==    by 0x401095: htable_insert (htable.c:87)
==25643==    by 0x400AB7: main (main.c:75)
==25643==  If you believe this happened as a result of a stack
==25643==  overflow in your program's main thread (unlikely but
==25643==  possible), you can try to increase the size of the
==25643==  main thread stack using the --main-stacksize= flag.
==25643==  The main thread stack size used in this run was 8388608.
==25643== 
==25643== HEAP SUMMARY:
==25643==     in use at exit: 1,982 bytes in 28 blocks
==25643==   total heap usage: 28 allocs, 0 frees, 1,982 bytes allocated
==25643== 
==25643== LEAK SUMMARY:
==25643==    definitely lost: 0 bytes in 0 blocks
==25643==    indirectly lost: 0 bytes in 0 blocks
==25643==      possibly lost: 0 bytes in 0 blocks
==25643==    still reachable: 1,982 bytes in 28 blocks
==25643==         suppressed: 0 bytes in 0 blocks
==25643== Rerun with --leak-check=full to see details of leaked memory
==25643== 
==25643== For counts of detected and suppressed errors, rerun with: -v
==25643== Use --track-origins=yes to see where uninitialised values come from
==25643== ERROR SUMMARY: 7 errors from 4 contexts (suppressed: 6 from 6)
Segmentation fault (core dumped)

static unsigned int htable_word_to_int(char *word){
  unsigned int result = 0;
  while(*word != '\0'){
    result = (*word++ + 31 * result);
  }
  return result;
}

除了你的htable中的值可能是無效指針(即,既不是NULL也不是指向正確的C字符串的指針)的可能性之外,如果它既不包含NULL也不包含字符串,則會遇到嚴重的問題:遇到無限循環正在尋找。

對於直接問題,請嘗試將代碼更改為:

#define FLUSH fflush (stdout); fsync (fileno (stdout))

int linear_probe (htable h, char *item, int k) {
    int pos = k;
    do {
        pos = (pos + 1) % h->capacity;
        printf ("========\n");                    FLUSH;
        printf ("inpk: %d\n",   k);               FLUSH;
        printf ("posn: %d\n",   pos);             FLUSH;
        printf ("cpct: %d\n",   h->capacity);     FLUSH;
        printf ("keyp: %p\n",   h->keys[pos]);    FLUSH;
        printf ("keys: '%s'\n", h->keys[pos]);    FLUSH;
        printf ("item: '%s'\n", item);            FLUSH;
        printf ("========\n");                    FLUSH;
    } while ((pos != k)
          && (h->keys[pos] != NULL)
          && (strcmp (h->keys[pos], item) != 0));
    return pos;
}

那些調試語句應該可以指示出現了什么問題。


既然你得到了:

inpk: -2055051140
posn: -30
cpct: 113
keyp: 0x100000001

在崩潰之前,很明顯有人正在為k傳遞虛假價值。 負數的模運算是在C標准中定義的實現,所以你也得到了pos的負值。 由於h->pos[-30]將成為未定義的行為,所有投注都將被取消。

找到並修復傳遞偽造值的代碼(可能是未初始化的變量)或通過更改以下內容來保護您的函數:

int pos = k;

成:

int pos;
if ((k < 0) || (k >= h->capacity))
    k = 0;
pos = k;

在你的功能開始。 我實際上都做了兩件事然后我很偏執:-)


並且,基於另一個更新(散列鍵計算,如果生成unsigned int然后盲目地將其用作signed int ,則很有可能獲得負值:

#include <stdio.h>

int main (void) {
    unsigned int x = 0xffff0000U;
    int y = x;
    printf ("%u %d\n", x, y);
    return(0);
}

這輸出:

4294901760 -65536

我的建議是使用無符號整數表示明確無符號的值。

如果您使用的是linux,請嘗試valgrind。 它可以告訴你無效訪問,內存泄漏,未初始化的變量等。輸出可能看起來很混亂,難以閱讀,但如果你繼續嘗試,它會獎勵你。 到底是怎么回事:

  1. 使用-g開關構建程序以包含調試信息
  2. 使用valgrind: valgrind ./myprogram運行程序
  3. 通過閱讀產出獲利

正如我所說,輸出可能看起來非常混亂,所以可能首先嘗試一些簡單的程序(普通的空主)來看看當一切正常時它是什么樣的,然后嘗試故意崩潰你的程序,如:

int *bullet = 0;
*bullet = 123;

並看到輸出。


可以在這里找到一個很好的基本介紹和示例。


當你提供valgrind輸出時,我會開始修復那里列出的問題。 首先, Conditional jump or move depends on uninitialised value(s)錯誤。 您可以使用--track-origins=yes重新運行valgrind,因為valgrind建議查看更多詳細信息,然后修復它(您的代碼片段中沒有行號,我無法幫助您更多)。

./valgrind --track-origins=yes ./myprogram      #don't switch parameters!

然后Invalid read of size 1錯誤意味着您已經訪問了不屬於您的內存,但僅讀取它,因此它“不介意”。 但它仍然是一個不應該發生的錯誤,所以修復它(如果不是由第一個錯誤修復修復)。

最后, Access not within mapped regionAccess not within mapped region是對未分配的內存的寫入。

現在嘗試修復錯誤(按照valgrind列出的順序)遵循valgrind建議(比如用開關重新運行它)。

好吧你沒有包括圍繞htable填充這個哈希表等的代碼.strcmp可能是segfaulted因為你要么給它一個NULL字符串或一個字符數組沒有正確結束0 ....

h->鍵是否用NULL完全初始化? 否則你里面有隨機指針。

順便說一句,

h->keys[p] = (char *)malloc(strlen(item)+1);
strcpy(h->keys[p], item);

無論錯誤情況多么不可能,如果它發出錯誤信號,請務必檢查函數的返回是否有效。 malloc()失敗時返回NULL。

乍一看,我的猜測是你的段錯誤來自p - 你永遠不會初始化那個變量,因此不能保證從零開始; 它可以從-123456開始,你所知道的,然后你將訪問一個無效的內存地址。 編輯:誤讀了do-while循環。 忽略這一段。

乍一看,我會檢查h->keys[p]是否是以空字符結尾的字符串 - strcmp繼續讀取值,直到它達到零字節為止; 如果沒有這樣的字節,它可以繼續運行直到它到達無效的存儲器地址。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM