C - strcmp 的分段错误? [英] C - Segmentation Fault with strcmp?

查看:42
本文介绍了C - strcmp 的分段错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我似乎在 strcmp 函数的某个地方遇到了分段错误.我对 C 还是很陌生,我不明白为什么它会给我这个错误.

I appear to be getting a segmentation fault somewhere with the strcmp function. I'm still very new to C and I can't see why it gives me the error.

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结构

insertion code and htable struct

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 - 我输入随机值添加到表中

valgrind - me entering random values to add to table

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 != ''){
    result = (*word++ + 31 * result);
  }
  return result;
}

推荐答案

除了 htable 中的值可能是无效指针(即,既不是 NULL 也不是指向像样 Cstring),如果它既不包含 NULL 也不包含您要查找的字符串,您将遇到无限循环的严重问题.

Apart from the possibility that the values in your htable may be invalid pointers (i.e., neither NULL nor a pointer to a decent C string), you have a serious problem of encountering an infinite loop if it contains neither a NULL nor the string you're looking for.

对于当前的问题,尝试将代码更改为:

For the immediate problem, try changing the code to:

#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 ("========
");                    FLUSH;
        printf ("inpk: %d
",   k);               FLUSH;
        printf ("posn: %d
",   pos);             FLUSH;
        printf ("cpct: %d
",   h->capacity);     FLUSH;
        printf ("keyp: %p
",   h->keys[pos]);    FLUSH;
        printf ("keys: '%s'
", h->keys[pos]);    FLUSH;
        printf ("item: '%s'
", item);            FLUSH;
        printf ("========
");                    FLUSH;
    } while ((pos != k)
          && (h->keys[pos] != NULL)
          && (strcmp (h->keys[pos], item) != 0));
    return pos;
}

这些调试语句应该可以告诉您出了什么问题.

Those debug statements should give you an indication as to what's going wrong.

因为你得到:

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

就在崩溃之前,很明显有人为 k 传递了一个虚假值.对负数的模运算是在 C 标准中定义的实现,因此您也可以得到 pos 的负值.而且由于 h->pos[-30] 将是未定义的行为,所有赌注都没有了.

right before the crash, it's evident that someone is passing in a bogus value for k. The modulo operation on negative numbers is implementation defined in the C standard so you're getting a negative value for pos as well. And since h->pos[-30] is going to be undefined behaviour, all bets are off.

要么找到并修复传入该虚假值(可能是未初始化的变量)的代码,要么通过更改来保护您的函数:

Either find and fix the code that's passing in that bogus value (probably an uninitialised variable) or protect your function by changing:

int pos = k;

进入:

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

在你的函数开始时.我实际上会同时做这两件事,但是我很偏执:-)

at the start of your function. I'd actually do both but then I'm pretty paranoid :-)

并且,基于 another 更新(哈希键计算,如果您生成一个 unsigned int 然后盲目地将其用作签名 int,你很有可能得到负值:

And, based on yet another update (the hash key calculation, if you generate an unsigned int and then blindly use that as a signed int, you've got a good chance of getting negative values:

#include <stdio.h>

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

这个输出:

4294901760 -65536

我的建议是对明显意味着无符号的值使用无符号整数.

My suggestion is to use unsigned integers for values that are clearly meant to be unsigned.

这篇关于C - strcmp 的分段错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆